4

Google doesn't have much of a solution (similar question but no answer).

Because bcrypt generates a new hash each time, the authentication fails. I've looked into the code (perhaps extend class myself) but it's pretty messy (would prefer a native solution). How can I use the $bcrpt->verify() with $identity->isValid()?

Edit: For now, I've subclassed the authentication DbTable class, and it's working, but I highly doubt it's optimized/"fully right". Still looking for an "elegant" solution.

Code Lღver
  • 15,573
  • 16
  • 56
  • 75
Raekye
  • 5,081
  • 8
  • 49
  • 74
  • 1
    It's indeed a pitty that ZF2 has a Bcrypt wrapper but doesn't provide a Brypt auth adapter. – markus Jan 06 '13 at 11:41

3 Answers3

15

You can use:

Zend\Authentication\Adapter\DbTable\CallbackCheckAdapter

Like this :

use Zend\Authentication\Adapter\DbTable\CallbackCheckAdapter as AuthAdapter;
use Zend\Crypt\Password\Bcrypt;    

$credentialValidationCallback = function($dbCredential, $requestCredential) {
    return (new Bcrypt())->verify($requestCredential, $dbCredential);
};
$authAdapter = new AuthAdapter($dbAdapter, 'user', 'login', 'password', $credentialValidationCallback);
// ...
B.Asselin
  • 978
  • 10
  • 19
4

As you should know, BCrypt hashes using a salt. And that salt is generated again randomly each time. That drastically increases the hardness of finding all passwords if your database is compromised. Thus, indeed, it will generate a new hash each time.

My own solution for the problem that you were having, is having my own Zend\Authentication adapter, that would retrieve a user model from the database (using the username/email), and then calling $user->checkPassword($credential);. That method would get an instance of Zend\Crypt\Password\Bcrypt. Which would simply call $bcrypt->verify() on the given password, and the hash in the user model.

kokx
  • 1,706
  • 13
  • 19
1

I've done it like this (test code and it works)..;

if ($request->isPost()) {
            $form->setData($request->getPost());
            if ($form->isValid()) {

                $bcrypt = new Bcrypt();
                $user   = new User();
                $user->exchangeArray($form->getData());

                $password    = $user->password;
                $data        = $this->getUserTable()->selectUser($user->username);

                if (!$data)
                {
                    echo 'user not found';
                } else {

                    if ($bcrypt->verify($password, $data->hash)) {

                    $sm          = $this->getServiceLocator();
                    $dbAdapter   = $sm->get('Zend\Db\Adapter\Adapter');
                    $authAdapter = new AuthAdapter(
                                            $dbAdapter,
                                            'cms_users',
                                            'username',
                                            'hash'
                                        );
                    $authAdapter->setIdentity($user->username)
                                ->setCredential($data->hash);                           

                    $result = $auth->authenticate($authAdapter);
                    echo $result->getIdentity() . "\n\n";
                    // do you thing on succes/failure


                    } else {
                    echo 'invalid password';
                    }
                }
            }
        }
directory
  • 3,093
  • 8
  • 45
  • 85
  • First of all you are doing an extra DB call, check the user entered password with the hash from the first DB call, then use the hash from the first DB call to authenticate with hash which is in DB using 2nd DB call. This will work but it is not the right way. I think the solution that @bigBen provided is the correct way. – Evren Yurtesen Mar 23 '16 at 14:05