diff --git a/FEATURES/74786 b/FEATURES/74786
new file mode 100644
index 0000000000000000000000000000000000000000..54baf80d6ee5afa24004d4b09b8312004bfa279d
--- /dev/null
+++ b/FEATURES/74786
@@ -0,0 +1,10 @@
+        '74786' =>
+            ['Label' => $this->_('Processus de ré-initialisation du mot de passe'),
+             'Desc' => $this->_('Bokeh permet d\'envoyer un lien de réinitialisation du mot de passe par mail.'),
+             'Image' => '',
+             'Video' => 'https://www.youtube.com/watch?v=DHmqvlPetvA',
+             'Category' => $this->_('Compte lecteur'),
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=Fiche_utilisateur',
+             'Test' => '',
+             'Date' => '2018-07-03'],
diff --git a/VERSIONS_WIP/74786 b/VERSIONS_WIP/74786
new file mode 100644
index 0000000000000000000000000000000000000000..f0880934d9fb4a13fa797dbfd316f0d983c1222d
--- /dev/null
+++ b/VERSIONS_WIP/74786
@@ -0,0 +1 @@
+ - ticket #74786 : Abonné : nouveau processus de réinitialisation du mot de passe
\ No newline at end of file
diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php
index 4fe952f6ab4a05fa0edc7ce119dcdccbed558786..360743c546ebf708e08fa0ae60f37630cf41afe1 100644
--- a/application/modules/opac/controllers/AbonneController.php
+++ b/application/modules/opac/controllers/AbonneController.php
@@ -611,24 +611,26 @@ class AbonneController extends ZendAfi_Controller_Action {
       Class_Newsletter::findAllBy(['id' => $subscriptions]) :
       [];
 
-    try {
-      $password = $this->_request->getParam('password');
-      if (empty($password))
-        $password = $this->_user->getPassword();
+    $password = $this->_request->getParam('password');
+    if (empty($password))
+      $password = $this->_user->getPassword();
 
-      $this->_user->updateSIGBOnSave();
+    $fields_to_save = Class_AdminVar::getChampsFicheUtilisateur();
+    $attributes = [];
+    foreach($fields_to_save as $field)
+      $attributes[$field] = $this->_request->getParam($field);
 
-      $fields_to_save = Class_AdminVar::getChampsFicheUtilisateur();
-      $attributes = [];
-      foreach($fields_to_save as $field)
-        $attributes[$field] = $this->_request->getParam($field);
+    $this->_user
+      ->updateAttributes($attributes)
+      ->setPassword($password)
+      ->setNewsletters($newsletters);
 
-      $this->_user
-        ->updateAttributes($attributes)
-        ->setPassword($password)
-        ->setNewsletters($newsletters);
+    $patron = $this->_user->getEmprunteur();
+    $patron->updateFromUser($this->_user);
 
+    try {
       if ($this->_user->save()) {
+        $patron->ensureService($this->_user)->save();
         $this->_helper->notify($this->_('Vos modifications ont bien été enregistrées'));
         $this->_redirect('/abonne/fiche');
       }
diff --git a/application/modules/opac/controllers/AuthController.php b/application/modules/opac/controllers/AuthController.php
index a4a6e7523075a66f5062921f294ba8f514e88d92..b08c29afb6b4e85fdea56bbcebc0cd4ff3f23cac 100644
--- a/application/modules/opac/controllers/AuthController.php
+++ b/application/modules/opac/controllers/AuthController.php
@@ -280,20 +280,6 @@ class AuthController extends ZendAfi_Controller_Action {
   }
 
 
-  public function ajaxlostpassAction()  {
-    if ($this->_request->isPost()) {
-      $user = ZendAfi_Filters_Post::filterStatic($this->_request->getPost('username'));
-      $classe_user = new Class_Users();
-      $ret = $classe_user->lostpass($user);
-      $this->view->message = $this->getErrorMessages($ret["error"]);
-      $this->view->message_mail = $ret["message_mail"];
-    }
-    $this->view->username=$user;
-    $viewRenderer = $this->getHelper('ViewRenderer');
-    $viewRenderer->setLayoutScript('subModal.phtml');
-  }
-
-
   public function logoutAction()  {
     ZendAfi_Auth::getInstance()->clearIdentity();
     $profil = Class_Profil::getCurrentProfil();
@@ -331,7 +317,7 @@ class AuthController extends ZendAfi_Controller_Action {
     $login = ZendAfi_Filters_Post::filterStatic($this->_request->getPost('lost_username'));
     $this->view->username = $login;
 
-    $user = Class_Users::findFirstValidOrNotBy(['login' => $login]);
+    $user = Class_Users::findFirstBy(['login' => $login]);
     $this->view->message_mail = (new Class_User_LostPass($user))->send();
   }
 
@@ -357,11 +343,18 @@ class AuthController extends ZendAfi_Controller_Action {
         || !$form->isValid($this->_request->getPost()))
       return;
 
-    $user->setPassword($form->getValue('new_pass'))
-         ->save();
+    $user->setPassword($form->getValue('new_pass'));
+    $patron = $user->getEmprunteur();
+    $patron->updateFromUser($user);
+    try {
+      if ($user->save())
+        $patron->ensureService($user)->save();
+    } catch(Exception $e) {
+      $this->_helper->notify($e->getMessage());
+      return $this->_redirect('/auth/login');
+    }
 
     $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/ajax-login.phtml b/application/modules/opac/views/scripts/auth/ajax-login.phtml
index ef0a781ecfa6a85dda1b830bfa1829c459dd58d8..edf276fcff2773717f843afd75992b0835bf1e4e 100644
--- a/application/modules/opac/views/scripts/auth/ajax-login.phtml
+++ b/application/modules/opac/views/scripts/auth/ajax-login.phtml
@@ -1,15 +1,3 @@
-<script>
-function getUsername(){
-  oUser = document.getElementById('username');
-  username = oUser.value;
-  var url = window.location.href="ajaxlostpass?id="+username;
-  return(url);
-}
-
-function submit() {
-  $(parent).getForm().submit();
-}
-</script>
 <center>
   <h1>
     <?php
diff --git a/application/modules/opac/views/scripts/auth/ajaxlostpass.phtml b/application/modules/opac/views/scripts/auth/ajaxlostpass.phtml
deleted file mode 100644
index c4ba5ab6fd73b1ec2a7c164e29c5bb6b24af4af1..0000000000000000000000000000000000000000
--- a/application/modules/opac/views/scripts/auth/ajaxlostpass.phtml
+++ /dev/null
@@ -1,48 +0,0 @@
-<script>
-function getUsername()
-{
-    oUser = document.getElementById('username');
-    username = oUser.value;
-    var url = window.location.href="lostpass?id="+username;
-    return(url);
-}
-</script>
-<center>
-<h1><?php echo $this->_('Mot de passe oublié') ?></h1>
-<div class="formTable">
-<?php
-// Message final
-if($this->message_mail)
-{
-  echo '<div align="center">'.$this->message_mail;
-  echo '<input type="button" value="Ok" class="bouton" onclick="parent.window.hidePopWin(false);">';
-  echo '</div>';
-}
-
-// Saisie nom d'utilisateur
-else
-{
-  if($this->message) echo '<p class="erreur">'.$this->message.'</p>'; else echo BR;
-?>
-  <p style="margin-top:0px"><?php echo $this->_('Après reconnaissance de votre identifiant, un mail vous sera envoyé avec vos paramètres de connexion.') ?></p>
-  <form name="form" action="<?php echo $this->url(['module'=>'opac','controller'=>'auth','action'=>'ajaxlostpass']); ?>"  method="post">
-
-  <fieldset>
-      <legend><?php echo $this->_('Votre identité s.v.p.') ?></legend>
-      <table cellspacing="2">
-        
-        <tr height="50px">
-          <td class="droite" width="35%"><?php echo $this->_('Identifiant') ?>&nbsp;</td>
-          <td class="gauche"><input type="text" name="username" id="username" value=""></td>
-        </tr>
-      
-      </table>
-  </fieldset>
-<?php
-  echo $this->formSubmit("",$this->_("Valider"),array("class" => "bouton"));
-}
-?>
-
-</form>
-</div>
-</center>
diff --git a/cosmogramme/sql/patch/patch_348.php b/cosmogramme/sql/patch/patch_348.php
new file mode 100644
index 0000000000000000000000000000000000000000..78b91ab41ac5f5b564ba296f44422008fdf759cc
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_348.php
@@ -0,0 +1,5 @@
+<?php
+$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+try {
+  $adapter->query('ALTER TABLE bib_c_site add column reset_password text not null');
+} catch(Exception $e) {}
\ No newline at end of file
diff --git a/library/Class/Bib.php b/library/Class/Bib.php
index 9d176767d0236ad5240dfb45ff72cb9ebe04ed8a..21a07d6411bf036fa0bb5faaf1850bb0abf9dca5 100644
--- a/library/Class/Bib.php
+++ b/library/Class/Bib.php
@@ -303,6 +303,7 @@ class Class_Bib extends Storm_Model_Abstract {
                                   'pret' => '',
                                   'annexe' => '',
                                   'procure' => '',
+                                  'reset_password' => '',
                                   'closed_on_holidays' => true,
                                   'id_lieu' => 0,
                                   'rewrite_url' => '',
diff --git a/library/Class/CommSigb.php b/library/Class/CommSigb.php
index 8270b3565376b07a0a0a1f85e2bd0b5b93b93401..9d38ae3bced9bf1bac21a54589823e5ea6ae1ca2 100644
--- a/library/Class/CommSigb.php
+++ b/library/Class/CommSigb.php
@@ -37,6 +37,7 @@ class Class_CommSigb {
   }
 
 
+  /** @category testing */
   public static function setLogger($logger) {
     static::$_logger = $logger;
   }
@@ -102,7 +103,9 @@ class Class_CommSigb {
    * @return array
    */
   public function ficheAbonne($std_user) {
-    $user = Class_Users::getLoader()->find($std_user->ID_USER);
+    if (!$user = Class_Users::find($std_user->ID_USER))
+      return $this->_error($this->_('Abonné inconnu'));
+
     $cache = Class_WebService_SIGB_EmprunteurCache::newInstance();
 
     if ($cache->isCached($user))
diff --git a/library/Class/Profil/Preferences/LoansHistory.php b/library/Class/Profil/Preferences/LoansHistory.php
index e7a1c289c1943418526131fcd1ae86f059fb982e..ab1e98db5f179904e309423b42caf78c97783dc9 100644
--- a/library/Class/Profil/Preferences/LoansHistory.php
+++ b/library/Class/Profil/Preferences/LoansHistory.php
@@ -103,7 +103,6 @@ class Class_Profil_Preferences_LoansHistory extends Class_Profil_Preferences_Loa
                                'Label' => $this->_('Imprimer')]))
             ->whenCalledDo('renderWith', function($view_helper)
                            {
-                             xdebug_break();
                              $loans = $view_helper->getLoans();
                              $view = $view_helper->view;
                              $config = new Class_Entity(['Models' => $loans->getArrayCopy(),
diff --git a/library/Class/User/LostPass.php b/library/Class/User/LostPass.php
index eb3b83dde9199302efd94c82815483aece3736d7..8ea5047aec07c92031f1fe14c787cdd549330194 100644
--- a/library/Class/User/LostPass.php
+++ b/library/Class/User/LostPass.php
@@ -21,7 +21,8 @@
 
 
 class Class_User_LostPass {
-  use Trait_TimeSource;
+
+  use Trait_TimeSource, Trait_Translator;
 
   const MAX_MINUTES = 30;
   const TOKEN_SEPARATOR = '@';
@@ -35,11 +36,14 @@ class Class_User_LostPass {
 
 
   public function send() {
-    $strategy = $this->_user->isAbonne()
-      ? new Class_User_LostPassPatron($this)
-      : new Class_User_LostPassLocal($this);
+    return $this->_getMailStrategy()->sendTo($this->_user);
+  }
 
-    return $strategy->sendTo($this->_user);
+
+  protected function _getMailStrategy() {
+    return $this->isValid(function($message) {return false;})
+      ? new Class_User_LostPassResetLink($this)
+      : new Class_User_LostPassSendNothing($this);
   }
 
 
@@ -56,6 +60,23 @@ class Class_User_LostPass {
 
     return $from < $now;
   }
+
+
+  public function isValid($addError) {
+    if (!$this->_user->hasMail())
+      return $addError($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 (!$this->_user->isAbonne())
+      return true;
+
+    if (!$this->_user->isSIGBProvidesChangePasswordService())
+      return $addError((($library = $this->_user->getBib())
+                        && ($message = $library->getResetPassword()))
+                       ? $message
+                       : $this->_('Merci de vous adresser à la bibliothèque pour récupérer votre mot de passe ou bien le remplacer par un nouveau.'));
+
+    return true;
+  }
 }
 
 
@@ -94,26 +115,15 @@ abstract class Class_User_LostPassSender {
 
 
 
-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_LostPassSendNothing extends Class_User_LostPassSender {
+  public function sendTo($user) {
+    return '';
   }
 }
 
 
 
-class Class_User_LostPassLocal extends Class_User_LostPassSender{
+class Class_User_LostPassResetLink extends Class_User_LostPassSender{
   use Trait_TimeSource;
 
   protected function _contentFor($user) {
diff --git a/library/Class/User/Password.php b/library/Class/User/Password.php
index eedb739ae717c6042cf7f7316edf0afc442ad26d..4299f74e2e3c316d790742c4b014d11092c25d25 100644
--- a/library/Class/User/Password.php
+++ b/library/Class/User/Password.php
@@ -29,8 +29,11 @@ class Class_User_Password {
 
 
   public function format() {
-    return $this->shouldHash()
-      ? $this->asBlowFish()
+    if ($this->shouldHash())
+      return $this->asBlowFish();
+
+    return $this->isPatron() && Class_AdminVar::isLoginThroughSigbOnlyEnabled()
+      ? ''
       : $this->password();
   }
 
@@ -48,7 +51,7 @@ class Class_User_Password {
 
 
   public function shouldHash() {
-    return $this->hasRoleLevel() && !$this->isPatron() && !$this->isBlowFish();
+    return !$this->isPatron() && !$this->isBlowFish();
   }
 
 
diff --git a/library/Class/Users.php b/library/Class/Users.php
index fd8c356f1b8303ab5acc3543cbcf184adc6b69fc..effcbf480c6a32ac181d7fb5b709ce64aef4ce50 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -311,14 +311,6 @@ 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;
-  }
 }
 
 
@@ -1127,35 +1119,6 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
-  public function lostpass($login) {
-    if(!trim($login))
-      return ['error' => 1];
-
-    if (!$user = Class_Users::getLoader()->findFirstBy(['login' => $login]))
-      $user = Class_UsersNonValid::getLoader()->findFirstBy(['login' => $login]);
-
-    if (!$user)
-      return ['error' => 2];
-
-    if (!$user->hasMail())
-      return ['error' => 4];
-
-    // envoi du mail
-    $message_mail = sprintf("%s\n\n",
-                            $this->_('Vous avez fait une demande de mot de passe sur le portail.'));
-    $message_mail .= $this->_("Votre identifiant : %s\n", $user->getLogin());
-    $message_mail .= $this->_("Votre mot de passe : %s\n", $user->getPassword());
-    $message_mail .= sprintf("%s\n\n", $this->_('Bonne navigation sur le portail'));
-    $erreur = (new Class_Mail())->sendMail(Class_Profil::getCurrentProfil()->getTitreSite(),
-                                           $message_mail,
-                                           $user->getMail());
-
-    return $erreur
-      ? ['message_mail' => '<p class="error">'.$erreur.'</p>']
-      : ['message_mail' => $this->_("Un mail vient de vous être envoyé avec vos paramètres de connexion.")];
-  }
-
-
   public function getNomAff($id_user = null, $complet = false) {
     if ($id_user != null) {
       if (null === $user = Class_Users::find($id_user))
@@ -1281,7 +1244,7 @@ class Class_Users extends Storm_Model_Abstract {
    * @return Class_WebService_SIGB_Emprunteur
    */
   public function getEmprunteur() {
-    return array_at('fiche', $this->getFicheSIGB());
+    return array_at('fiche', $this->getFicheSigb());
   }
 
 
@@ -1370,12 +1333,6 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
-  public function updateSIGBOnSave() {
-    $this->getFicheSigb();
-    return $this;
-  }
-
-
   public function setFicheSIGB($fiche) {
     $this->_fiche_sigb = $fiche;
     return $this;
@@ -1401,18 +1358,6 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
-  /**
-   * Hook AbstractModel::save
-   * Sauvegarde des données compte lecteur sur le SIGB
-   */
-  public function afterSave() {
-    if (!isset($this->_fiche_sigb['fiche'])) return;
-
-    $emprunteur = $this->_fiche_sigb['fiche'];
-    $emprunteur->updateFromUserAndSave($this);
-  }
-
-
   public function beforeSave() {
     $this->setDateMaj(Class_Multimedia_Utils_DateTimeFormat::getInstance()
                       ->getCurrentDateFormatInYmdHMS());
@@ -1925,4 +1870,9 @@ class Class_Users extends Storm_Model_Abstract {
       ? $int_library_mail
       : $library_mail;
   }
+
+
+  public function isSIGBProvidesChangePasswordService() {
+    return ($sigb_com = $this->getSIGBComm()) && $sigb_com->providesChangePasswordService();
+  }
 }
diff --git a/library/Class/WebService/SIGB/Emprunteur.php b/library/Class/WebService/SIGB/Emprunteur.php
index fb1ff7295584f05cccf0bfedada976a6abfab948..a528445e7d39ad2b7a457ff8649f122a2de01199 100644
--- a/library/Class/WebService/SIGB/Emprunteur.php
+++ b/library/Class/WebService/SIGB/Emprunteur.php
@@ -612,6 +612,14 @@ class Class_WebService_SIGB_Emprunteur {
   }
 
 
+  public function ensureService($user) {
+    if (!$this->_service)
+      $this->_service = $user->getSIGBComm();
+
+    return $this;
+  }
+
+
   public function setLibraryCode($library_code) {
     $this->_library_code = $library_code;
     return $this;
@@ -654,25 +662,6 @@ class Class_WebService_SIGB_Emprunteur {
   }
 
 
-  public function updateFromUserAndSave($user) {
-    $this
-      ->setNom($user->getNom())
-      ->setPrenom($user->getPrenom())
-      ->setEMail($user->getMail())
-      ->setPassword($user->getPassword())
-      ->setTelephone($user->getTelephone())
-      ->setIsContactSms($user->getIsContactSms())
-      ->setIsContactEmail($user->getIsContactMail())
-      ->setLogin($user->getLogin())
-      ;
-
-    if (!$this->_service)
-      $this->_service = $user->getSIGBComm();
-
-    $this->save();
-  }
-
-
   public function save() {
     if (!isset($this->_service))
       return false;
@@ -755,6 +744,22 @@ class Class_WebService_SIGB_Emprunteur {
   }
 
 
+  public function updateFromUser($user) {
+    $this
+      ->setNom($user->getNom())
+      ->setPrenom($user->getPrenom())
+      ->setEMail($user->getMail())
+      ->setPassword($user->getPassword())
+      ->setTelephone($user->getTelephone())
+      ->setIsContactSms($user->getIsContactSms())
+      ->setIsContactEmail($user->getIsContactMail())
+      ->setLogin($user->getLogin())
+      ;
+
+    return $this;
+  }
+
+
   /**
    * @codeCoverageIgnore
    * @return string
diff --git a/library/ZendAfi/Controller/Plugin/Manager/User.php b/library/ZendAfi/Controller/Plugin/Manager/User.php
index eebb6c93502283f92d84472ee46bd6173af48d9a..71440fb095b9b0abe99d18a6f234ec17f59f52f0 100644
--- a/library/ZendAfi/Controller/Plugin/Manager/User.php
+++ b/library/ZendAfi/Controller/Plugin/Manager/User.php
@@ -98,10 +98,20 @@ class ZendAfi_Controller_Plugin_Manager_User extends ZendAfi_Controller_Plugin_M
   }
 
 
-  protected function _setupFormAndSave($model) {
-    if ($this->_request->isPost())
-      $model->updateSIGBOnSave();
+  protected function _doBeforeSave($model) {
+    parent::_doBeforeSave($model);
+    $model->getEmprunteur()->updateFromUser($model);
+    return $this;
+  }
 
+
+  protected function _doAfterSave($model) {
+    $model->getEmprunteur()->ensureService($model)->save();
+    return parent::_doAfterSave($model);
+  }
+
+
+  protected function _setupFormAndSave($model) {
     try {
       return parent::_setupFormAndSave($model);
     } catch (Exception $e) {
diff --git a/library/ZendAfi/Form/Admin/Library.php b/library/ZendAfi/Form/Admin/Library.php
index fa54c681971f3fa2a2b9fae4d03c17e4552169eb..31674b5e6c253f3862de76747708ab852435824a 100644
--- a/library/ZendAfi/Form/Admin/Library.php
+++ b/library/ZendAfi/Form/Admin/Library.php
@@ -131,11 +131,17 @@ class ZendAfi_Form_Admin_Library extends ZendAfi_Form {
                    ['label' => $this->_('Annexe'),
                     'rows' => 4,
                     'cols' => 51])
+
       ->addElement('textarea', 'horaire',
                    ['label' => $this->_('Horaire'),
                     'rows' => 4,
                     'cols' => 51])
 
+      ->addElement('textarea', 'reset_password',
+                   ['label' => $this->_('Comment modifier mon mot de passe'),
+                    'rows' => 4,
+                    'cols' => 51])
+
       ->addElement('select', 'visibilite', ['label' => $this->_('Statut de la bib'),
                                             'multiOptions' => (new Class_Bib())->getAllStatus(),
                                             ])
@@ -176,7 +182,8 @@ class ZendAfi_Form_Admin_Library extends ZendAfi_Form {
                          'fond',
                          'procure',
                          'annexe',
-                         'horaire'],
+                         'horaire',
+                         'reset_password'],
                         'informations',
                         ['legend' => $this->_('Informations')])
 
diff --git a/library/ZendAfi/Validate/LostUsername.php b/library/ZendAfi/Validate/LostUsername.php
index eead94453952c1080477cccb6a55b4ddceb2fe0d..086cd10cec0ca61f96d0a26299a8213900395bb9 100644
--- a/library/ZendAfi/Validate/LostUsername.php
+++ b/library/ZendAfi/Validate/LostUsername.php
@@ -25,13 +25,17 @@ class ZendAfi_Validate_LostUsername extends Zend_Validate_Abstract {
 
   const
     NO_USER = 'no_user',
-    NO_MAIL = 'no_mail';
+    NO_MAIL = 'no_mail',
+    NO_ACTIVE_USER = 'no_active';
 
 
   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.")];
+
+       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."),
+
+       static::NO_ACTIVE_USER => $this->_("Votre compte n\'a pas encore été activé. Veuillez utiliser le lien d\'activation reçu précédemment par mail ou vous adresser à la bibliothèque si vous ne l\'avez pas reçu.")];
   }
 
 
@@ -42,11 +46,23 @@ class ZendAfi_Validate_LostUsername extends Zend_Validate_Abstract {
    */
   public function isValid($value, array $fields_values = array()) {
     $value = ZendAfi_Filters_Post::filterStatic($value);
-    if (!$user = Class_Users::findFirstValidOrNotBy(['login' => $value])) {
+
+    if ($user = Class_UsersNonValid::findFirstBy(['login' => $value])) {
+      $this->_error(static::NO_ACTIVE_USER);
+      return false;
+    }
+
+    if (!$user = Class_Users::findFirstBy(['login' => $value])) {
       $this->_error(static::NO_USER);
       return false;
     }
 
+    if (!(new Class_User_LostPass($user))->isValid(function($message)
+                                                   {
+                                                     return $this->addError($message);
+                                                   }))
+      return false;
+
     if (!$user->hasMail()) {
       $this->_error(static::NO_MAIL);
       return false;
@@ -54,4 +70,12 @@ class ZendAfi_Validate_LostUsername extends Zend_Validate_Abstract {
 
     return true;
   }
+
+
+  public function addError($message) {
+    $key = md5($message);
+    $this->_messageTemplates [$key] = $message;
+    $this->_error($key);
+    return false;
+  }
 }
diff --git a/library/digital_resources/Cvs/tests/CvsTest.php b/library/digital_resources/Cvs/tests/CvsTest.php
index 23197364e4e6546e1028b77b426bd7663ca16a53..b1bec27ccd8b64f243cc8f98a20f931b9c6982e6 100644
--- a/library/digital_resources/Cvs/tests/CvsTest.php
+++ b/library/digital_resources/Cvs/tests/CvsTest.php
@@ -649,6 +649,8 @@ class CvsSearchWithJerryLoggedTest extends CvsActivatedTestCase {
                              'nom' => 'Khan',
                              'mail' => 'feu@essence.fr',
                              'password' => 'secret',
+                             'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                             'id_site' => 1,
                              'date_fin' => '2023-09-02',
                              'naissance' => '1977-06-27']);
 
@@ -757,6 +759,10 @@ class CvsLinkWithBorrowerTest extends CvsActivatedTestCase {
   public function setUp() {
     parent::setUp();
 
+    $this->fixture('Class_Bib',
+                   ['id' => 34,
+                    'libelle' => 'Annecy']);
+
     $jerry = $this->fixture('Class_Users',
                             ['id' => 4,
                              'idabon' => 34,
@@ -766,15 +772,11 @@ class CvsLinkWithBorrowerTest extends CvsActivatedTestCase {
                              'nom' => 'Khan',
                              'mail' => 'feu@essence.fr',
                              'password' => 'secret',
+                             'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                             'id_site' => 34,
                              'date_fin' => '2023-09-02',
                              'naissance' => '1977-06-27']);
 
-    $jerry->setBib($this->fixture('Class_Bib',
-                                  ['id' => 34,
-                                   'libelle' => 'Annecy']));
-
-    $jerry->beAbonneSIGB();
-
     ZendAfi_Auth::getInstance()->logUser($jerry);
 
     $this->_cvs = new Cvs_Service;
@@ -858,6 +860,10 @@ class CvsServiceWithBorrowerAndLibraryLabelTest extends CvsActivatedTestCase {
 
     Class_AdminVar::set('Cvs_BMLABEL', 'Chinon-Vienne-Loire');
 
+    $this->fixture('Class_Bib',
+                   ['id' => 34,
+                    'libelle' => 'Annecy']);
+
     $jerry = $this->fixture('Class_Users',
                             ['id' => 4,
                              'idabon' => 34,
@@ -866,14 +872,12 @@ class CvsServiceWithBorrowerAndLibraryLabelTest extends CvsActivatedTestCase {
                              'prenom' => 'Jerry',
                              'nom' => 'Khan',
                              'mail' => 'feu@essence.fr',
+                             'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                             'id_site' => 34,
                              'password' => 'secret',
                              'date_fin' => '2023-09-02',
                              'naissance' => '1977-06-27']);
 
-    $jerry->setBib($this->fixture('Class_Bib',
-                                  ['id' => 34,
-                                   'libelle' => 'Annecy']));
-
     ZendAfi_Auth::getInstance()->logUser($jerry);
 
     $this->_cvs = new Cvs_Service;
diff --git a/library/storm b/library/storm
index 5f6d083091b950f93fdf19d87fb6e64aa76cb1cf..03a836b167a34618068cfe97d6cd9a3b04b34053 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit 5f6d083091b950f93fdf19d87fb6e64aa76cb1cf
+Subproject commit 03a836b167a34618068cfe97d6cd9a3b04b34053
diff --git a/robots.txt b/robots.txt
index 78c7e9ed19c575e3c7e7a61e0ed3db677bb7fc05..f6a5693a894b1a8db232691da1f72b7089eb6fbb 100644
--- a/robots.txt
+++ b/robots.txt
@@ -1,4 +1,5 @@
 User-Agent: *
+Disallow: /*/facette/*
 Disallow: /ckeditor/
 Disallow: /amber/
 Crawl-delay: 10 
diff --git a/tests/application/modules/admin/controllers/BibControllerTest.php b/tests/application/modules/admin/controllers/BibControllerTest.php
index 6f9c4939f955898c626ee9b7ad7f985e88595557..3f841e5880d0cc4bc164d14dff167d5d2a7b057d 100644
--- a/tests/application/modules/admin/controllers/BibControllerTest.php
+++ b/tests/application/modules/admin/controllers/BibControllerTest.php
@@ -62,6 +62,7 @@ abstract class BibControllerTestCase extends AbstractControllerTestCase {
                                         'inscription' => 'gratuite !',
                                         'pret' => 'sur demande' ,
                                         'procure' => 'a la bibliotheque',
+                                        'reset_password' => 'Se présenter à l\'accueil',
                                         'annexe' => 'lac',
                                         'horaire' => '10-12',
                                         'fond' => 'documentaires',
@@ -375,7 +376,8 @@ class BibControllerWithAdminBibEditAnnecyTest extends BibControllerWithAdminBibT
             [ 'fond', 'documentaires' ],
             [ 'procure' , 'a la bibliotheque' ],
             [ 'annexe', 'lac' ],
-            [ 'horaire', '10-12']
+            [ 'horaire', '10-12'],
+            [ 'reset_password', 'Se présenter à l\'accueil'],
     ];
   }
 
@@ -575,6 +577,7 @@ class BibControllerWithAdminBibEditAnnecyPostTest extends BibControllerWithAdmin
                          'gln' => '9876',
                          'visibilite' => '2',
                          'procure' => 'bib',
+                         'reset_password' => 'Se réabonner',
                          'id_bib' => 2]);
   }
 
@@ -589,6 +592,7 @@ class BibControllerWithAdminBibEditAnnecyPostTest extends BibControllerWithAdmin
             [ ['telephone' => '04 56 56 56 56'] ],
             [ ['visibilite' => '2'] ],
             [ ['procure' => 'bib'] ],
+            [ ['reset_password' => 'Se réabonner'] ],
     ];
   }
 
diff --git a/tests/application/modules/admin/controllers/UsersControllerTest.php b/tests/application/modules/admin/controllers/UsersControllerTest.php
index f8262bbff007daed003888690afa64b7ceccacfa..f8991c555b319485803733efda69266894e938f8 100644
--- a/tests/application/modules/admin/controllers/UsersControllerTest.php
+++ b/tests/application/modules/admin/controllers/UsersControllerTest.php
@@ -133,10 +133,10 @@ class UsersControllerIndexTest extends UsersControllerWithMarcusTestCase {
 
          ->whenCalled('findAllBy')
          ->with(['idabon' => '',
-                 'password' => 'francis',
+                 'password' => $francis->getPassword(),
                  'login' => 'francis',
                  'ordreabon' => ''])
-         ->answers($francis)
+         ->answers([$francis])
 
          ->whenCalled('findAllBy')
          ->with(['role_level' => 2,
@@ -784,12 +784,6 @@ class UsersControllerReferentIndexTest extends UsersControllerWithMarcusTestCase
 
 
 class UsersControllerAddActionPostTest extends UsersControllerWithMarcusTestCase {
-  public function setUp() {
-    parent::setUp();
-    $this->user_loader = $this->onLoaderOfModel('Class_Users');
-  }
-
-
   protected function _postData() {
     $this->postDispatch('/admin/users/add',
                         ['login' => 'mdavis',
@@ -800,8 +794,8 @@ class UsersControllerAddActionPostTest extends UsersControllerWithMarcusTestCase
                          'mail' => 'mdavis@free.fr',
                          'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
                          'id_site' => '100',
-                         'idabon' => '2341',
-                         'ordreabon' => '2',
+                         'idabon' => '3444',
+                         'ordreabon' => '',
                          'telephone' => '',
                          'adresse' => '',
                          'code_postal' => '',
@@ -817,20 +811,8 @@ class UsersControllerAddActionPostTest extends UsersControllerWithMarcusTestCase
 
   /** @test */
   public function validDataShouldRedirectToUsers() {
-    $this->user_loader
-      ->whenCalled('save')
-      ->answers(true)
-
-      ->whenCalled('findFirstBy')
-      ->answers(null)
-
-      ->whenCalled('getIdentity')
-      ->answers(Class_Users::newInstanceWithId(777)
-                ->setLogin('sysadmin')
-                ->setRoleLevel(ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN)
-                ->setPseudo('admin'));
-
     $this->_postData();
+    $this->assertNotNull(Class_Users::findFirstBy(['login' => 'mdavis']));
     $this->assertRedirect();
   }
 
@@ -1365,6 +1347,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                    ['id' => 2,
                     'login' => 'Ret',
                     'password' => 'urn',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => '49',
                     'ordreabon' => 1]);
 
@@ -1372,6 +1356,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                    ['id' => 29,
                     'login' => 'Ret',
                     'password' => 'urn',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => '49',
                     'ordreabon' => 1]);
 
@@ -1379,6 +1365,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                    ['id' => 123,
                     'login' => 'Ret',
                     'password' => 'urn',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => '49',
                     'ordreabon' => 2]);
 
@@ -1386,6 +1374,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                    ['id' => 25,
                     'login' => 'Ret',
                     'password' => 'urn',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => '89',
                     'ordreabon' => 18]);
 
@@ -1393,6 +1383,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                    ['id' => 654,
                     'login' => 'Ret',
                     'password' => 'urn',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => '89',
                     'ordreabon' => 18]);
 
@@ -1400,6 +1392,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                    ['id' => 655,
                     'login' => 'Ret',
                     'password' => 'urn',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => '89',
                     'ordreabon' => 18]);
 
@@ -1431,6 +1425,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                     'login' => 'rita',
                     'date_fin' => null,
                     'password' => 'rita',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => 100,
                     'ordreabon' => 18]);
 
@@ -1442,6 +1438,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                     'date_fin' => null,
                     'login' => 'rita',
                     'password' => 'rita',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => 100,
                     'ordreabon' => 18]);
 
@@ -1462,6 +1460,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                     'login' => 'rita',
                     'date_fin' => '2017-01-08',
                     'password' => 'rita',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => $id_abon,
                     'ordreabon' => 18]);
 
@@ -1473,6 +1473,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                     'date_fin' => '2017-01-07',
                     'login' => 'rita',
                     'password' => 'rita',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => $id_abon,
                     'ordreabon' => 18]);
 
@@ -1484,6 +1486,8 @@ abstract class UsersControllerDoubleTestCase extends Admin_AbstractControllerTes
                     'date_fin' => '2016-09-07',
                     'login' => 'rita',
                     'password' => 'rita',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
                     'idabon' => $id_abon,
                     'ordreabon' => 18]);
 
diff --git a/tests/application/modules/opac/controllers/AbonneControllerEditTest.php b/tests/application/modules/opac/controllers/AbonneControllerEditTest.php
index dc36044159e944e93361ed5ce50084412dbdd96d..247e515ace75eb8b3a108211080eb609e546bdfb 100644
--- a/tests/application/modules/opac/controllers/AbonneControllerEditTest.php
+++ b/tests/application/modules/opac/controllers/AbonneControllerEditTest.php
@@ -18,31 +18,59 @@
  * along with BOKEH; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-require_once 'AbstractControllerTestCase.php';
 
 abstract class AbonneControllerEditActionWithAbonneSIGBTestCase extends AbstractControllerTestCase {
   protected $_storm_default_to_volatile = true;
 
-  protected $_jerome;
+  protected
+    $_jerome,
+    $_sigb,
+    $_mock_service;
 
   public function setUp() {
     parent::setUp();
-    $mock_emprunteur = Storm_Test_ObjectWrapper::mock();
-    $mock_emprunteur->whenCalled('updateFromUserAndSave')->answers(true);
-
-    $this->_jerome = Class_Users::newInstanceWithId(4, ['login' => 'jm',
-                                                        'prenom' => 'Jerome',
-                                                        'is_contact_sms' => true,
-                                                        'idabon' => '12345',
-                                                        'id_site' => 1,
-                                                        'password' => 'secret',
-                                                        'fiche_sigb' => ['fiche' => $mock_emprunteur]])->beAbonneSIGB();
-    ZendAfi_Auth::getInstance()->logUser($this->_jerome);
 
-    Storm_Test_ObjectWrapper::onLoaderOfModel('Class_Users')
-    ->whenCalled('save')
-    ->answers(true);
+    $comm_params = ['url_serveur' => 'http://localhost',
+                    'restful' => '1'];
+
+    $this->_mock_service = $this->mock();
+    Class_WebService_SIGB_Koha::setService(array_merge($comm_params,
+                                                       ['id_bib' => 1,
+                                                        'type' => Class_IntBib::COM_KOHA]),
+                                           $this->_mock_service
+                                           ->whenCalled('isConnected')->answers(true)
+                                           //->whenCalled('getEmpruntsOf')->answers([])
+                                           //->whenCalled('getReservationsOf')->answers([])
+                                           ->whenCalled('getEmprunteur')
+                                           ->answers(Class_WebService_SIGB_Emprunteur::nullInstance()
+                                                     ->setService($this->_mock_service))
+                                           ->whenCalled('saveEmprunteur')->answers(true));
+
+    $this->_sigb = $this->fixture('Class_IntBib',
+                                  [
+                                   'id' => 1,
+                                   'comm_params' => $comm_params,
+                                   'comm_sigb' => Class_IntBib::COM_KOHA
+                                  ]);
+
+    $this->fixture('Class_Bib', ['id' => 1,
+                                 'libelle' => 'Bibliothèque Victor Hugo',
+                                 'visibilite' => Class_Bib::V_DATA,
+                                 'int_bib' => $this->_sigb]);
+
+    $this->_jerome = $this->fixture('Class_Users',
+                                    ['id' => 4,
+                                     'login' => 'jm',
+                                     'prenom' => 'Jerome',
+                                     'is_contact_sms' => true,
+                                     'telephone' => '06 06 06 06 06',
+                                     'idabon' => '12345',
+                                     'id_site' => 1,
+                                     'id_int_bib' => 1,
+                                     'password' => 'secret',
+                                     'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB]);
 
+    ZendAfi_Auth::getInstance()->logUser($this->_jerome);
   }
 }
 
@@ -62,6 +90,9 @@ class AbonneControllerEditWithContactMailSmsPostTest extends AbonneControllerEdi
                          'mode_contact' => 'is_contact_mail',
                          'prenom' => 'Marcel',
                          'nom' => 'Mazout']);
+
+    Class_Users::clearCache();
+    $this->_jerome = Class_Users::find(4);
   }
 
 
@@ -82,16 +113,17 @@ class AbonneControllerEditWithContactMailSmsPostTest extends AbonneControllerEdi
     $this->assertTrue($this->_jerome->getIsContactMail());
   }
 
-  /** @test */
-  public function userShouldBeSaved() {
-    $this->assertTrue(Class_Users::methodHasBeenCalled('save'),
-                      implode(',', $this->_jerome->getErrors()));
-  }
 
   /** @test */
   public function responseShouldRedirectToFiche() {
     $this->assertRedirectTo('/abonne/fiche');
   }
+
+
+  /** @test */
+  public function shouldSaveInWebservice() {
+    $this->assertTrue($this->_mock_service->methodHasBeenCalled('saveEmprunteur'));
+  }
 }
 
 
@@ -254,5 +286,3 @@ class AbonneControllerEditWithContactPasswordMailTest extends AbonneControllerEd
     $this->assertXPath('//fieldset[@id="fieldset-identification"]//input[@name="confirm_password"]');
   }
 }
-
-?>
\ 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 a2ab99ab2ae847c8be953055c315fe435809f285..57ae9afff599c8baf456f1fb21c8ca1cb2776998 100644
--- a/tests/application/modules/opac/controllers/AuthControllerTest.php
+++ b/tests/application/modules/opac/controllers/AuthControllerTest.php
@@ -1372,11 +1372,11 @@ class AuthControllerLostPasswordNoMailPostTest extends AbstractControllerTestCas
     $this->postDispatch('/opac/auth/lostpass' , ['lost_username' => 'luddite']);
   }
 
-/** @test */
+
+  /** @test */
   public function withoutEmailShouldReturnErrorMessage() {
     $this->assertXPathContentContains('//div', "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.");
   }
-
 }
 
 
@@ -2486,6 +2486,15 @@ class AuthControllerPostWithSameIdSigbTest extends AbstractControllerTestCase {
                     ->whenCalled('getEmprunteur')
                     ->answers($emprunteur)
 
+                    ->whenCalled('saveEmprunteur')
+                    ->answers(false)
+
+                    ->whenCalled('getReservationsOf')
+                    ->answers([])
+
+                    ->whenCalled('getEmpruntsOf')
+                    ->answers([])
+
                     ->whenCalled('isConnected')
                     ->answers(true);
 
@@ -2628,4 +2637,57 @@ class AuthControllerPostLoginWithDifferentIdIntBibTest
     $this->assertEquals('Pasc Library', $user->getLibelleBib());
     $this->assertEquals(56, $user->getIdIntBib());
   }
+}
+
+
+
+
+class AuthControllerBorrowerLostPasswordTest extends AbstractControllerTestCase{
+  protected $_storm_default_to_volatile = true;
+
+  public function setUp() {
+    parent::setUp();
+
+    $mail_transport = new MockMailTransport();
+    Zend_Mail::setDefaultTransport($mail_transport);
+
+    $sigb = $this->fixture('Class_IntBib',
+                           ['id' => 3,
+                            'comm_params' => ['url_serveur' => 'http://localhost',
+                                              'restful' => '0'],
+                            'comm_sigb' => Class_IntBib::COM_KOHA
+                           ]);
+
+    $this->fixture('Class_Bib', ['id' => 3,
+                                 'libelle' => 'Bibliothèque Georges Brassens',
+                                 'int_bib' => $sigb]);
+
+    $user = $this->fixture('Class_Users',
+                           ['id' => 78,
+                            'login' => 'Chambelle',
+                            'password' => 'upw',
+                            'idabon' => '93658',
+                            'mail' => 'Chambelle@here.fr',
+                            'id_site' => 3,
+                            'int_bib' => $sigb]);
+
+    $user->beAbonneSIGB()->save();
+
+    ZendAfi_Auth::getInstance()->clearIdentity();
+  }
+
+
+  /** @test */
+  public function withoutSIGBProvideResetPasswordShouldDisplayCustomMessage() {
+    Class_Bib::find(3)->setResetPassword('Venir à l\'accueil');
+    $this->postDispatch('/opac/auth/lostpass' , ['lost_username' => 'Chambelle']);
+    $this->assertXPathContentContains('//ul[@class="errors"]', "Venir à l'accueil");
+  }
+
+
+  /** @test */
+  public function withoutSIGBProvideResetPasswordShouldDisplayErrorMessage() {
+    $this->postDispatch('/opac/auth/lostpass' , ['lost_username' => 'Chambelle']);
+    $this->assertXPathContentContains('//ul[@class="errors"]', 'Merci de vous adresser à la bibliothèque pour récupérer votre mot de passe ou bien le remplacer par un nouveau.');
+  }
 }
\ No newline at end of file
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index d0638524ce73d5a951f1df3b2b7bb26c796b10da..d2bbaf027c0604b1f322017a90529955b454795e 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -2102,4 +2102,20 @@ class UpgradeDB_347_Test extends UpgradeDBTestCase {
   public function mailShouldBeVarchar255() {
     $this->assertFieldType('bib_admin_users', 'mail', 'varchar(255)');
   }
+}
+
+
+
+class UpgradeDB_348_Test extends UpgradeDBTestCase {
+  public function prepare() {
+    try {
+      $this->query('ALTER TABLE bib_c_site drop column reset_password');
+    } catch(Exception $e) {}
+  }
+
+
+  /** @test */
+  public function mailShouldBeVarchar255() {
+    $this->assertFieldType('bib_c_site', 'reset_password', 'text');
+  }
 }
\ No newline at end of file
diff --git a/tests/library/Class/User/LostPassTest.php b/tests/library/Class/User/LostPassTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7844721e2458757f810826a709797e50f2f568fb
--- /dev/null
+++ b/tests/library/Class/User/LostPassTest.php
@@ -0,0 +1,102 @@
+<?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_LostPassSendTest extends ModelTestCase {
+  protected
+    $_storm_default_to_volatile = true,
+    $_mail_transport,
+    $_user;
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_Profil',
+                   ['id' => 1,
+                    'libelle' => 'Portal',
+                    'mail_site' => 'nobody@nowhere.com'
+                   ])->beCurrentProfil();
+
+    $this->_mail_transport = new MockMailTransport();
+    Zend_Mail::setDefaultTransport($this->_mail_transport);
+
+    $this->_sigb = $this->fixture('Class_IntBib',
+                                  [
+                                   'id' => 3,
+                                   'comm_params' => ['url_serveur' => 'http://localhost',
+                                                     'restful' => '1'],
+                                   'comm_sigb' => Class_IntBib::COM_KOHA
+                                  ]);
+
+    $this->fixture('Class_Bib', ['id' => 3,
+                                 'libelle' => 'Bibliothèque Georges Brassens',
+                                 'int_bib' => $this->_sigb,
+                                 'reset_password' => 'Venir à l\'accueil']);
+
+    $this->_user = $this->fixture('Class_Users',
+                                  ['id' => 78,
+                                   'login' => 'Chambelle',
+                                   'password' => 'upw',
+                                   'idabon' => '93658',
+                                   'mail' => 'Chambelle@here.fr',
+                                   'id_site' => 3,
+                                   'int_bib' => $this->_sigb]);
+
+    $this->_user->beAbonneSIGB()->save();
+  }
+
+
+  /** @test */
+  public function withKohaRestfulShouldMailShouldContainsResetLink() {
+    (new Class_User_LostPass($this->_user))->send();
+    $mail = $this->_mail_transport->getSentMails()[0]->getBodyText()->getContent();
+    $this->assertContains('/auth/reset-password', $mail);
+  }
+
+
+  /** @test */
+  public function withUserGuestMailShouldContainsResetLink() {
+    $this->_user->beInvite()->save();
+    (new Class_User_LostPass($this->_user))->send();
+    $mail = $this->_mail_transport->getSentMails()[0]->getBodyText()->getContent();
+    $this->assertContains('/auth/reset-password', $mail);
+  }
+
+
+  /** @test */
+  public function withKohaNotRestfultShouldNotSendMail() {
+    $this->_sigb->setCommParams(['url_serveur' => 'http://localhost',
+                                 'restful' => '0'])
+                ->save();
+
+    (new Class_User_LostPass($this->_user))->send();
+    $this->assertEmpty($this->_mail_transport->getSentMails());
+  }
+
+
+  /** @test */
+  public function withPergameShouldNotsendMail() {
+    $this->_sigb->setCommSigb(Class_IntBib::COM_PERGAME)->save();
+    Class_Bib::find(3)->setResetPassword('');
+    (new Class_User_LostPass($this->_user))->send();
+    $this->assertEmpty($this->_mail_transport->getSentMails());
+  }
+}
diff --git a/tests/library/Class/UserDatasTest.php b/tests/library/Class/UserDatasTest.php
index 23b4ff0f5dab10d1b5f86e5267e6d9f2d3a19158..a3b2319c04af20648b82f772105cfd775a1377ff 100644
--- a/tests/library/Class/UserDatasTest.php
+++ b/tests/library/Class/UserDatasTest.php
@@ -46,11 +46,13 @@ class UserDatasTest extends UserDatasTestCase {
 
     $this->fixture('Class_Users', ['id' => 45,
                                    'login' => 'actarus',
-                                   'password' => 'vega4ever']);
+                                   'password' => 'vega4ever',
+                                   'mail' => 'vegarulez@moon.sky']);
 
     $this->fixture('Class_Users', ['id' => 46,
                                    'login' => 'venusia',
-                                   'password' => 'vega4ever']);
+                                   'password' => 'vega4ever',
+                                   'mail' => 'vegarulez@moon.sky']);
 
 
     $this->_sql->whenCalled('fetchOne')
@@ -85,7 +87,7 @@ class UserDatasTest extends UserDatasTestCase {
 
   /** @test */
   public function givingToMultipleTargetsShouldDoNothing() {
-    $this->assertFalse($this->_datas->giveTo(['password' => 'vega4ever'], true));
+    $this->assertFalse($this->_datas->giveTo(['mail' => 'vegarulez@moon.sky'], true));
     $this->assertEquals('Too many targets', $this->_datas->getError());
   }
 
diff --git a/tests/library/Class/UsersNonValidTest.php b/tests/library/Class/UsersNonValidTest.php
index cca90045c74054336c9a64203d0eef28f2cd3c73..02112526c7d71201b5bc8cf82578eef5929add1e 100644
--- a/tests/library/Class/UsersNonValidTest.php
+++ b/tests/library/Class/UsersNonValidTest.php
@@ -66,8 +66,7 @@ class Class_UsersNonValidActivateTest extends ModelTestCase {
 
 
   /** @test */
-  public function userPasswordShouldBeIfeelgood() {
-    $this->assertEquals('ifeelgood', $this->_new_user->getPassword());
+  public function userPasswordShouldBeIfeelgoodHashed() {
+    $this->assertTrue($this->_new_user->verifyPassword('ifeelgood'));
   }
 }
-?>
\ No newline at end of file
diff --git a/tests/library/Class/UsersTest.php b/tests/library/Class/UsersTest.php
index 82ce9b58d7018267adfd64b62b9c6f2f176c9cb6..12c8bca049867f68361c3e518e2d267827d99b93 100644
--- a/tests/library/Class/UsersTest.php
+++ b/tests/library/Class/UsersTest.php
@@ -550,60 +550,6 @@ abstract class UsersMailingActionTestCase extends Storm_Test_ModelTestCase {
 
 
 
-
-class UsersLostPassTest extends UsersMailingActionTestCase {
-  protected $ret, $mail;
-
-  public function setUp() {
-    parent::setUp();
-
-    $this->fixture('Class_Users',
-                   ['id' => '8',
-                    'login' => 'zork',
-                    'mail' => 'zork@afi.fr',
-                    'password' => '123']);
-
-
-    $this->fixture('Class_UsersNonValid',
-                   ['id' => '9',
-                    'login' => 'glub',
-                    'mail' => 'glub@afi.fr',
-                    'password' => '456']);
-
-    $this->ret = $this->user->lostPass('zork');
-  }
-
-
-  /** @test */
-  public function retShouldContainsUnMailViensDetreEnvoye() {
-    $this->assertContains('Un mail vient de vous', $this->ret['message_mail']);
-  }
-
-
-  /** @test */
-  public function mailShouldHaveBeenSentToZork() {
-    $this->assertContains('zork@afi.fr', $this->getSentMailRecipients());
-  }
-
-
-  /** @test */
-  public function mailShouldContainsLoginAndPassword() {
-    $body = $this->getSentMailContent();
-    $this->assertContains('Votre identifiant : zork', $body);
-    $this->assertContains('Votre mot de passe : 123', $body);
-  }
-
-
-  /** @test */
-  public function withUserNonValidGlubMailShouldHaveBeenSentToGlub() {
-    $this->ret = $this->user->lostPass('glub');
-    $this->assertContains('glub@afi.fr', $this->getSentMailRecipients());
-  }
-}
-
-
-
-
 class UsersFicheAbonneTest extends ModelTestCase {
   protected
     $_storm_default_to_volatile = true,
@@ -879,14 +825,18 @@ class UsersGetUsersWithBlowfishPasswordTest extends ModelTestCase {
     $this->fixture('Class_Users',
                    ['id' => 1,
                     'login' => 'Biquette',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
+                    'idabon' => '3',
                     'password' => '.ACeW295qSfRJuTd04i/zwjjNI67ZUmVIHe']);
 
     $this->fixture('Class_Users',
                    ['id' => 2,
                     'login' => 'Biquette',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'id_site' => 1,
+                    'idabon' => '12',
                     'password' => '$2a$08$gPuCFG7FU2psZ52z5R.ACeW295qSfRJuTd04i/zwjjNI67ZUmVIHe']);
-
-
   }
 
 
@@ -938,4 +888,64 @@ class UserGetBookmarkedLibraryTest extends ModelTestCase {
     $this->assertContains('56', Class_Users::find(15)->getSettings());
   }
 }
-?>
\ No newline at end of file
+
+
+
+class UsersWithLoginThroughSigbOnlyTest extends ModelTestCase {
+
+  protected $_storm_default_to_volatile = true;
+
+
+  /** @test */
+  public function borrowerPasswordShouldBeEmpty() {
+    Class_AdminVar::set('LOGIN_THROUGH_SIGB_ONLY', 1);
+
+    $this->fixture('Class_Bib',
+                   ['id' => 58,
+                    'libelle' => 'Login through SIGB bought']);
+
+    $user = $this->fixture('Class_Users',
+                           ['id' => 5,
+                            'login' => 'test',
+                            'password' => '123123',
+                            'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                            'idabon' => '654',
+                            'id_site' => 58]);
+
+    $this->assertEquals('', $user->getPassword());
+  }
+
+
+  /** @test */
+  public function borrowerPasswordShouldBe123123() {
+    Class_AdminVar::set('LOGIN_THROUGH_SIGB_ONLY', 0);
+
+    $this->fixture('Class_Bib',
+                   ['id' => 58,
+                    'libelle' => 'Login through SIGB bought']);
+
+    $user = $this->fixture('Class_Users',
+                           ['id' => 5,
+                            'login' => 'test',
+                            'password' => '123123',
+                            'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                            'idabon' => '654',
+                            'id_site' => 58]);
+
+    $this->assertEquals('123123', $user->getPassword());
+  }
+
+
+  /** @test */
+  public function userPasswordShouldBeHashed() {
+    Class_AdminVar::set('LOGIN_THROUGH_SIGB_ONLY', 1);
+
+    $user = $this->fixture('Class_Users',
+                           ['id' => 5,
+                            'login' => 'test',
+                            'password' => '123123',
+                            'role_level' => ZendAfi_Acl_AdminControllerRoles::INVITE]);
+
+    $this->assertTrue((new Class_User_Password($user))->isBlowFish());
+  }
+}
\ No newline at end of file
diff --git a/tests/library/Class/WebService/SIGB/KohaRestfulTest.php b/tests/library/Class/WebService/SIGB/KohaRestfulTest.php
index 93c4a3a81bd90b4fdd44c75535c6b6dda003665f..39339c1d134bfd146ba08764c3972ae165b7e51e 100644
--- a/tests/library/Class/WebService/SIGB/KohaRestfulTest.php
+++ b/tests/library/Class/WebService/SIGB/KohaRestfulTest.php
@@ -443,6 +443,8 @@ class KohaRestfulChangePasswordTest extends KohaRestfulTestCase {
     $user = $this->fixture('Class_Users',
                            ['id' => 34,
                             'login' => 'harlock',
+                            'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                            'id_site' => 1,
                             'password' => 'arcadia',
                             'idabon' => 'AO989IE']);
 
@@ -456,9 +458,12 @@ class KohaRestfulChangePasswordTest extends KohaRestfulTestCase {
       ->answers(json_encode([['success' =>  ['password' => '$2a$08$o0BrhvBevJBbWcYJElH3IevoytrdwnkZUQLwNcxQt3GhAjtht3RoK']]]))
       ->beStrict();
 
-    $user
-      ->setPassword('ce1snm2p')
-      ->save();
+
+    $user->setPassword('ce1snm2p');
+    $borrower->updateFromUser($user);
+    $user->save();
+    Class_Users::clearCache();
+    $borrower->save();
   }
 
 
@@ -466,4 +471,10 @@ class KohaRestfulChangePasswordTest extends KohaRestfulTestCase {
   public function userPasswordShouldBeCe1snm2p() {
     $this->assertEquals('ce1snm2p', Class_Users::find(34)->getPassword());
   }
+
+
+  /** @test */
+  public function kohaShouldHaveBeenCalled() {
+    $this->assertTrue($this->mock_web_client->methodHasBeenCalled('putData'));
+  }
 }
\ No newline at end of file
diff --git a/tests/library/Class/WebService/SIGB/OpsysServiceTest.php b/tests/library/Class/WebService/SIGB/OpsysServiceTest.php
index 874aea44d7e3e109e35625493541c1c5cfb38cb3..81a8167d631667178b5ddd1ad66b2e6b4877fa77 100644
--- a/tests/library/Class/WebService/SIGB/OpsysServiceTest.php
+++ b/tests/library/Class/WebService/SIGB/OpsysServiceTest.php
@@ -698,12 +698,12 @@ class OpsysServiceEmprAuthentifierTestCreateEmprunteur extends OpsysServiceWithS
       ->answers($result);
 
     try {
-      Class_Users::find(123)
+      $user = Class_Users::find(123)
         ->setFicheSIGB(['fiche' => $this->emprunteur])
         ->setIntBib(Class_IntBib::newInstanceWithId(2, ['comm_sigb' => Class_IntBib::COM_OPSYS,
                                                         'comm_params' => serialize([ 'url_serveur' => "http://localhost:8088/mockServiceRechercheSoap?WSDL",
-                                                                                     'catalogue_web' => '1'])]))
-        ->save();
+                                                                                     'catalogue_web' => '1'])]));
+      $this->emprunteur->updateFromUser($user)->save();
       $this->fail();
     } catch (Exception $e) {
       $this->assertEquals("(1) zork", $e->getMessage());
diff --git a/tests/library/Class/WebService/SIGB/PMBTest.php b/tests/library/Class/WebService/SIGB/PMBTest.php
index a44e5fbffa0fdf8fd4ef81df1c49a10b3fa39b5c..c428791932cc8d34c1e1196ca10cfb751023c432 100644
--- a/tests/library/Class/WebService/SIGB/PMBTest.php
+++ b/tests/library/Class/WebService/SIGB/PMBTest.php
@@ -111,6 +111,9 @@ class PMBServiceTest extends PMBTestCase {
                                    'id_sigb' => '654987',
                                    'mail' => 'anemail@web.com',
                                    'naissance' => '2002-12-14',
+                                   'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                                   'id_site' => 1,
+                                   'idabon' => '654987',
                                    'password' => 'pollux',
                                    'date_fin' => '2015-12-14']);