mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-05 07:31:34 +08:00
Option Security::passwordHashStrategy added
This commit is contained in:
@ -58,10 +58,18 @@ class Security extends Component
|
|||||||
/**
|
/**
|
||||||
* @var string strategy, which should be used to derive a key for encryption.
|
* @var string strategy, which should be used to derive a key for encryption.
|
||||||
* Available strategies:
|
* Available strategies:
|
||||||
* - 'pbkdf2' - PBKDF2 key derivation, this option is recommended, but it requires PHP version >= 5.5.0
|
* - 'pbkdf2' - PBKDF2 key derivation. This option is recommended, but it requires PHP version >= 5.5.0
|
||||||
* - 'hmac' - HMAC hash key derivation.
|
* - 'hmac' - HMAC hash key derivation.
|
||||||
*/
|
*/
|
||||||
public $deriveKeyStrategy = 'hmac';
|
public $deriveKeyStrategy = 'hmac';
|
||||||
|
/**
|
||||||
|
* @var string strategy, which should be used to generate password hash.
|
||||||
|
* Available strategies:
|
||||||
|
* - 'password_hash' - use of PHP `password_hash()` function with PASSWORD_DEFAULT algorithm. This option is recommended,
|
||||||
|
* but it requires PHP version >= 5.5.0
|
||||||
|
* - 'crypt' - use PHP `crypt()` function.
|
||||||
|
*/
|
||||||
|
public $passwordHashStrategy = 'crypt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts data.
|
* Encrypts data.
|
||||||
@ -154,7 +162,7 @@ class Security extends Component
|
|||||||
case 'hmac':
|
case 'hmac':
|
||||||
return $this->deriveKeyHmac($password, $salt);
|
return $this->deriveKeyHmac($password, $salt);
|
||||||
default:
|
default:
|
||||||
throw new InvalidConfigException("Unknown Derive key strategy '{$this->deriveKeyStrategy}'");
|
throw new InvalidConfigException("Unknown derive key strategy '{$this->deriveKeyStrategy}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,14 +343,23 @@ class Security extends Component
|
|||||||
*/
|
*/
|
||||||
public function generatePasswordHash($password, $cost = 13)
|
public function generatePasswordHash($password, $cost = 13)
|
||||||
{
|
{
|
||||||
|
switch ($this->passwordHashStrategy) {
|
||||||
|
case 'password_hash':
|
||||||
|
if (!function_exists('password_hash')) {
|
||||||
|
throw new InvalidConfigException('Password hash key strategy "password_hash" requires PHP >= 5.5.0, either upgrade your environment or use another strategy.');
|
||||||
|
}
|
||||||
|
return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
|
||||||
|
case 'crypt':
|
||||||
$salt = $this->generateSalt($cost);
|
$salt = $this->generateSalt($cost);
|
||||||
$hash = crypt($password, $salt);
|
$hash = crypt($password, $salt);
|
||||||
|
|
||||||
if (!is_string($hash) || strlen($hash) < 32) {
|
if (!is_string($hash) || strlen($hash) < 32) {
|
||||||
throw new Exception('Unknown error occurred while generating hash.');
|
throw new Exception('Unknown error occurred while generating hash.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hash;
|
return $hash;
|
||||||
|
default:
|
||||||
|
throw new InvalidConfigException("Unknown password hash strategy '{$this->passwordHashStrategy}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -351,6 +368,7 @@ class Security extends Component
|
|||||||
* @param string $hash The hash to verify the password against.
|
* @param string $hash The hash to verify the password against.
|
||||||
* @return boolean whether the password is correct.
|
* @return boolean whether the password is correct.
|
||||||
* @throws InvalidParamException on bad password or hash parameters or if crypt() with Blowfish hash is not available.
|
* @throws InvalidParamException on bad password or hash parameters or if crypt() with Blowfish hash is not available.
|
||||||
|
* @throws InvalidConfigException on unsupported password hash strategy is configured.
|
||||||
* @see generatePasswordHash()
|
* @see generatePasswordHash()
|
||||||
*/
|
*/
|
||||||
public function validatePassword($password, $hash)
|
public function validatePassword($password, $hash)
|
||||||
@ -363,13 +381,22 @@ class Security extends Component
|
|||||||
throw new InvalidParamException('Hash is invalid.');
|
throw new InvalidParamException('Hash is invalid.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ($this->passwordHashStrategy) {
|
||||||
|
case 'password_hash':
|
||||||
|
if (!function_exists('password_verify')) {
|
||||||
|
throw new InvalidConfigException('Password hash key strategy "password_hash" requires PHP >= 5.5.0, either upgrade your environment or use another strategy.');
|
||||||
|
}
|
||||||
|
return password_verify($password, $hash);
|
||||||
|
case 'crypt':
|
||||||
$test = crypt($password, $hash);
|
$test = crypt($password, $hash);
|
||||||
$n = strlen($test);
|
$n = strlen($test);
|
||||||
if ($n < 32 || $n !== strlen($hash)) {
|
if ($n < 32 || $n !== strlen($hash)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->compareString($test, $hash);
|
return $this->compareString($test, $hash);
|
||||||
|
default:
|
||||||
|
throw new InvalidConfigException("Unknown password hash strategy '{$this->passwordHashStrategy}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -29,14 +29,6 @@ class SecurityTest extends TestCase
|
|||||||
|
|
||||||
// Tests :
|
// Tests :
|
||||||
|
|
||||||
public function testPasswordHash()
|
|
||||||
{
|
|
||||||
$password = 'secret';
|
|
||||||
$hash = $this->security->generatePasswordHash($password);
|
|
||||||
$this->assertTrue($this->security->validatePassword($password, $hash));
|
|
||||||
$this->assertFalse($this->security->validatePassword('test', $hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHashData()
|
public function testHashData()
|
||||||
{
|
{
|
||||||
$data = 'known data';
|
$data = 'known data';
|
||||||
@ -48,6 +40,40 @@ class SecurityTest extends TestCase
|
|||||||
$this->assertFalse($this->security->validateData($hashedData, $key));
|
$this->assertFalse($this->security->validateData($hashedData, $key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function dataProviderPasswordHash()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'crypt',
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'password_hash',
|
||||||
|
!function_exists('password_hash')
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataProviderPasswordHash
|
||||||
|
*
|
||||||
|
* @param string $passwordHashStrategy
|
||||||
|
* @param boolean $isSkipped
|
||||||
|
*/
|
||||||
|
public function testPasswordHash($passwordHashStrategy, $isSkipped)
|
||||||
|
{
|
||||||
|
if ($isSkipped) {
|
||||||
|
$this->markTestSkipped("Unable to test '{$passwordHashStrategy}' password hash strategy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->security->passwordHashStrategy = $passwordHashStrategy;
|
||||||
|
|
||||||
|
$password = 'secret';
|
||||||
|
$hash = $this->security->generatePasswordHash($password);
|
||||||
|
$this->assertTrue($this->security->validatePassword($password, $hash));
|
||||||
|
$this->assertFalse($this->security->validatePassword('test', $hash));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data provider for [[testEncrypt()]]
|
* Data provider for [[testEncrypt()]]
|
||||||
* @return array test data
|
* @return array test data
|
||||||
|
|||||||
Reference in New Issue
Block a user