Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Bcrypt Strategy For New Application #10

Closed
Saraylu opened this issue Mar 30, 2013 · 6 comments
Closed

Using Bcrypt Strategy For New Application #10

Saraylu opened this issue Mar 30, 2013 · 6 comments

Comments

@Saraylu
Copy link

Saraylu commented Mar 30, 2013

How to use Bcrypt strategy in new application?

This extension is useful, but i didn't still use it.
I open a topic on Stackoverflow:
http://stackoverflow.com/questions/15714387/yiipassword-extension-usage

I very tried any way, i want now you how to use this extension for your application? Mainly encode the user password and verify it at user-login.

@githubjeka
Copy link
Collaborator

To understand how it works you need to understand how to work with the behaviors and read a thread Authorization.
http://www.yiiframework.com/doc/guide/1.1/en/basics.component#component-behavior
http://www.yiiframework.com/doc/guide/1.1/en/topics.auth

Let's see the my implementation here - https://github.com/airily/skeletonYiiApp/blob/master/protected/common/modules/users/models/User.php

YiiPassword extension extracted into https://github.com/airily/skeletonYiiApp/tree/master/protected/common/modules/users/extensions/behaviors
(alias - users.extensions.behaviors)

in behaviors

public function behaviors() {
$pathToBehaviors = 'users.extensions.behaviors.';
        \Yii::import($pathToBehaviors . 'password.*');
        
        return array(           
            // Password behavior strategy
            'APasswordBehavior' => array(
                'class' => 'APasswordBehavior',
                'defaultStrategyName' => 'bcrypt',
                'strategies' => array(
                    'bcrypt' => array(
                        'class' => 'ABcryptPasswordStrategy',
                        'minLength' => 8,
                    ),
                ),
            )
        );
}

in rules

$passStrategy = get_class($this->getStrategy());
array('newPassword', $passStrategy, 'minLength' => $this->getStrategy()->minLength)
array('newPassword', $passStrategy, 'minLength' => $this->getStrategy()->minLength, 'on' => 'changePassword, register'),

The password for authentication here - https://github.com/airily/skeletonYiiApp/blob/master/protected/common/modules/users/components/UserIdentityComponent.php

public function authenticate()
    {
        $user = User::model()->findByAttributes(array('username' => $this->username));
        if ($user->verifyPassword($this->password)) {
            $this->_id = $user->id;
            return true;
        }
        $this->errorsValidation = $user->getErrors();
        return false;
    }

There is another implementation (from YiiBoilerplate) - https://github.com/clevertech/YiiBoilerplate/blob/master/common/models/User.php

In a short time, update the file Readme. There will be a section as set behavior.

@Saraylu
Copy link
Author

Saraylu commented Mar 30, 2013

ABcryptPasswordStrategyTest.php:

<?php
Yii::import("application.components.passwordStrategy.*");
Yii::import("application.models.*");

/**
 * Tests for the {@link ABcryptPasswordStrategy} class.
 * @author Charles Pick
 * @package packages.passwordStrategy
 */
class ABcryptPasswordStrategyTest extends CTestCase
{
    public function testEncode()
    {
        $user=User::model()->findByAttributes(array('username'=>'user'));
        $strategy = new ABcryptPasswordStrategy();
        $strategy->getSalt(true);

        $password = $strategy->encode("pass");
        $user->password = $password;
        $user->save();

        $this->assertTrue($user->verifyPassword("pass"));
    }
}

Result:

PHPUnit 3.7.1 by Sebastian Bergmann.

Configuration read from C:\Apache2\htdocs\x\protected\tests\phpunit.xml

F

Time: 3 seconds, Memory: 8.25Mb

There was 1 failure:

1) ABcryptPasswordStrategyTest::testEncode
Failed asserting that false is true.

C:\Apache2\htdocs\x\protected\tests\unit\ABcryptPasswordStrategyTest.php:22
C:\php\phpunit:46

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Why don't verify?

@githubjeka
Copy link
Collaborator

Why don't verify? There are two reasons.

public function verifyPassword($password)
    {
        $owner = $this->getOwner(); /* @var CActiveRecord $owner */
        $strategy = $this->getStrategy();
        if ($strategy === false) {
            return false; // no strategy
        }
        if ($this->saltAttribute) {
            $strategy->setSalt($owner->{$this->saltAttribute});
        }
        if (!$strategy->compare($password,$owner->{$this->passwordAttribute})) {
            return false;
        }
        if ($this->autoUpgrade && $strategy->name != $this->defaultStrategyName) {
            if (!$this->changePassword($password,!$strategy->canUpgradeTo($this->getDefaultStrategy()))) {
                // couldn't upgrade their password, so ask them for a new password
                $owner->saveAttributes(array(
                    $this->requireNewPasswordAttribute => true
                ));
            }
        }
        return true;
    }
  1. if ($strategy === false) {
  2. $strategy->compare($password,$owner->{$this->passwordAttribute}) === false

@Saraylu
Copy link
Author

Saraylu commented Mar 31, 2013

Very excuseme, following is attributes values:

Array
(
    [id] => 6
    [username] => user
    [password] => $2a$08$DJokJdw6d2NKA64oDeMniuqMivglw//v2aV07jz4NY/rklN.mbp6C
    [email] => test@yahoo.com
    [name] => thomas
    [family] => mat
    [address] => England
    [telephone] => 754327453287
    [mobile] => 78324534
    [website] => www.blog.com
    [salt] => $2a$08$DJokJdw6d2NKA64oDeMniw
    [passwordStrategy] => bcrypt
    [requiresNewPassword] =>
)

I very well know you responded all my questions and also i very tried, however you have no idea after have seen the attributes values?
Each time the test runs, the values ​​of these attributes will change.(password and salt)
Very Thanks

@githubjeka
Copy link
Collaborator

every time you do $user->save(); the following code in https://github.com/phpnode/YiiPassword/blob/master/APasswordBehavior.php

public function beforeSave($event)
    {
        $password = $event->sender->{$this->passwordAttribute};
        if ($password != $this->_hashedPassword && $password != "") {
            $this->changePasswordInternal($password);
        }
        elseif ($password == "" && $this->_hashedPassword != "") {
            $event->sender->{$this->passwordAttribute} = $this->_hashedPassword;
        }
    }

In $this->changePasswordInternal($password);

$owner->{$this->passwordAttribute} = $strategy->encode($password);

So code

($strategy->compare($password,$owner->{$this->passwordAttribute}))

will always return false, since you are using $password = $strategy->encode("pass"); once before.

@Saraylu
Copy link
Author

Saraylu commented Mar 31, 2013

SOLVED, Very Thanks.
The following test successfully done, ABcryptPasswordStrategyTest.php :

<?php
Yii::import("application.components.passwordStrategy.*");
Yii::import("application.models.*");

/**
 * Tests for the {@link ABcryptPasswordStrategy} class.
 * @author Charles Pick
 * @package packages.passwordStrategy
 */
class ABcryptPasswordStrategyTest extends CTestCase
{
    public function testEncode()
    {
        $user=User::model()->findByAttributes(array('username'=>'user'));
        $strategy = new ABcryptPasswordStrategy();
        $strategy->getSalt(true);

        $user->password = 'pass';
        $user->save();

        $this->assertTrue($user->verifyPassword("pass"));
    }
}

@Saraylu Saraylu closed this as completed Mar 31, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants