Merge pull request #3452 from Icinga/feature/drop-php-lt-56-support
Drop support for PHP < 5.6
This commit is contained in:
commit
303637df3c
|
@ -3,8 +3,6 @@ dist: trusty
|
|||
sudo: false
|
||||
|
||||
php:
|
||||
- '5.4'
|
||||
- '5.5'
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
- '7.1'
|
||||
|
|
|
@ -14,9 +14,7 @@ chapter.
|
|||
|
||||
* [Icinga 2](https://www.icinga.com/products/icinga-2/) with the IDO database backend (MySQL or PostgreSQL)
|
||||
* A web server, e.g. Apache or Nginx
|
||||
* PHP version >= 5.6.0. Though Icinga Web 2 version 2.5.x is compatible with PHP version >= 5.3.2 there are modules
|
||||
which require a higher PHP version. Also, future versions of Icinga Web 2 will drop support for outdated PHP versions.
|
||||
Packages for Icinga Web 2 already require PHP >= 5.6.0
|
||||
* PHP version >= 5.6.0
|
||||
* The following PHP modules must be installed: cURL, gettext, intl, mbstring, OpenSSL and xml
|
||||
* Default time zone configured for PHP in the php.ini file
|
||||
* LDAP PHP library when using Active Directory or LDAP for authentication
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
namespace Icinga\Authentication\User;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Authentication\PasswordHelper;
|
||||
use Icinga\Data\Inspectable;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
|
@ -166,7 +165,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||
*/
|
||||
protected function persistPassword($value)
|
||||
{
|
||||
return PasswordHelper::hash($value);
|
||||
return password_hash($value, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,7 +212,7 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||
public function authenticate(User $user, $password)
|
||||
{
|
||||
try {
|
||||
return PasswordHelper::verify(
|
||||
return password_verify(
|
||||
$password,
|
||||
$this->getPasswordHash($user->getUsername())
|
||||
);
|
||||
|
|
|
@ -54,11 +54,7 @@ class Json
|
|||
*/
|
||||
protected static function encodeAndSanitize($value, $options, $depth, $autoSanitize)
|
||||
{
|
||||
if (version_compare(phpversion(), '5.5.0', '<')) {
|
||||
$encoded = json_encode($value, $options);
|
||||
} else {
|
||||
$encoded = json_encode($value, $options, $depth);
|
||||
}
|
||||
$encoded = json_encode($value, $options, $depth);
|
||||
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_NONE:
|
||||
|
@ -72,7 +68,7 @@ class Json
|
|||
// Fallthrough
|
||||
|
||||
default:
|
||||
throw new JsonEncodeException('%s: %s', static::lastErrorMsg(), var_export($value, true));
|
||||
throw new JsonEncodeException('%s: %s', json_last_error_msg(), var_export($value, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,39 +88,11 @@ class Json
|
|||
$decoded = json_decode($json, $assoc, $depth, $options);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new JsonDecodeException('%s: %s', static::lastErrorMsg(), var_export($json, true));
|
||||
throw new JsonDecodeException('%s: %s', json_last_error_msg(), var_export($json, true));
|
||||
}
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link json_last_error_msg()} replacement for PHP < 5.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function lastErrorMsg()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
|
||||
return json_last_error_msg();
|
||||
}
|
||||
|
||||
// All possible error codes before PHP 5.5.0 (except JSON_ERROR_NONE)
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
return 'Maximum stack depth exceeded';
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
return 'State mismatch (invalid or malformed JSON)';
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
return 'Control character error, possibly incorrectly encoded';
|
||||
case JSON_ERROR_SYNTAX:
|
||||
return 'Syntax error';
|
||||
case JSON_ERROR_UTF8:
|
||||
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
default:
|
||||
return 'Unknown error';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace bad byte sequences in UTF-8 strings inside the given JSON-encodable structure with question marks
|
||||
*
|
||||
|
|
|
@ -884,9 +884,9 @@ msgstr "Root DN"
|
|||
|
||||
#: ../../../../modules/setup/library/Setup/WebWizard.php:556
|
||||
msgid ""
|
||||
"Running Icinga Web 2 requires PHP version 5.4."
|
||||
"Running Icinga Web 2 requires PHP version 5.6."
|
||||
msgstr ""
|
||||
"Der Betrieb von Icinga Web 2 erfordert die PHP-Version 5.4."
|
||||
"Der Betrieb von Icinga Web 2 erfordert die PHP-Version 5.6."
|
||||
|
||||
#: ../../../../modules/setup/library/Setup/Steps/ResourceStep.php:104
|
||||
msgid "SSL Cert"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Copyright (C) 2015 Icinga Development Team
|
||||
# This file is distributed under the same license as Setup Module.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
@ -862,9 +862,9 @@ msgstr "Root DN"
|
|||
|
||||
#: /usr/share/icingaweb2/modules/setup/library/Setup/WebWizard.php:552
|
||||
msgid ""
|
||||
"Running Icinga Web 2 requires PHP version 5.4."
|
||||
"Running Icinga Web 2 requires PHP version 5.6."
|
||||
msgstr ""
|
||||
"Icinga Web 2 richiede PHP 5.4."
|
||||
"Icinga Web 2 richiede PHP 5.6."
|
||||
|
||||
#: /usr/share/icingaweb2/modules/setup/library/Setup/WebWizard.php:356
|
||||
msgid "Setup Icinga Web 2"
|
||||
|
|
|
@ -568,10 +568,10 @@ class WebWizard extends Wizard implements SetupWizard
|
|||
$set = new RequirementSet();
|
||||
|
||||
$set->add(new PhpVersionRequirement(array(
|
||||
'condition' => array('>=', '5.4'),
|
||||
'condition' => array('>=', '5.6'),
|
||||
'description' => mt(
|
||||
'setup',
|
||||
'Running Icinga Web 2 requires PHP version 5.4.'
|
||||
'Running Icinga Web 2 requires PHP version 5.6.'
|
||||
)
|
||||
)));
|
||||
|
||||
|
|
|
@ -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'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,16 +3,10 @@
|
|||
set -ex
|
||||
|
||||
ICINGAWEB_HOME=${ICINGAWEB_HOME:="$(dirname "$(readlink -f $(dirname "$0"))")"}
|
||||
PHP_VERSION="$(php -r 'echo phpversion();')"
|
||||
PHPCS_VERSION=${PHPCS_VERSION:=3.0.2}
|
||||
MOCKERY_VERSION=${MOCKERY_VERSION:=0.9.9}
|
||||
HAMCREST_VERSION=${HAMCREST_VERSION:=2.0.0}
|
||||
|
||||
if [ "$PHP_VERSION" '<' 5.6.0 ]; then
|
||||
PHPUNIT_VERSION=${PHPUNIT_VERSION:=4.8}
|
||||
else
|
||||
PHPUNIT_VERSION=${PHPUNIT_VERSION:=5.7}
|
||||
fi
|
||||
PHPUNIT_VERSION=${PHPUNIT_VERSION:=5.7}
|
||||
|
||||
cd ${ICINGAWEB_HOME}
|
||||
|
||||
|
|
Loading…
Reference in New Issue