I'm building a laravel app using Sentinel, based in an old system code in Yii.
Purpose is be able to login in new system with old users / old db.
I first has to resolved model issue:
Custom Model and fields with Sentinel / Laravel
Now, it is ok.
I have a last issue, it seems to be hashing password from different ways.
When I check the hash method in Yii, I can find that it use Blowfish algorithm:
/**
* CPasswordHelper provides a simple API for secure password hashing and verification.
*
* CPasswordHelper uses the Blowfish hash algorithm available in many PHP runtime
* environments through the PHP {@link http://php.net/manual/en/function.crypt.php crypt()}
* built-in function. As of Dec 2012 it is the strongest algorithm available in PHP
* and the only algorithm without some security concerns surrounding it. For this reason,
* CPasswordHelper fails to initialize when run in and environment that does not have
* crypt() and its Blowfish option. Systems with the option include:
* (1) Most *nix systems since PHP 4 (the algorithm is part of the library function crypt(3));
* (2) All PHP systems since 5.3.0; (3) All PHP systems with the
* {@link http://www.hardened-php.net/suhosin/ Suhosin patch}.
* For more information about password hashing, crypt() and Blowfish, please read
* the Yii Wiki article
* {@link http://www.yiiframework.com/wiki/425/use-crypt-for-password-storage/ Use crypt() for password storage}.
* and the
* PHP RFC {@link http://wiki.php.net/rfc/password_hash Adding simple password hashing API}.
*
* CPasswordHelper throws an exception if the Blowfish hash algorithm is not
* available in the runtime PHP's crypt() function. It can be used as follows
*
In the other hand, Sentinel manage several hash methods:
Native hasher
Bcrypt hasher
Callback hasher
Whirlpool hasher
SHA256 hasher
So, I guessed the common method was bcrypt, and in my Laravel model I did:
class Administrador extends EloquentUser {
protected $table = 'administrador';
protected $fillable = [];
protected $primaryKey = 'administradorid';
protected $loginNames = ['correo'];
protected $guarded = ['administradorid'];
protected $hidden = ['contrasena', 'remember_token'];
use SoftDeletes;
protected $dates = ['deleted_at'];
/**
* Set the Sentry User Model Hasher to be the same as the configured Sentry Hasher
*/
public static function boot()
{
parent::boot();
Sentinel::setHasher(new BcryptHasher);
}
}
So really, I don't really know what to do to solve it....
What you can do to support both systems at this time is create an implementation of the Cartalyst\Sentinal\Hashing\HasherInterface
like this for example:
use Cartalyst\Sentinel\Hashing\HasherInterface;
class CombinedHasher implements HasherInterface
{
/**
* @var HasherInterface
*/
private $primary;
/**
* @var HasherInterface
*/
private $fallback;
/**
* @param HasherInterface $primary
* @param HasherInterface $fallback
*/
public function __construct(HasherInterface $primary, HasherInterface $fallback)
{
$this->primary = $primary;
$this->fallback = $fallback;
}
/**
* Hash the given value.
*
* @param string $value
* @return string
* @throws \RuntimeException
*/
public function hash($value)
{
return $this->primary->hash($value);
}
/**
* Checks the string against the hashed value.
*
* @param string $value
* @param string $hashedValue
* @return bool
*/
public function check($value, $hashedValue)
{
if ($this->primary->check($value, $hashedValue)) {
return true;
}
return $this->fallback->check($value, $hashedValue);
}
}
As you can see it takes two instances of the HasherInterface
. So in this case you would inject the new implementation you want you use first and then create an implementation of the interface which implements the hashing algorithm Yii is using.
While checking the hash it will first use the new hashing algorithm. If this returns false
it will also check using the fallback (Yii algorithm). To create hashes it will only use the new hashing algorithm. (You might want to change this for development however you should not develop using the production database anyways.)
So what you have to do next is create an implementation of the HasherInterface
which will use the hashing algorithm Yii is using:
use Cartalyst\Sentinel\Hashing\HasherInterface;
class YiiHasher implements HasherInterface
{
/**
* Hash the given value.
*
* @param string $value
* @return string
* @throws \RuntimeException
*/
public function hash($value)
{
// You'll have to implement this
return yiiHasher($value);
}
/**
* Checks the string against the hashed value.
*
* @param string $value
* @param string $hashedValue
* @return bool
*/
public function check($value, $hashedValue)
{
// You'll have to implement this
return yiiHashChecker($value, $hashedValue);
}
}
You'll have to check whether Yii has a package for this or you'll have to check their source code to see how it works.
So to use this you would create an instance of the CombinedHasher
like this:
use Cartalyst\Sentinel\Hashing\BcryptHasher;
use Namespace\For\Your\YiiHasher;
$primary = new BcryptHasher();
$fallback = new YiiHasher();
$hasher = new CombinedHasher($primary, $fallback);
Update 1: Extra info from the documentation
After actually reading through their documentation I noticed they also provide a CallbackHasher
which might be less work to set up: https://cartalyst.com/manual/sentinel/2.0#callback-hasher
They also recommend using the NativeHasher
over the BcryptHasher
: https://cartalyst.com/manual/sentinel/2.0#native-hasher
Update 2: Where to set up
You could for example create them in app/Hashing
. Then you'd have to make sure they have the namespace App\Hashing
.
To set this up you can use your AppServiceProvider
which is located in app/Providers/AppServiceProvider.php
.
// Import the classes on the top
use App\Hashing\CombinedHasher;
use App\Hashing\YiiHasher;
use Cartalyst\Sentinel\Hashing\NativeHasher;
// In the AppServiceProvider class itself
public function boot()
{
$hasher = $this->app['Cartalyst\Sentinel\Hashing\HasherInterface'];
Sentinel::setHasher($hasher);
}
public function register()
{
$this->app->singleton('Cartalyst\Sentinel\Hashing\HasherInterface', function($app) {
$primary = new NativeHasher();
$secondary = new YiiHasher();
return new CombinedHasher($primary, $secondary);
});
}