1

Having a bit of trouble getting cakephp to authenticate against a blowfish stored password.

In AppController. Setup global compnents. User Model is CompaniesUser, which corresponds to a file on disk called CompaniesUser.php. Password Hasher is Blowfish

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

class AppController extends Controller {
    public $helpers = array('CustomHtml');
    public $components = array(
        'DebugKit.Toolbar',
        'Session',
            'Auth' => array(
                'loginRedirect' => array(
                    'controller' => 'dashboard',
                    'action' => 'something'
                ),
                'logoutRedirect' => array(
                    'controller' => 'users',
                    'action' => 'login'
                ),
                'authenticate' => array(
                    'Form' => array(
                        'userModel' => 'CompaniesUser',
                        'passwordHasher' => 'Blowfish'
                )
            )
        )
    );

Login CTP:

 <?php
         echo $this->Form->create('User', array('action' => 'login'));
         echo $this->Form->input('username');
         echo $this->Form->input('password');
         echo $this->Form->end('Login');
     ?>

CompaniesUser Model before the Item is saved:

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

The database does indeed appear to have the blowfished password in place.

UsersController.php where the login method lives..

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

class UsersController extends AppController {

    public $uses = array(
        'Company','CompaniesUser'
    );



    public function login() 
    {
        //uses a different theme
        $this->layout = 'admin\login';

        if ($this->request->is('post')) {
            if (  $this->Auth->login() ) 
              return $this->redirect( $this->Auth->redirectUrl() );

            $this->Session->setFlash( __( Configure::read('UsersController.InvalidPassword') ), 'custom\flash' );
        }
    }

public function beforeFilter() 
    {
        parent::beforeFilter();
        $this->Auth->authenticate = array(
            'Basic' => array('userModel' => 'CompaniesUser'),
            'Form' => array('userModel' => 'CompaniesUser')
        );
        // Allow users to register and logout.
        $this->Auth->allow('register', 'logout', 'verify', 'verifyResend', 'verifyAuth');
    }

Cake still refuses to login, and considering $this->Auth->login() is something of a black box, I can't see what SQL output currently looks like. I've tried some of the guidance on using DebugKit, currently reports: Sql Logs

Warning No active database connections. <-- now returning SQL having changed the form name.

Anyone any ideas on things to try?

UPDATE: SQL coming back from the login form looks like this.

SELECT `CompaniesUser`.`id`, `CompaniesUser`.`company_id`, `CompaniesUser`.`name`,    `CompaniesUser`.`username`
  , `CompaniesUser`.`password`, `CompaniesUser`.`active`, `CompaniesUser`.`user_activation_hash`, `CompaniesUser`.`user_password_reset_hash`, `CompaniesUser`.`user_password_reset_timestamp`, `CompaniesUser`.`holidays_allocated`, `CompaniesUser`.`admin`, `CompaniesUser`.`manager`, `CompaniesUser`.`first_run_finished`, `CompaniesUser`.`payment_active`, `Company`.`id`, `Company`.`name`, `Company`.`account_type`, `Company`.`active`, `Company`.`stripe_customer_id`, `Company`.`payment_active` 
FROM `deckchair`.`companies_users` AS `CompaniesUser` 
LEFT JOIN `deckchair`.`companies` AS `Company` 
  ON (`CompaniesUser`.`company_id` = `Company`.`id`) 
WHERE `CompaniesUser`.`username` = 'user@test.com' LIMIT 1
Squiggs.
  • 4,299
  • 6
  • 49
  • 89
  • I believe when you setup the Auth component with the Blowfish hasher, it hashes it automatically for you. Since you're also hashing it in your beforeSave, it's likely trying to login with a hash of your hash. See [the book](http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#using-bcrypt-for-passwords) for details and examples. – Oldskool Dec 23 '14 at 13:33
  • 2
    Why are you using `'userModel' => 'CompaniesUser',` when you got a `$this->Form->create('User')` etc? That doesn't add up. Don't strive from conventions as a beginner. You can do that once you got a grasp of how things work. I would simply stick to a `User` model. Then it all works ouf of the box. – mark Dec 23 '14 at 13:34
  • There are relationships setup between models CompaniesUser is a Child of Company. i.e. belongsTo with foreign keys. This is to gain access to Company elsewhere in my code. I can change my controller name easily enough to match? – Squiggs. Dec 23 '14 at 13:38
  • What Cakephp version are you using? – AgRizzo Dec 23 '14 at 14:29
  • Version 2.5.7 Stable – Squiggs. Dec 23 '14 at 14:35
  • 1
    Couple things to try: (1) `allow` the `login` action in your `beforeFilter`. (2) Change your form name from `User` to `CompaniesUser` – AgRizzo Dec 23 '14 at 15:15
  • Adjusted my form name +1 for that suggestion, the form post variables obviously change name off that. SQL now coming back, and I've traced my way into the PHP core whilst waiting for a reply here. Base Authenticate _findUser $this->_passwordHasher returns object(SimplePasswordHasher), so looks distinctly like my blowfish hash not properly set somewhere at the minute. – Squiggs. Dec 23 '14 at 15:33

2 Answers2

0

I am not too familiar with cake but seeing how your issue seems to be in the db have you tried opening a terminal and outputting the database general_log in real-time?

I can't see what SQL output currently looks like.

For example using mysql you could do something like...

Check to see if your general log is turned on.

SHOW GLOBAL VARIABLES LIKE '%general_log%';

If it is turned off your output will look something like

Variable_name Value                                      
general_log       OFF                                         
general_log_file /var/lib/mysql/something.log    


So you would turn it on like so

SET GLOBAL general_log = 'ON'

Then if you are using Ubuntu for example you will open the log and monitor the output of the database in real-time by using

sudo tail -f -n300 /var/lib/mysql/something.log # same path as general_log_file value from db query

That way you will see exactly what is going on when it happens. This has saved me before. Caveat, be sure to turn this off when you are done debugging.

However if you're getting

Warning No active database connections

everything mentioned above may be a moot point and you would need to suss out issues with your db connection. Maybe try poking around config/app.php.

However there does seem to be an issue with DebugKit if you leave your sql_dump.ctp layout element in your view file as referenced here.

If you have left the sql_dump.ctp layout element in your view file, it will consume the logs before DebugKit renders the toolbar. This doesn't fix the login issues but it could very well help with attaining more information on the issue.

One more thing. Are you working in a windows environment? You have inconsistent slash directions in your UsersController.php file I would opt for all forward slashed but it may not make a difference if you are on a windows server I guess.

trendsetter37
  • 582
  • 8
  • 15
0

After doing some trawling through the Core classes to figure out what was happening I managed to stumble my way into an answer. Base Authenticate line 74 has $settings, which when var_dumped didn't show any signs of the Blowfish setting.

Below sets that. No idea if this is the defacto standard Cake way of doing things, or indeed why specifing blowfish algo in Components array makes no difference, but maybe this will help someone else.

public function beforeFilter() 
{
    parent::beforeFilter();
    $this->Auth->authenticate = array(
        'Form' => array('userModel' => 'CompaniesUser','passwordHasher' => 'Blowfish')
    );

    // Allow users to register and logout.
    $this->Auth->allow('register', 'logout', 'verify', 'verifyResend', 'verifyAuth', 'login');
}
Squiggs.
  • 4,299
  • 6
  • 49
  • 89
  • I see the mistake at `$this->Auth->allow('logout')` because when user hasn't authenticated, therefore unauthenticated user no need logout. – Vy Do Dec 24 '14 at 16:07