diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d4a2e5fc0ff5ff011883dd9f3f2f9ac032e6ca3..18532dfff7f828c300072de3b4db691cf1ba5dfd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,8 +5,15 @@
 - Authentification locale activable/désactivable dans la config.
     - Clé de config `unicaen-auth` > `local` > `enabled`.
 
-- Fonctionnalité "Mot de passe oublié" pour l'authentification locale. 
+- Ajout de la fonctionnalité "Mot de passe oublié" pour l'authentification locale. 
     - Principe: un lien contenant un token est envoyé par mail à l'utilisateur.
     - NB: Le username de l'utilisateur doit être une adresse électronique.
-    - NB: nécessitéd de créer une nouvelle colonne dans la table des utilisateurs,
+    - NB: nécessité de créer une nouvelle colonne dans la table des utilisateurs,
       cf. [répertoire data](./data).    
+
+## 1.3.1 - 25/01/2019
+
+- Fonctionnalité "Mot de passe oublié" :
+    - Correction: l'utilisateur n'était pas recherché par son username!
+    - Ajout d'un validateur sur le formulaire de saisie de l'adresse électronique.
+    - Vérification que le compte utilisateur est bien local.
diff --git a/src/UnicaenAuth/Controller/AuthController.php b/src/UnicaenAuth/Controller/AuthController.php
index 33747a8659674b6081988871cdb2c7021c819d36..643d6d1bb9ab909715bbb39e86684c779f5ef331 100644
--- a/src/UnicaenAuth/Controller/AuthController.php
+++ b/src/UnicaenAuth/Controller/AuthController.php
@@ -2,7 +2,7 @@
 
 namespace UnicaenAuth\Controller;
 
-use Doctrine\ORM\NoResultException;
+use DomainException;
 use UnicaenApp\Controller\Plugin\AppInfos;
 use UnicaenApp\Controller\Plugin\Mail;
 use UnicaenApp\Exception\RuntimeException;
@@ -135,24 +135,42 @@ class AuthController extends AbstractActionController
             $form->setData($data);
             if ($form->isValid()) {
                 $email = $data['email'];
-                $this->processPasswordResetRequest($email);
-
-                $view->setVariable('email', $email);
-                $view->setTemplate('unicaen-auth/auth/request-password-reset-success');
+                try {
+                    $this->processPasswordResetRequest($email);
+
+                    $view->setVariable('email', $email);
+                    $view->setTemplate('unicaen-auth/auth/request-password-reset-success');
+                } catch (DomainException $de) {
+                    // affichage de l'erreur comme une erreur de validation
+                    $form->get('email')->setMessages([$de->getMessage()]);
+                }
             }
         }
 
         return $view;
     }
 
+    /**
+     * @param string $email
+     */
     private function processPasswordResetRequest($email)
     {
-        try {
-            $token = $this->userService->updateUserPasswordResetToken($email);
-        } catch (NoResultException $nre) {
-            // aucun utilisateur trouvé tel que username = $email
+        // Recherche de l'utilisateur ayant pour *username* (login) l'email spécifié
+        $user = $this->userService->getUserMapper()->findOneByUsername($email);
+
+        if ($user === null) {
+            // Aucun utilisateur trouvé ayant l'email spécifié :
+            // on ne fait rien mais on ne le signale pas sinon le formulaire permettrait
+            // de tester si des emails potentiellement valides existent dans la base.
             return;
         }
+        if (! $user->isLocal()) {
+            // L'email spécifié appartient à un utilisateur non local : on signale l'impossibilité de changer le mdp.
+            throw new DomainException("Le changement de mot de passe n'est pas possible pour cet utilisateur.");
+        }
+
+        // génération/enregistrement d'un token
+        $token = $this->userService->updateUserPasswordResetToken($user);
 
         // envoi du mail contenant le lien de changement de mdp
         $app = $this->appInfos()->getNom();
diff --git a/src/UnicaenAuth/Entity/Db/AbstractUser.php b/src/UnicaenAuth/Entity/Db/AbstractUser.php
index a8adfa17b9254fb4ee540ce1ac35af59a872889d..9b0b006e82f09f43f49df431720b88f9b85a4a38 100644
--- a/src/UnicaenAuth/Entity/Db/AbstractUser.php
+++ b/src/UnicaenAuth/Entity/Db/AbstractUser.php
@@ -14,6 +14,9 @@ use Doctrine\ORM\Mapping as ORM;
  */
 abstract class AbstractUser implements UserInterface, ProviderInterface
 {
+    const PASSWORD_LDAP = 'ldap';
+    const PASSWORD_SHIB = 'shib';
+
     /**
      * @var int
      * @ORM\Id
@@ -246,6 +249,22 @@ abstract class AbstractUser implements UserInterface, ProviderInterface
         $this->roles->add($role);
     }
 
+    /**
+     * Retourne true si cet utilisateur est local.
+     *
+     * Un utilisateur est local s'il ne résulte pas d'une authentification LDAP ou Shibboleth.
+     * Son mot de passe est chiffré dans la table des utilisateurs.
+     *
+     * @return bool
+     */
+    public function isLocal()
+    {
+        return ! in_array($this->getPassword(), [
+            AbstractUser::PASSWORD_LDAP,
+            AbstractUser::PASSWORD_SHIB,
+        ]);
+    }
+
     /**
      *
      * @return string
diff --git a/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php b/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php
index 3312082344781febd0e56333e80c4a2aaf829613..d444b1c4c27e91895e3cecddda93d849660ee73c 100644
--- a/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php
+++ b/src/UnicaenAuth/Entity/Shibboleth/ShibUser.php
@@ -2,6 +2,7 @@
 
 namespace UnicaenAuth\Entity\Shibboleth;
 
+use UnicaenAuth\Entity\Db\AbstractUser;
 use ZfcUser\Entity\UserInterface;
 
 class ShibUser implements UserInterface
@@ -200,7 +201,7 @@ class ShibUser implements UserInterface
      */
     public function getPassword()
     {
-        return 'shib';
+        return AbstractUser::PASSWORD_SHIB;
     }
 
     /**
diff --git a/src/UnicaenAuth/Service/User.php b/src/UnicaenAuth/Service/User.php
index d566f10ef17a53edce6af21c620630db19e2db66..1d72db1f6794eb544d817870fe0ffa4b30e6e067 100644
--- a/src/UnicaenAuth/Service/User.php
+++ b/src/UnicaenAuth/Service/User.php
@@ -3,11 +3,11 @@
 namespace UnicaenAuth\Service;
 
 use DateTime;
-use Doctrine\ORM\NoResultException;
 use Ramsey\Uuid\Uuid;
 use UnicaenApp\Entity\Ldap\People;
 use UnicaenApp\Exception\RuntimeException;
 use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
+use UnicaenAuth\Entity\Db\AbstractUser;
 use UnicaenAuth\Entity\Shibboleth\ShibUser;
 use UnicaenAuth\Event\UserAuthenticatedEvent;
 use UnicaenAuth\Options\ModuleOptions;
@@ -22,11 +22,11 @@ use Zend\Form\Form;
 use Zend\InputFilter\Input;
 use Zend\ServiceManager\ServiceLocatorAwareInterface;
 use Zend\ServiceManager\ServiceLocatorAwareTrait;
+use Zend\Validator\EmailAddress;
 use Zend\Validator\Identical;
 use ZfcUser\Entity\UserInterface;
 use ZfcUser\Options\AuthenticationOptionsInterface;
 use ZfcUser\Options\ModuleOptions as ZfcUserModuleOptions;
-use UnicaenAuth\Entity\Db\AbstractUser;
 
 /**
  * Service traitant des utilisateurs locaux de l'application.
@@ -81,13 +81,13 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface
             case $userData instanceof People:
                 $username = $userData->getData($this->getOptions()->getLdapUsername());
                 $email = $userData->getMail();
-                $password = 'ldap';
+                $password = AbstractUser::PASSWORD_LDAP;
                 $state = in_array('deactivated', ldap_explode_dn($userData->getDn(), 1)) ? 0 : 1;
                 break;
             case $userData instanceof ShibUser:
                 $username = $userData->getUsername();
                 $email = $userData->getEmail();
-                $password = 'shib';
+                $password = AbstractUser::PASSWORD_SHIB;
                 $state = 1;
                 break;
             default:
@@ -260,7 +260,11 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface
         $form->add((new Text('email'))->setLabel("Adresse électronique :"));
         $form->add((new Csrf('csrf')));
         $form->add((new Submit('submit'))->setLabel("Envoyer le lien"));
-        $form->getInputFilter()->add((new Input('email'))->setRequired(true));
+
+        $emailInput = new Input('email');
+        $emailInput->setRequired(true);
+        $emailInput->getValidatorChain()->attach(new EmailAddress());
+        $form->getInputFilter()->add($emailInput);
 
         return $form;
     }
@@ -287,22 +291,13 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface
     }
 
     /**
-     * Si l'utilisateur dont le username égale l'email spécifié est trouvé,
-     * génère puis enregistre le token permettant d'autoriser cet utilisateur à changer son mot de passe.
+     * Génère puis enregistre le token permettant d'autoriser un utilisateur à changer son mot de passe.
      *
-     * @param string $email Email de l'utilisateur qui doit être aussi son username
+     * @param AbstractUser $user Utilisateur concerné
      * @return string|null Token généré
-     * @throws NoResultException Aucun utilisateur trouvé avec cet email
      */
-    public function updateUserPasswordResetToken($email)
+    public function updateUserPasswordResetToken(AbstractUser $user)
     {
-        // Si l'email est inconnu, on ne fera rien mais on ne le signale pas sinon le formulaire permettrait
-        // de tester si des emails potentiellement valides existent dans la base.
-        $user = $this->getUserMapper()->findByEmail($email); /** @var User $user */
-        if ($user === null) {
-            throw new NoResultException();
-        }
-
         // Génération du token.
         $token = $this->generatePasswordResetToken();
 
@@ -344,8 +339,14 @@ class User implements ServiceLocatorAwareInterface, EventManagerAwareInterface
      */
     public function generatePasswordResetToken()
     {
+        try {
+            $uuid = Uuid::uuid4();
+        } catch (\Exception $e) {
+            throw new RuntimeException("Erreur rencontrée lors de la génération du UUID.", null, $e);
+        }
+
         // NB: la date de fin de vie du token est concaténée à la fin.
-        $token = Uuid::uuid4()->toString() . self::PASSWORD_RESET_TOKEN_SEP . date('YmdHis', time() + 3600*24);
+        $token = $uuid->toString() . self::PASSWORD_RESET_TOKEN_SEP . date('YmdHis', time() + 3600 * 24);
         // durée de vie = 24h
 
         return $token;
diff --git a/src/UnicaenAuth/Service/UserMapper.php b/src/UnicaenAuth/Service/UserMapper.php
index b41c49b66dc40ccdeac7cc4b36fee6767d07db44..88c6b6ade37b18e82e2bd921ef7ec4b81602f2b2 100644
--- a/src/UnicaenAuth/Service/UserMapper.php
+++ b/src/UnicaenAuth/Service/UserMapper.php
@@ -2,18 +2,32 @@
 
 namespace UnicaenAuth\Service;
 
-use UnicaenAuth\Entity\Db\User;
+use UnicaenAuth\Entity\Db\AbstractUser;
 use ZfcUserDoctrineORM\Mapper\User as ZfcUserDoctrineORMUserMapper;
 
 class UserMapper extends ZfcUserDoctrineORMUserMapper
 {
+    /**
+     * Recherche un utilisateur par son username (identifiant de connexion).
+     *
+     * @param string $username
+     * @return AbstractUser|null
+     */
+    public function findOneByUsername($username)
+    {
+        /** @var AbstractUser $user */
+        $user = $this->em->getRepository($this->options->getUserEntityClass())->findOneBy(['username' => $username]);
+
+        return $user;
+    }
+
     /**
      * @param string $token
-     * @return User
+     * @return AbstractUser
      */
     public function findOneByPasswordResetToken($token)
     {
-        /** @var User $user */
+        /** @var AbstractUser $user */
         $user = $this->em->getRepository($this->options->getUserEntityClass())->findOneBy(['passwordResetToken' => $token]);
 
         return $user;
diff --git a/view/unicaen-auth/auth/request-password-reset-form.phtml b/view/unicaen-auth/auth/request-password-reset-form.phtml
index c297a4de736e83b809ac79f31fca8ff00cd44747..61e8802100efd7029f08724fa3a3bc9a95c811d9 100644
--- a/view/unicaen-auth/auth/request-password-reset-form.phtml
+++ b/view/unicaen-auth/auth/request-password-reset-form.phtml
@@ -15,8 +15,8 @@ use Zend\Form\Form;
 </h2>
 
 <p class="lead">
-    Un lien permettant de changer votre mot de passe vous sera envoyé à l'adresse que vous renseignerez ci-dessous.<br>
-    <strong>NB:</strong> Cette adresse doit correspondre au compte que vous utilisez pour vous connecter à l'application.
+    Cette page permet d'initier le changement du mot de passe associé à votre compte local de connexion à l'application.<br>
+    <strong>NB:</strong> Cela n'est possible que pour les utilisateurs se connectant avec leur adresse électronique.<br>
 </p>
 
 <div class="col-sm-4">
@@ -30,6 +30,7 @@ use Zend\Form\Form;
         echo $this->formInput($email);
         echo $this->formElementErrors($email, ['class' => 'text-danger']);
         ?>
+        <span class="help-block">Un lien à cliquer vous sera envoyé à cette adresse électronique.</span>
     </p>
 
     <?php echo $this->formInput($form->get('csrf')); ?>