diff --git a/VERSIONS_WIP/71949 b/VERSIONS_WIP/71949
new file mode 100644
index 0000000000000000000000000000000000000000..7526dd27210b90ab1865d4d395f39f86aded3367
--- /dev/null
+++ b/VERSIONS_WIP/71949
@@ -0,0 +1,2 @@
+ - ticket #71949 : Compte abonné : ajout d'un paramètre autorisant la connexion des abonnées uniquement via le webservice du SIGB.
+ 
\ No newline at end of file
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index 2fb6bc5ed7733bf857c3061aa44a27d4a221f7e2..60796c91e62b51a482601ffdf202dbac7190c0e7 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -286,6 +286,9 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
   protected function _getGlobalVars() {
     return [
             'FORCE_HTTPS' => Class_AdminVar_Meta::newOnOff($this->_('Forcer l\'accès au site par le protocole HTTPS. Nécessite l\'installation et la configuration appropriée du serveur Web')),
+            'LOGIN_THROUGH_SIGB_ONLY' => Class_AdminVar_Meta::newOnOff($this->_('Les abonnées peuvent se connecter uniquement via le webservice du SIGB.')
+                                                                       . '<br/>'
+                                                                       . $this->_('De plus, à la connexion, l\'enregistrement des mots de passes des abonnés est désactivé.'))->bePrivate(),
             'OAUTH_ACCEPT_HTTP' => Class_AdminVar_Meta::newOnOff($this->_('Autoriser l\'accès aux API OAUTH via HTTP (non sécurisé - déconseillé)'), ['value' => 0]),
             'NB_AFFICH_AVIS_PAR_AUTEUR'  => Class_AdminVar_Meta::newDefault($this->_('Nombre d\'avis maximum à afficher par utilisateur.')),
             'CLEF_GOOGLE_MAP' => Class_AdminVar_Meta::newDefault($this->_('Clef d\'activation pour le plan d\'accès google map. <a target="_blank" href="http://code.google.com/apis/maps/signup.html">Obtenir la clé google map</a>')),
@@ -876,6 +879,11 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
   }
 
 
+  public static function isLoginThroughSigbOnlyEnabled() {
+    return Class_AdminVar::isModuleEnabled('LOGIN_THROUGH_SIGB_ONLY');
+  }
+
+
   public function getBabelthequeId() {
     $mathes = [];
     if (preg_match('/bw_([^\.]+)\.js/', (string)Class_AdminVar::get('BABELTHEQUE_JS'), $matches))
diff --git a/library/Class/CommSigb.php b/library/Class/CommSigb.php
index cf96df07565cc7f5ca0bf61c304201163785ba6f..8270b3565376b07a0a0a1f85e2bd0b5b93b93401 100644
--- a/library/Class/CommSigb.php
+++ b/library/Class/CommSigb.php
@@ -22,6 +22,7 @@ class Class_CommSigb {
   use Trait_Translator;
 
   protected static $_instance = null;
+  protected static $_logger;
 
 
   public static function getInstance() {
@@ -36,6 +37,18 @@ class Class_CommSigb {
   }
 
 
+  public static function setLogger($logger) {
+    static::$_logger = $logger;
+  }
+
+
+  public static function logError($url, $message) {
+    if (!static::$_logger)
+      return;
+    static::$_logger->logError($url, $message);
+  }
+
+
   /**
    * @param array $exemplaires_to_check
    * @return array
@@ -99,6 +112,7 @@ class Class_CommSigb {
       try {
         return ['fiche' =>  $cache->loadFromCacheOrSIGB($user, $sigb)];
       } catch (Exception $e) {
+        static::logError('', $e->getMessage());
         return $this->_error($e->getMessage());
       }
     };
@@ -174,7 +188,7 @@ class Class_CommSigb {
    */
   public function supprimerReservation($std_user, $id_reservation) {
     $supprimer = function ($user, $sigb) use ($id_reservation) {
-          return $sigb->supprimerReservation($user, $id_reservation);
+      return $sigb->supprimerReservation($user, $id_reservation);
     };
 
     return $this->withUserAndSIGBDo($std_user, $supprimer);
@@ -211,7 +225,7 @@ class Class_CommSigb {
    */
   public function prolongerPret($std_user, $id_pret) {
     $prolonger = function($user, $sigb) use ($std_user, $id_pret) {
-        return $sigb->prolongerPret($user, $id_pret);
+      return $sigb->prolongerPret($user, $id_pret);
     };
 
     return $this->withUserAndSIGBDo($std_user, $prolonger);
diff --git a/library/Class/Users.php b/library/Class/Users.php
index be6e2ddaac7b6360148d2ea241edf3903c409571..1626de1a33f69d7c40c00c90e2924949f85564ef 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -120,33 +120,44 @@ class UsersLoader extends Storm_Model_Loader {
    * @return bool
    */
   public function hasIdentity() {
-    return null != $this->getIdentity();
+    return null != Class_Users::getIdentity();
+  }
+
+
+  public function isLogged($user) {
+    if(!$user)
+      return false;
+
+    if(!$logged_user = Class_Users::getIdentity())
+      return false;
+
+    return $user->getId() == $logged_user->getId();
   }
 
 
   public function isCurrentUserAdmin() {
-    if (!$user = $this->getIdentity())
+    if (!$user = Class_Users::getIdentity())
       return false;
     return $user->isAdmin();
   }
 
 
   public function isCurrentUserSuperAdmin() {
-    if (!$user = $this->getIdentity())
+    if (!$user = Class_Users::getIdentity())
       return false;
     return $user->isSuperAdmin();
   }
 
 
   public function isCurrentUserCanAccesBackend() {
-    if (!$user = $this->getIdentity())
+    if (!$user = Class_Users::getIdentity())
       return false;
     return $user->canAccessBackend();
   }
 
 
   public function isCurrentUserCanConfigFront() {
-    if (!$user = $this->getIdentity())
+    if (!$user = Class_Users::getIdentity())
       return false;
     return $user->hasRightConfigFront();
   }
@@ -157,14 +168,14 @@ class UsersLoader extends Storm_Model_Loader {
    * @return bool
    */
   public function isCurrentUserCanEditArticle($article) {
-    if (!$user = $this->getIdentity())
+    if (!$user = Class_Users::getIdentity())
       return false;
     return $user->canEditArticle($article);
   }
 
 
   public function isCurrentUserAllowedToEditLibrary($library) {
-    if(!$user = $this->getIdentity())
+    if(!$user = Class_Users::getIdentity())
       return false;
     return $user->hasRightsForLibrary($library->getId());
   }
@@ -174,7 +185,7 @@ class UsersLoader extends Storm_Model_Loader {
     if(!$profile)
       return false;
 
-    if(!$user = $this->getIdentity())
+    if(!$user = Class_Users::getIdentity())
       return false;
 
     if((!$user->isAdminBib() && !$user->hasRightConfigFront())
@@ -190,7 +201,7 @@ class UsersLoader extends Storm_Model_Loader {
    * @return bool
    */
   public function isCurrentUserCanAccessAllBibs() {
-    if (!$user = $this->getIdentity())
+    if (!$user = Class_Users::getIdentity())
       return false;
     return $user->canAccessAllBibs();
   }
@@ -1009,19 +1020,18 @@ class Class_Users extends Storm_Model_Abstract {
   /* Hook appelé sur save */
   public function validate() {
     $this->checkAttribute('login',$this->getLogin(), $this->_("Vous devez compléter le champ 'Identifiant'"));
-    $this->checkAttribute('password',$this->getPassword(), $this->_("Vous devez compléter le champ 'Mot de passe'"));
+
+    $this->_checkPassword();
 
     $this->checkAttribute('login',mb_strlen($this->getLogin(),'UTF-8') <= 50, $this->_("Le champ 'Identifiant' doit être inférieur à 50 caractères"));
 
-    if ($this->isNew()) {
+    if ($this->isNew())
       $this->checkAttribute('login', $this->_isUnique(),
                             $this->_("L'identifiant que vous avez choisi existe déjà."));
-    }
 
     $this->checkAttribute('password', mb_strlen($this->getPassword(),
                                                 'UTF-8') <= 255, $this->_("Le champ 'Mot de passe' doit être inférieur à 255 caractères"));
 
-
     if ($this->getRoleLevel() > 1 and $this->getRoleLevel() < 5 and $this->getIdSite() == 0) {
       $cls_role= new ZendAfi_Acl_AdminControllerRoles();
       $this->addError($this->_("La bibliothèque est obligatoire pour le rôle : %s",
@@ -1046,6 +1056,17 @@ class Class_Users extends Storm_Model_Abstract {
   }
 
 
+  protected function _checkPassword() {
+    if (Class_AdminVar::isLoginThroughSigbOnlyEnabled()
+        && $this->isAbonne())
+      return;
+
+    $this->checkAttribute('password',
+                          $this->getPassword(),
+                          $this->_("Vous devez compléter le champ 'Mot de passe'"));
+  }
+
+
   public function deleteUser($id_user) {
     if ($user = $this->getLoader()->find($id_user))
       $user->delete();
diff --git a/library/Class/WebService/SIGB/Koha/Service.php b/library/Class/WebService/SIGB/Koha/Service.php
index 1890f779e5a2d2d96d3bdb2fbf1bcb92d15601c9..3e417df0f41c0100b00d0eeddef41993925ba837 100644
--- a/library/Class/WebService/SIGB/Koha/Service.php
+++ b/library/Class/WebService/SIGB/Koha/Service.php
@@ -110,7 +110,17 @@ class Class_WebService_SIGB_Koha_Service extends Class_WebService_SIGB_AbstractR
    * @return Class_WebService_SIGB_Emprunteur
    */
   public function getEmprunteur($user) {
-    if (!$patron_id = $this->_authenticateWebservice($user))
+    if(!$user)
+      return Class_WebService_SIGB_Emprunteur::nullInstance();
+
+    $patron_id = Class_Users::isLogged($user)
+      ? $user->getIdSigb()
+      : '';
+
+    if(!$patron_id)
+      $patron_id = $this->_authenticateWebservice($user);
+
+    if (!$patron_id)
       return Class_WebService_SIGB_Emprunteur::nullInstance();
 
     $emprunteur = $this->getEmprunteurFor($patron_id);
diff --git a/library/ZendAfi/Auth/Adapter/CommSigb.php b/library/ZendAfi/Auth/Adapter/CommSigb.php
index c750efadcbcbacfb571a1e395ccb5198b706a9d6..dbf23edbae840a11a5d2e00cdb226224d27d753f 100644
--- a/library/ZendAfi/Auth/Adapter/CommSigb.php
+++ b/library/ZendAfi/Auth/Adapter/CommSigb.php
@@ -63,8 +63,10 @@ class ZendAfi_Auth_Adapter_CommSigb implements Zend_Auth_Adapter_Interface {
 
     $user_to_save = $this->_getUserToSave($user_from_sigb)
                          ->beAbonneSIGB()
-                         ->setLogin($this->_identity)
-                         ->setPassword($this->_credential);
+                         ->setLogin($this->_identity);
+
+    if (!Class_AdminVar::isLoginThroughSigbOnlyEnabled())
+      $user_to_save->setPassword($this->_credential);
 
     $this->_updateOptionalAttribs($user_from_sigb, $user_to_save);
 
@@ -112,28 +114,43 @@ class ZendAfi_Auth_Adapter_CommSigb implements Zend_Auth_Adapter_Interface {
   protected function _getUserFromSigb($user) {
     $bibs = $this->_getBibsToAuthenticateTo($user);
 
-    foreach($bibs as $bib) {
-      if (!$emprunteur = $bib->getSIGBComm()->getEmprunteur($user))
-        continue;
+    foreach($bibs as $bib)
+      if($user_found = $this->_getUserFromSigbWithLibrary($user, $bib))
+        return $user_found;
 
-      if (!$emprunteur->isValid())
-        continue;
+    return  null;
+  }
 
-      if ($emprunteur->getPassword() != $user->getPassword())
-        continue;
 
-      $emprunteur->updateUser($user);
+  protected function _getUserFromSigbWithLibrary($user, $library) {
+    if (!$loaner = $library->getSIGBComm()->getEmprunteur($user))
+      return;
 
-      if(!$user->hasIdSite())
-        $user->setIdSite($bib->getId());
+    if (!$loaner->isValid())
+      return;
 
-      if(!$user->hasIdIntBib())
-        $user->setIdIntBib($bib->getId());
+    if(!$loaner = $this->_loanerWithValidPassword($user, $loaner))
+      return;
 
-      return $user;
-    }
+    $loaner->updateUser($user);
 
-    return  null;
+    if(!$user->hasIdSite())
+      $user->setIdSite($library->getId());
+
+    if(!$user->hasIdIntBib())
+      $user->setIdIntBib($library->getId());
+
+    return $user;
+  }
+
+
+  protected function _loanerWithValidPassword($user, $loaner) {
+    if (Class_AdminVar::isLoginThroughSigbOnlyEnabled())
+      return $loaner->setPassword('');
+
+    return ($loaner->getPassword() == $user->getPassword())
+      ? $loaner
+      : null;
   }
 
 
diff --git a/tests/application/modules/opac/controllers/AuthControllerWithoutPasswordTest.php b/tests/application/modules/opac/controllers/AuthControllerWithoutPasswordTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..22ad1712f2bff501b5e10c8f965be2a4a6f6b7a4
--- /dev/null
+++ b/tests/application/modules/opac/controllers/AuthControllerWithoutPasswordTest.php
@@ -0,0 +1,174 @@
+<?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
+ */
+
+require_once 'tests/fixtures/KohaFixtures.php';
+
+abstract class AuthControllerWithoutPasswordTestCase extends AbstractControllerTestCase {
+  protected
+    $_storm_default_to_volatile = true,
+    $_mock_web_client,
+    $_emprunteur,
+    $_service,
+    $_params;
+
+  public function setUp() {
+    parent::setUp();
+
+    $logger = $this->mock()
+                   ->whenCalled('log')->answers(true)
+
+                   ->whenCalled('logError')
+                   ->willDo(
+                            function($url, $message) {
+                              throw new RuntimeException($url . ' :: ' . $message);
+                            });
+
+    Class_CommSigb::setLogger($logger);
+    Class_WebService_SIGB_AbstractService::setLogger($logger);
+
+    Class_AdminVar::set('LOGIN_THROUGH_SIGB_ONLY', 1);
+    ZendAfi_Auth::getInstance()->clearIdentity();
+
+    $this->_emprunteur = Class_WebService_SIGB_Emprunteur::newInstance(789, 'koha')
+      ->setPassword('bar')
+      ->beValid();
+
+    $this->_params = ['url_serveur' => 'http://mon-koha-de-test.org',
+                      'id_bib' => 56,
+                      'type' => Class_IntBib::COM_KOHA];
+
+    $this->_setService();
+
+    Class_WebService_SIGB_Koha::setService($this->_params,
+                                           $this->_service);
+
+    $this->fixture('Class_Bib',
+                   ['id' => 56,
+                    'libelle' => 'Library']);
+
+    $this->fixture('Class_IntBib',
+                   ['id' => 56,
+                    'id_bib' => 56,
+                    'comm_sigb' => 5,
+                    'comm_params' => serialize($this->_params)]);
+
+    $this->fixture('Class_Users',
+                   ['id' => 5,
+                    'login' => 'foo',
+                    'password' => '',
+                    'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB,
+                    'idabon' => 'foo',
+                    'id_site' => 56,
+                    'id_int_bib' => 56,
+                    'id_sigb' => 789]);
+  }
+
+
+  protected function _setService() {}
+
+
+  public function tearDown() {
+    Class_CommSigb::setLogger(null);
+    Class_WebService_SIGB_AbstractService::setLogger(null);
+    Class_WebService_SIGB_Koha::reset();
+    $this->_mock_web_client = null;
+    $this->_service = null;
+    $this->_emprunteur = null;
+    $this->_params = null;
+    parent::tearDown();
+  }
+}
+
+
+
+class AuthControllerWithoutPasswordKohaTest extends AuthControllerWithoutPasswordTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->postDispatch('/opac/auth/login', ['username' => 'foo', 'password' => 'bar']);
+  }
+
+
+  protected function _setService() {
+    $this->_service = $this->mock()
+
+                           ->whenCalled('getEmprunteur')
+                           ->answers($this->_emprunteur)
+
+                           ->whenCalled('isConnected')
+                           ->answers(true);
+  }
+
+
+  /** @test */
+  public function userFooShouldBeLogged() {
+    $this->assertEquals('foo', Class_Users::getIdentity()->getLogin());
+  }
+
+
+  /** @test */
+  public function userFooPasswordShouldHaveNotBeenSet() {
+    $this->assertEquals('', Class_Users::getIdentity()->getPassword());
+  }
+}
+
+
+
+
+class AuthControllerDispatchAbonnePretsWithoutPasswordKohaTest extends AuthControllerWithoutPasswordTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    ZendAfi_Auth::getInstance()->logUser(Class_Users::find(5));
+    $this->dispatch('/opac/abonne/prets', true);
+  }
+
+
+  protected function _setService() {
+    $this->_mock_web_client = $this->mock()
+                                   ->whenCalled('open_url')
+                                   ->with('http://mon-koha-de-test.org?service=GetPatronInfo&patron_id=789&show_contact=1&show_loans=1&show_holds=1')
+                                   ->answers('')
+
+                                   ->beStrict();
+
+    $this->_service = Class_WebService_SIGB_Koha::getService($this->_params);
+    $this->_service->setWebClient($this->_mock_web_client);
+  }
+
+
+  /** @test */
+  public function authenticateShouldNotBeCall() {
+    $this->assertFalse(
+                       $this->_mock_web_client
+                       ->methodHasBeenCalledWithParams('open_url',
+                                                       ['http://mon-koha-de-test.org?service=AuthenticatePatron&username=foo&password=']));
+  }
+
+
+  /** @test */
+  public function patronInfoShouldBeCallWithPatronId789() {
+    $this->assertTrue(
+                      $this->_mock_web_client
+                      ->methodHasBeenCalledWithParams('open_url',
+                                                      ['http://mon-koha-de-test.org?service=GetPatronInfo&patron_id=789&show_contact=1&show_loans=1&show_holds=1']));
+  }
+}
\ No newline at end of file