Commit 052ae833 by Paul Klimov

Option `Security::autoGenerateSecretKey` added

parent 25a36377
...@@ -87,6 +87,7 @@ Upgrade from Yii 2.0 Beta ...@@ -87,6 +87,7 @@ Upgrade from Yii 2.0 Beta
'deriveKeyStrategy' => 'hmac', // for PHP version < 5.5.0 'deriveKeyStrategy' => 'hmac', // for PHP version < 5.5.0
//'deriveKeyStrategy' => 'pbkdf2', // for PHP version >= 5.5.0 //'deriveKeyStrategy' => 'pbkdf2', // for PHP version >= 5.5.0
'useDeriveKeyUniqueSalt' => false, 'useDeriveKeyUniqueSalt' => false,
'autoGenerateSecretKey' => true,
], ],
// ... // ...
], ],
......
...@@ -82,6 +82,20 @@ class Security extends Component ...@@ -82,6 +82,20 @@ class Security extends Component
* If disabled this option reduces encrypted text length, but also reduces security. * If disabled this option reduces encrypted text length, but also reduces security.
*/ */
public $useDeriveKeyUniqueSalt = true; public $useDeriveKeyUniqueSalt = true;
/**
* @var array list of predefined secret keys in format: keyVerboseName => keyValue
* While retrieving secret keys [[getSecretKey()]] method usage is recommended.
*/
public $secretKeys = [];
/**
* @var boolean whether to automatically generate secret key, if it is missing at [[secretKeys]] list
* while being requested via [[getSecretKey()]].
* Usage of this feature is not recommended - it is better to explicitly define list of secret keys.
* However, you may enable this option while project is in development stage to simplify generating of the keys
* list for the future explicit configuration.
* Generated keys can be found under 'runtime' application directory in 'keys.json' file.
*/
public $autoGenerateSecretKey = false;
/** /**
* Encrypts data. * Encrypts data.
...@@ -273,29 +287,31 @@ class Security extends Component ...@@ -273,29 +287,31 @@ class Security extends Component
/** /**
* Returns a secret key associated with the specified name. * Returns a secret key associated with the specified name.
* If the secret key does not exist, a random key will be generated * If the secret key does not exist and [[autoGenerateSecretKey]] enabled,
* and saved in the file "keys.json" under the application's runtime directory * a random key will be generated and saved in the file "keys.json" under the application's runtime
* so that the same secret key can be returned in future requests. * directory so that the same secret key can be returned in future requests.
* @param string $name the name that is associated with the secret key * @param string $name the name that is associated with the secret key
* @param integer $length the length of the key that should be generated if not exists * @param integer $length the length of the key that should be generated if not exists
* @throws InvalidParamException if secret key not exist and its generation is not allowed
* @return string the secret key associated with the specified name * @return string the secret key associated with the specified name
*/ */
public function getSecretKey($name, $length = 32) public function getSecretKey($name, $length = 32)
{ {
static $keys; if (!array_key_exists($name, $this->secretKeys)) {
if (!$this->autoGenerateSecretKey) {
throw new InvalidParamException("Unknown secret key '{$name}'");
}
$keyFile = Yii::$app->getRuntimePath() . '/keys.json'; $keyFile = Yii::$app->getRuntimePath() . '/keys.json';
if ($keys === null) {
$keys = [];
if (is_file($keyFile)) { if (is_file($keyFile)) {
$keys = json_decode(file_get_contents($keyFile), true); $keys = json_decode(file_get_contents($keyFile), true);
$this->secretKeys = array_merge($keys, $this->secretKeys);
} }
if (!isset($this->secretKeys[$name])) {
$this->secretKeys[$name] = $this->generateRandomKey($length);
file_put_contents($keyFile, json_encode($this->secretKeys));
} }
if (!isset($keys[$name])) {
$keys[$name] = $this->generateRandomKey($length);
file_put_contents($keyFile, json_encode($keys));
} }
return $this->secretKeys[$name];
return $keys[$name];
} }
/** /**
......
...@@ -40,6 +40,10 @@ class SecurityTest extends TestCase ...@@ -40,6 +40,10 @@ class SecurityTest extends TestCase
$this->assertFalse($this->security->validateData($hashedData, $key)); $this->assertFalse($this->security->validateData($hashedData, $key));
} }
/**
* Data provider for [[testPasswordHash()]]
* @return array test data
*/
public function dataProviderPasswordHash() public function dataProviderPasswordHash()
{ {
return [ return [
...@@ -127,4 +131,25 @@ class SecurityTest extends TestCase ...@@ -127,4 +131,25 @@ class SecurityTest extends TestCase
$decryptedData = $this->security->decrypt($encryptedData, $key); $decryptedData = $this->security->decrypt($encryptedData, $key);
$this->assertEquals($data, $decryptedData); $this->assertEquals($data, $decryptedData);
} }
public function testGetSecretKey()
{
$this->security->autoGenerateSecretKey = false;
$keyName = 'testGet';
$keyValue = 'testGetValue';
$this->security->secretKeys = [
$keyName => $keyValue
];
$this->assertEquals($keyValue, $this->security->getSecretKey($keyName));
$this->setExpectedException('yii\base\InvalidParamException');
$this->security->getSecretKey('notExistingKey');
}
/*public function testGenerateSecretKey()
{
$this->security->autoGenerateSecretKey = true;
$keyValue = $this->security->getSecretKey('test');
$this->assertNotEmpty($keyValue);
}*/
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment