mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENHANCEMENT: Implement blowfish encryption and use it by default. (#7111)
This commit is contained in:
parent
2288d80c30
commit
fa60f9e8b2
@ -11,4 +11,6 @@ PasswordEncryptor:
|
|||||||
md5_v2.4:
|
md5_v2.4:
|
||||||
PasswordEncryptor_PHPHash: md5
|
PasswordEncryptor_PHPHash: md5
|
||||||
sha1_v2.4:
|
sha1_v2.4:
|
||||||
PasswordEncryptor_PHPHash: sha1
|
PasswordEncryptor_PHPHash: sha1
|
||||||
|
blowfish:
|
||||||
|
PasswordEncryptor_Blowfish:
|
@ -33,6 +33,8 @@ class SS_Backtrace {
|
|||||||
array('PasswordEncryptor_MySQLPassword', 'salt'),
|
array('PasswordEncryptor_MySQLPassword', 'salt'),
|
||||||
array('PasswordEncryptor_MySQLOldPassword', 'encrypt'),
|
array('PasswordEncryptor_MySQLOldPassword', 'encrypt'),
|
||||||
array('PasswordEncryptor_MySQLOldPassword', 'salt'),
|
array('PasswordEncryptor_MySQLOldPassword', 'salt'),
|
||||||
|
array('PasswordEncryptor_Blowfish', 'encrypt'),
|
||||||
|
array('PasswordEncryptor_Blowfish', 'salt'),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,7 +116,44 @@ abstract class PasswordEncryptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the default class used for built-in hash types in PHP.
|
* Blowfish encryption - this is the default from SilverStripe 3.
|
||||||
|
* PHP 5.3+ will provide a php implementation if there is no system
|
||||||
|
* version available.
|
||||||
|
*
|
||||||
|
* @package framework
|
||||||
|
* @subpackage security
|
||||||
|
*/
|
||||||
|
class PasswordEncryptor_Blowfish extends PasswordEncryptor {
|
||||||
|
/**
|
||||||
|
* Cost of encryption.
|
||||||
|
* Higher costs will increase security, but also increase server load.
|
||||||
|
* If you are using basic auth, you may need to decrease this as encryption
|
||||||
|
* will be run on every request.
|
||||||
|
* Must be between 4 and 31.
|
||||||
|
*/
|
||||||
|
protected static $cost = 10;
|
||||||
|
|
||||||
|
function encrypt($password, $salt = null, $member = null) {
|
||||||
|
$method_and_salt = '$2y$' . $salt;
|
||||||
|
$encrypted_password = crypt($password, $method_and_salt);
|
||||||
|
// We *never* want to generate blank passwords. If something
|
||||||
|
// goes wrong, throw an exception.
|
||||||
|
if(strpos($encrypted_password, $method_and_salt) === false)
|
||||||
|
throw new PasswordEncryptor_EncryptionFailed('Blowfish password encryption failed.');
|
||||||
|
|
||||||
|
// Remove the method and salt from the password, as the salt
|
||||||
|
// is stored in a separate column.
|
||||||
|
return substr($encrypted_password, strlen($method_and_salt));
|
||||||
|
}
|
||||||
|
|
||||||
|
function salt($password, $memeber = null) {
|
||||||
|
$generator = new RandomGenerator();
|
||||||
|
return self::$cost . '$' . substr($generator->generateHash('sha1'), 0, 21);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encryption using built-in hash types in PHP.
|
||||||
* Please note that the implemented algorithms depend on the PHP
|
* Please note that the implemented algorithms depend on the PHP
|
||||||
* distribution and architecture.
|
* distribution and architecture.
|
||||||
*
|
*
|
||||||
@ -240,3 +277,9 @@ class PasswordEncryptor_None extends PasswordEncryptor {
|
|||||||
* @subpackage security
|
* @subpackage security
|
||||||
*/
|
*/
|
||||||
class PasswordEncryptor_NotFoundException extends Exception {}
|
class PasswordEncryptor_NotFoundException extends Exception {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package framework
|
||||||
|
* @subpackage security
|
||||||
|
*/
|
||||||
|
class PasswordEncryptor_EncryptionFailed extends Exception {}
|
||||||
|
@ -50,7 +50,7 @@ class Security extends Controller {
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected static $encryptionAlgorithm = 'sha1_v2.4';
|
protected static $encryptionAlgorithm = 'blowfish';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Showing "Remember me"-checkbox
|
* Showing "Remember me"-checkbox
|
||||||
|
@ -44,13 +44,13 @@ class PasswordEncryptorTest extends SapphireTest {
|
|||||||
$this->assertNotContains('test', array_keys(PasswordEncryptor::get_encryptors()));
|
$this->assertNotContains('test', array_keys(PasswordEncryptor::get_encryptors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testEncrytorPHPHashWithArguments() {
|
function testEncryptorPHPHashWithArguments() {
|
||||||
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_md5'=>array('PasswordEncryptor_PHPHash'=>'md5')));
|
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_md5'=>array('PasswordEncryptor_PHPHash'=>'md5')));
|
||||||
$e = PasswordEncryptor::create_for_algorithm('test_md5');
|
$e = PasswordEncryptor::create_for_algorithm('test_md5');
|
||||||
$this->assertEquals('md5', $e->getAlgorithm());
|
$this->assertEquals('md5', $e->getAlgorithm());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testEncrytorPHPHash() {
|
function testEncryptorPHPHash() {
|
||||||
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_sha1'=>array('PasswordEncryptor_PHPHash'=>'sha1')));
|
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_sha1'=>array('PasswordEncryptor_PHPHash'=>'sha1')));
|
||||||
$e = PasswordEncryptor::create_for_algorithm('test_sha1');
|
$e = PasswordEncryptor::create_for_algorithm('test_sha1');
|
||||||
$password = 'mypassword';
|
$password = 'mypassword';
|
||||||
@ -60,8 +60,19 @@ class PasswordEncryptorTest extends SapphireTest {
|
|||||||
$e->encrypt($password, $salt)
|
$e->encrypt($password, $salt)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testEncryptorBlowfish() {
|
||||||
|
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_blowfish'=>array('PasswordEncryptor_Blowfish'=>'')));
|
||||||
|
$e = PasswordEncryptor::create_for_algorithm('test_blowfish');
|
||||||
|
$password = 'mypassword';
|
||||||
|
$salt = '10$mysaltmustbetwen2char';
|
||||||
|
$this->assertEquals(
|
||||||
|
crypt($password, '$2y$' . $salt),
|
||||||
|
'$2y$' . $salt . $e->encrypt($password, $salt)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function testEncrytorPHPHashCompare() {
|
function testEncryptorPHPHashCompare() {
|
||||||
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_sha1'=>array('PasswordEncryptor_PHPHash'=>'sha1')));
|
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_sha1'=>array('PasswordEncryptor_PHPHash'=>'sha1')));
|
||||||
$e = PasswordEncryptor::create_for_algorithm('test_sha1');
|
$e = PasswordEncryptor::create_for_algorithm('test_sha1');
|
||||||
$this->assertTrue($e->compare(sha1('mypassword'), sha1('mypassword')));
|
$this->assertTrue($e->compare(sha1('mypassword'), sha1('mypassword')));
|
||||||
@ -74,7 +85,7 @@ class PasswordEncryptorTest extends SapphireTest {
|
|||||||
* Handy command for reproducing via CLI on different architectures:
|
* Handy command for reproducing via CLI on different architectures:
|
||||||
* php -r "echo(base_convert(sha1('mypassword'), 16, 36));"
|
* php -r "echo(base_convert(sha1('mypassword'), 16, 36));"
|
||||||
*/
|
*/
|
||||||
function testEncrytorLegacyPHPHashCompare() {
|
function testEncryptorLegacyPHPHashCompare() {
|
||||||
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_sha1legacy'=>array('PasswordEncryptor_LegacyPHPHash'=>'sha1')));
|
Config::inst()->update('PasswordEncryptor', 'encryptors', array('test_sha1legacy'=>array('PasswordEncryptor_LegacyPHPHash'=>'sha1')));
|
||||||
$e = PasswordEncryptor::create_for_algorithm('test_sha1legacy');
|
$e = PasswordEncryptor::create_for_algorithm('test_sha1legacy');
|
||||||
// precomputed hashes for 'mypassword' from different architectures
|
// precomputed hashes for 'mypassword' from different architectures
|
||||||
|
@ -14,7 +14,7 @@ class EncryptAllPasswordsTaskTest extends SapphireTest {
|
|||||||
$t->run(null);
|
$t->run(null);
|
||||||
|
|
||||||
$m = DataObject::get_by_id('Member', $m->ID);
|
$m = DataObject::get_by_id('Member', $m->ID);
|
||||||
$this->assertEquals($m->PasswordEncryption, 'sha1_v2.4');
|
$this->assertEquals($m->PasswordEncryption, 'blowfish');
|
||||||
$this->assertNotEquals($m->Password, 'plain');
|
$this->assertNotEquals($m->Password, 'plain');
|
||||||
$result = $m->checkPassword('plain');
|
$result = $m->checkPassword('plain');
|
||||||
$this->assertTrue($result->valid());
|
$this->assertTrue($result->valid());
|
||||||
|
Loading…
Reference in New Issue
Block a user