diff --git a/src/UnicaenAuth/Authentication/Adapter/Db.php b/src/UnicaenAuth/Authentication/Adapter/Db.php index 20b5aeb9ef6b86ead5648b40d6167892f36d6068..dcaeac11e7189fa1ca25a16bede9095cd552212a 100644 --- a/src/UnicaenAuth/Authentication/Adapter/Db.php +++ b/src/UnicaenAuth/Authentication/Adapter/Db.php @@ -1,11 +1,14 @@ <?php namespace UnicaenAuth\Authentication\Adapter; +use UnicaenApp\Exception; +use UnicaenAuth\Authentication\Adapter\Db; +use UnicaenAuth\Options\AuthenticationOptionsInterface; use Zend\Authentication\Result as AuthenticationResult; use Zend\Crypt\Password\Bcrypt; use ZfcUser\Authentication\Adapter\AdapterChainEvent; use ZfcUser\Authentication\Adapter\AdapterChainEvent as AuthEvent; -use \UnicaenAuth\Options\AuthenticationOptionsInterface; +use ZfcUser\Entity\UserInterface; /** * Db authentication adpater with sesame password check. @@ -20,25 +23,51 @@ class Db extends \ZfcUser\Authentication\Adapter\Db protected $unicaenUserOptions; /** + * Authentification. * * @param AdapterChainEvent $e * @return boolean */ public function authenticate(AuthEvent $e) { - if ($this->isSatisfied()) { - $storage = $this->getStorage()->read(); - $e->setIdentity($storage['identity']) - ->setCode(AuthenticationResult::SUCCESS) - ->setMessages(array('Authentication successful.')); - return; + $result = parent::authenticate($e); + + // Failure, try sesame + if (false === $result) { + $identity = $e->getRequest()->getPost()->get('identity'); + if (!($userObject = $this->findUser($identity))) { + return false; + } + + $credential = $e->getRequest()->getPost()->get('credential'); + //$credential = $this->preProcessCredential($credential); + $bcrypt = new Bcrypt(); + $bcrypt->setCost($this->getOptions()->getPasswordCost()); + if (($sesame = $this->getUnicaenAuthOptions()->getSesamePassword()) && $bcrypt->verify($credential, $sesame)) { + // Success! + $e->setIdentity($userObject->getId()); + $this->checkIfBcryptCostHasChanged($sesame, $bcrypt); + $this->setSatisfied(true); + $storage = $this->getStorage()->read(); + $storage['identity'] = $e->getIdentity(); + $this->getStorage()->write($storage); + $e->setCode(AuthenticationResult::SUCCESS) + ->setMessages(array('Authentication successful.')); + } } + + return $result; + } - $identity = $e->getRequest()->getPost()->get('identity'); - $credential = $e->getRequest()->getPost()->get('credential'); - $credential = $this->preProcessCredential($credential); + /** + * Recherche dans la base de données l'utilisateur correspondant à l'identité. + * + * @param string $identity + * @return UserInterface + */ + protected function findUser($identity) + { $userObject = NULL; - // Cycle through the configured identity sources and test each $fields = $this->getOptions()->getAuthIdentityFields(); while ( !is_object($userObject) && count($fields) > 0 ) { @@ -52,39 +81,30 @@ class Db extends \ZfcUser\Authentication\Adapter\Db break; } } + return $userObject; + } - if (!$userObject) { - $e->setCode(AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND) - ->setMessages(array('A record with the supplied identity could not be found.')); - $this->setSatisfied(false); - return false; - } - - $bcrypt = new Bcrypt(); - $bcrypt->setCost($this->getOptions()->getPasswordCost()); - if (!$bcrypt->verify($credential,$userObject->getPassword())) { - // Password does not match, try sesame - if (!($sesame = $this->getUnicaenAuthOptions()->getSesamePassword()) || !$bcrypt->verify($credential, $sesame)) { - $e->setCode(AuthenticationResult::FAILURE_CREDENTIAL_INVALID) - ->setMessages(array('Supplied credential is invalid.')); - $this->setSatisfied(false); - return false; - } + /** + * Teste si la valeur du paramètre 'cost' de l'algo Bcrypt depuis le chiffrage + * du mot de passe spécifié. + * + * @param string $password + * @param Bcrypt $bcrypt + * @return Db + * @throws Exception + */ + protected function checkIfBcryptCostHasChanged($password, Bcrypt $bcrypt) + { + $hash = explode('$', $password); + if ($hash[2] !== $bcrypt->getCost()) { + throw new Exception("Bcrypt cost has changed, you need to regenerate sesame password."); } - - // Success! - $e->setIdentity($userObject->getId()); - // Update user's password hash if the cost parameter has changed - $this->updateUserPasswordHash($userObject, $credential, $bcrypt); - $this->setSatisfied(true); - $storage = $this->getStorage()->read(); - $storage['identity'] = $e->getIdentity(); - $this->getStorage()->write($storage); - $e->setCode(AuthenticationResult::SUCCESS) - ->setMessages(array('Authentication successful.')); + return $this; } - + /** + * Spécifie les options de config de ce module. + * * @param AuthenticationOptionsInterface $options */ public function setUnicaenAuthOptions(AuthenticationOptionsInterface $options) @@ -93,6 +113,8 @@ class Db extends \ZfcUser\Authentication\Adapter\Db } /** + * Retourne les options de config de ce module. + * * @return AuthenticationOptionsInterface */ public function getUnicaenAuthOptions()