3
votes

I'm using CakePHP 2.8.5. It's not letting me log in "Username or password is incorrect". This seems totally straightforward in the docs but it isn't working for me. I wonder if my model/data structure might be confusing CakePHP. I have a Users model, but the logins are associated with an Admins model. The login form and action are in the Pages model (it has forms for multiple models).

in AppController:

public $components = array(
    'DebugKit.Toolbar',
    'Flash',
    'Session',
    'Auth' => array(
        'userModel' => 'Admin',
        'authenticate' => array(
            'Form' => array(
                'fields' => array(
                    'username' => 'email',
                    'password' => 'password'
                ),
                'passwordHasher' => 'Blowfish'
            )
        ),
        'loginAction' => array(
            'controller' => 'pages',
            'action' => 'login',
        ),
        'logoutRedirect' => array(
            'controller' => 'pages',
            'action' => 'login',
        ),
        'authError' => 'Please log in',
        'authorize' => array('Controller')
    )
);

My login view, in /View/Pages. "email" is the username field:

<?php
echo $this->Form->create('Admin'); 
echo $this->Form->input('email'); 
echo $this->Form->input('password'); 
echo $this->Form->end('Submit'); 
?>

PagesController:

public function login() {

    if ($this->request->is('post')) {
        if ($this->Auth->login()) {
            return $this->redirect($this->Auth->redirect());
        } else {
            $this->Flash->error(__('Username or password is incorrect'));
        }
    }}

Top of Admin model:

App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');

Automatic Blowfish encryption in Admin model:

public function beforeSave($options = array()) {
    if (isset($this->data['Admin']['password'])) {
        $passwordHasher = new BlowfishPasswordHasher();
        $this->data['Admin']['password'] = $passwordHasher->hash(
            $this->data['Admin']['password']
        );
    }
    return true;
}

I notice if I enter the same password for different Admins, I get a different encryption result, but I've read that's normal.

If you want to see anything else, I'll add it.

1
"I notice if I enter the same password for different Admins, I get a different encryption result, but I've read that's normal." That's not normal. The same password should generate the same hash. That's kind of the whole point of the hash/compare. If they weren't the same, you couldn't compare. - Dave
That's what it seemed like to me, but then I read this Q-A: stackoverflow.com/questions/22667478/… - Bonjiro
I'm not sure what they're talking about, but it seems bassakwards to me. How could you possibly compare a password if its hash changes every time. I use cake every day all day, and have never had this issue. There must be something going on. I also know that it's the same, because when I manually generate a user, I sometimes copy/paste an existing hash into the new person's password field, and the previous password works fine. (yes, not pretty, but w/e) :) - Dave
The same password should generate the same hash @Dave this is completely false when applied to blowfish. Here's some random online tool to demonstrate. Also a useful reference php.net/manual/en/… - note that the hash of a password contains the salt to verify that the hash is correct. - AD7six
@AD7six - I certainly bow to your expertise on this one (not sarcastic). I thought my logic was sound, but apparently there's a gap in it. How can I copy/paste a hashed password field from one user to the next and have the same password function correctly for both? Or for that matter, how does it compare my password when typed in against the one in the database if it hashes differently every time? - Dave

1 Answers

2
votes

The userModel key is in the wrong place

Compare the config in the question:

public $components = array(
    'DebugKit.Toolbar',
    'Flash',
    'Session',
    'Auth' => array(
        'userModel' => 'Admin',
        'authenticate' => array(
            'Form' => array(
                'fields' => array(
                    'username' => 'email',
                    'password' => 'password'
                ),
                'passwordHasher' => 'Blowfish'
            )
        ),

To the config in the docs:

$this->Auth->authenticate = array(
    'Basic' => array('userModel' => 'Member'),
    'Form' => array('userModel' => 'Member')
);

In the question userModel is a top-level key, in the docs it is part of the individual authenticate keys. Looking at the api examples (or the doc blocks in the source code) the error is more clear:

... you can define settings that should be set to all authentications objects using the 'all' key:

$this->Auth->authenticate = array(
    'all' => array(
        'userModel' => 'Users.User',
        'scope' => array('User.active' => 1)
    ),
    'Form',
    'Basic'
);

It is possible to define a global userModel for all authenticate objects to use, but the syntax is simply different than the question.

Use the all key

Therefore to define a user model to use for all authenticate options, use the all key:

public $components = array(
    'DebugKit.Toolbar',
    'Flash',
    'Session',
    'Auth' => array(
        //'userModel' => 'Admin', // <- no
        'authenticate' => array(
            'all' => array(
                'userModel' => 'Admin' // <- yes
            ),
            'Form' => array(
                'fields' => array(
                    'username' => 'email',
                    'password' => 'password'
                ),
                'passwordHasher' => 'Blowfish'
            )
        ),