Revert "Introduce PasswordHelper for safer passwords"

This reverts commit f57277aa96.

Since we're dropping PHP support for versions lower than 5.6 this class is no longer necessary.
This commit is contained in:
Eric Lippmann 2018-05-08 09:04:52 +02:00
parent 966148e8f0
commit faaff42096
2 changed files with 0 additions and 201 deletions

View File

@ -1,109 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
namespace Icinga\Authentication;
use Icinga\Exception\AuthenticationException;
/**
* Helper for password hashing to improve compatibility to PHP < 5.5
*/
class PasswordHelper
{
/**
* The PHP version that introduced support for functions:
*
* password_hash()
* password_verify()
*
* @var string
*/
const PHP_VERSION_COMPAT = '5.5.0';
/**
* Algo to force fallback to compat algorithm
*/
const PASSWORD_ALGO_FALLBACK = 999;
/**
* The length of the salt to use when hashing a password with SHA method
*
* 16 is the required character count
*
* @var int
*/
const COMPAT_SALT_LENGTH = 16;
/**
* Hash type to use as compat method: SHA-512
*
* @var string
*/
const COMPAT_HASH = '$6$rounds=5000$';
/**
* Check if we have a modern PHP based on version
*
* @return bool
*/
public static function supportsModernAPI()
{
return version_compare(phpversion(), self::PHP_VERSION_COMPAT, '>=');
}
/**
* Hash a password with password_hash() or crypt()
*
* @param string $password
* @param int $algo
*
* @return string
* @throws AuthenticationException
*/
public static function hash($password, $algo = null)
{
if (static::supportsModernAPI() and $algo !== self::PASSWORD_ALGO_FALLBACK) {
if ($algo === null) {
$algo = PASSWORD_DEFAULT;
}
$p = password_hash($password, $algo);
if ($p === false) {
throw new AuthenticationException('Could not hash password, password_hash() returned false!');
}
} else {
$p = crypt($password, self::COMPAT_HASH . static::generateSalt());
if (strlen($p) < 13) {
throw new AuthenticationException('Hash generated by crypt() seems too small, this suggests an error!');
}
}
return $p;
}
/**
* Verify a password with either password_verify() or crypt()
*
* @param string $password
* @param string $hash
*
* @return bool
*/
public static function verify($password, $hash)
{
if (static::supportsModernAPI()) {
return password_verify($password, $hash);
} else {
return crypt($password, $hash) === $hash;
}
}
/**
* Shorthand to generate a salt to use with crypt()
*
* @return string
*/
public static function generateSalt()
{
return bin2hex(openssl_random_pseudo_bytes(self::COMPAT_SALT_LENGTH / 2));
}
}

View File

@ -1,92 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
namespace Tests\Icinga\Authentication\User;
use Icinga\Authentication\PasswordHelper;
use Icinga\Test\BaseTestCase;
class PasswordHelperTest extends BaseTestCase
{
const TEST_PASSWORD = 'icinga';
const TEST_PASSWORD_LONG = 'icashd89as9tgd897asztd78asztd87astd87astda8s7tda8s7tdas0duasdasdaasdua8sdz8a9szd97gjml';
const TEST_PASSWORD_HASHED_BLOWFISH_1 = '$2y$15$iYB4TlPDcZWRyZZ/OhQc/uJRF2ElEDdvYwx3o8Lo3HMyGmeRWVYZu';
const TEST_PASSWORD_HASHED_BLOWFISH_2 = '$2y$10$/avFxk1nhflzp1SjQAyz5OGkRj3XdTvlvEfsFS3jnK.RiFoXV12xW';
const TEST_PASSWORD_HASHED_BLOWFISH_LONG = '$2y$10$TKeUw2FFmhxhG4ed7Fy4CuPMY5h3wi6igKgs3j6XOHwP6Tupe4qbu';
// @codingStandardsIgnoreLine
const TEST_PASSWORD_HASHED_SHA256 = '$6$rounds=5000$ca15a2843471ce6a$pZobBdfC0AhF4sT5FPBH6WnPYHEkXB/d4ihXuSmETqLGMV.PMVLMuTZHO4wTU8BL48onyfmT5zHC.fOenOZmH1';
/**
* Test hash from the old Icinga Web 2 MD5 hash type
*
* Stored for hex2bin() / pack('H*', xx)
*
* @var string
*/
const TEST_PASSWORD_OLD_MD5 = '243124DBEC64CECBB8E0932434525A51424B744D313634757A543445483839496130';
public function testGenerateSalt()
{
$this->assertRegExp(
'~^[a-f0-9]{16}$~i',
PasswordHelper::generateSalt(),
'A hex based salt with 16 chars must be returned'
);
}
public function testHash()
{
foreach (array(self::TEST_PASSWORD, self::TEST_PASSWORD_LONG) as $pw) {
$hashed = PasswordHelper::hash($pw);
$this->assertRegExp(
'~^\$\d\w*\$(?:rounds=\d+\$)?~',
$hashed,
'Hash output must look like a hash: ' . $hashed
);
$this->assertEquals(
crypt($pw, $hashed),
$hashed,
'New hashed password must validate via crypt: ' . $hashed
);
}
}
public function testHashFallback()
{
$hashed = PasswordHelper::hash(self::TEST_PASSWORD, PasswordHelper::PASSWORD_ALGO_FALLBACK);
$this->assertRegExp(
'~^\$6\$rounds=\d+\$?~',
$hashed,
'Hash output must look like a SHA-512 hash: ' . $hashed
);
$this->assertEquals(
crypt(self::TEST_PASSWORD, $hashed),
$hashed,
'New hashed password must validate via crypt: ' . $hashed
);
}
public function testVerify()
{
$pws = array(
self::TEST_PASSWORD_HASHED_BLOWFISH_1 => self::TEST_PASSWORD,
self::TEST_PASSWORD_HASHED_BLOWFISH_2 => self::TEST_PASSWORD,
self::TEST_PASSWORD_HASHED_BLOWFISH_LONG => self::TEST_PASSWORD_LONG,
self::TEST_PASSWORD_HASHED_SHA256 => self::TEST_PASSWORD,
pack('H*', self::TEST_PASSWORD_OLD_MD5) => self::TEST_PASSWORD,
);
foreach ($pws as $hash => $pw) {
$this->assertTrue(
PasswordHelper::verify($pw, $hash),
'Password must be validated against its hash'
);
}
}
}