Commit a0002094 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'B12516passwordHashingExceptionForkred' into 'develop'

B12516 password hashing algorithm is configured in QFQ config

See merge request !346
parents d1414af7 bf61d8a1
Pipeline #5223 passed with stages
in 3 minutes and 24 seconds
......@@ -334,20 +334,23 @@ qfq.json
* Additionally to the keywords bellow one can also override the configuration values defined in the Typo3 extension manager: :ref:`extension-manager-qfq-configuration`
* e.g. if `qfq.json` contains `"flagProduction":"no"` then this value is taken instead of the one set in the extension manager.
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| Keyword | Example | Description |
+===============================+=======================================================+============================================================================+
| DB_<n>_USER | DB_1_USER=qfqUser | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_PASSWORD | DB_1_PASSWORD=1234567890 | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_SERVER | DB_1_SERVER=localhost | Hostname of MySQL Server |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_NAME | DB_1_NAME=qfq_db | Database name |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| LDAP_1_RDN | LDAP_1_RDN='ou=Admin,ou=example,dc=com' | Credentials for non-anonymous LDAP access. Only one set supported. |
| LDAP_1_PASSWORD | LDAP_1_PASSWORD='mySecurePassword' | |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| Keyword | Example | Description |
+===============================+=======================================================+==========================================================================================================+
| DB_<n>_USER | "DB_1_USER"="qfqUser" | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| DB_<n>_PASSWORD | "DB_1_PASSWORD"="1234567890" | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| DB_<n>_SERVER | "DB_1_SERVER"="localhost" | Hostname of MySQL Server |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| DB_<n>_NAME | "DB_1_NAME"="qfq_db" | Database name |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| LDAP_1_RDN | "LDAP_1_RDN"="ou=Admin,ou=example,dc=com " | Credentials for non-anonymous LDAP access. Only one set supported. |
| LDAP_1_PASSWORD | "LDAP_1_PASSWORD"="mySecurePassword" | |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
| PASSWORD_HASH_TYPE | "PASSWORD_HASH_TYPE"="PASSWORD_BCRYPT" | Password hashing algorithm used for "p" action class. See: :ref:`variable-escape` |
| | | Possible values: "PASSWORD_ARGON2I" (QFQ default), "PASSWORD_BCRYPT", "PASSWORD_DEFAULT" (PHP default) |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------------------------------------+
Example: *fileadmin/protected/qfqProject/qfq.json*: ::
......
......@@ -221,7 +221,7 @@ The following `escape` & `action` types are available:
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| m | `real_escape_string() <http://php.net/manual/en/mysqli.real-escape-string.php>`_ (m = mysql) |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| p | Password hashing: depends on the hashing type in the Typo3 installation, includes salting if configured. |
| p | Password hashing with salting. Password hashing algorithm may be configured in: :ref:`qfq.json` (default is Argon2i) |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
| s | Single ticks ``'`` will be escaped by ``\'``. |
+-------+----------------------------------------------------------------------------------------------------------------------------------+
......
......@@ -107,6 +107,7 @@ fi
### Write config files ###
# QFQ config
# NOTE: If the baseUrl is empty QFQ throws an exception. (The space is a hack to circumvent that)
cat <<EOT >> qfq.json
{
"DB_1_USER": "${MYSQL_USER}",
......
......@@ -552,6 +552,8 @@ const SYSTEM_FORM_BS_NOTE_COLUMNS = 'formBsNoteColumns';
const SYSTEM_BASE_URL = 'baseUrl';
const SYSTEM_PASWORD_HASH_TYPE = 'PASSWORD_HASH_TYPE';
const SYSTEM_SEND_E_MAIL_OPTIONS = 'sendEMailOptions';
const SYSTEM_EDIT_FORM_PAGE = 'editFormPage';
......
......@@ -8,8 +8,10 @@
namespace IMATHUZH\Qfq\Core\Typo3;
use IMATHUZH\Qfq\Core\Exception\Thrower;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Store\Config;
/**
......@@ -40,48 +42,48 @@ class T3Handler {
/**
* Convert a cleartext password to a hash. Respects if 'salted passwords' are enabled.
* The password hash type is taken from QFQ config, Argon2i is used by default.
*
* @param string $newPassword
* @return string
* @throws \CodeException
* @throws \UserFormException
* @throws \UserReportException
*/
public static function getHash($newPassword) {
// Restore T3 ErrorHandler. T3 throws exceptions - those should be handled by T3!
restore_error_handler();
$saltedPassword = null;
// Typo3 version <=8
// Legacy code based on https://docs.typo3.org/typo3cms/extensions/saltedpasswords/8.7/DevelopersGuide/Index.html
self::t3AutoloadIfNotRunning();
if (class_exists('\TYPO3\CMS\Core\Utility\GeneralUtility')
&& class_exists('\TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory')) {
// Typo3 version >=9
$hashInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory::class)
->getDefaultHashInstance('FE');
$saltedPassword = $hashInstance->getHashedPassword($newPassword);
} elseif (class_exists('\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility') && class_exists('\TYPO3\CMS\Saltedpasswords\Salt\SaltFactory')) {
// Typo3 version <=8
// Legacy code based on https://docs.typo3.org/typo3cms/extensions/saltedpasswords/8.7/DevelopersGuide/Index.html
if (!class_exists('\TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory')
&& class_exists('\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility')
&& class_exists('\TYPO3\CMS\Saltedpasswords\Salt\SaltFactory')) {
$saltedPassword = null;
restore_error_handler(); // Restore T3 ErrorHandler. T3 throws exceptions - those should be handled by T3!
if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
$objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(NULL);
if (is_object($objSalt)) {
$saltedPassword = $objSalt->getHashedPassword($newPassword);
}
}
Support::setQfqErrorHandler(); // Activate QFQ ErrorHandler again.
if (!is_null($saltedPassword)) {
return $saltedPassword;
}
}
// Activate QFQ ErrorHandler again.
Support::setQfqErrorHandler();
if (is_null($saltedPassword)) {
// Fallback, use Argon2i algorithm (with current default options of typo3 in year 2020)
// Typo3 version >=9
$type = Config::get(SYSTEM_PASWORD_HASH_TYPE) ?? 'PASSWORD_ARGON2I';
if ($type === 'PASSWORD_ARGON2I') {
// Use Argon2i algorithm (with current default options of typo3 in year 2020)
$saltedPassword = password_hash($newPassword, PASSWORD_ARGON2I, ['memory_cost' => 65536, 'time_cost' => 16, 'threads' => 1]);
} elseif ($type === 'PASSWORD_DEFAULT') {
$saltedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
} elseif ($type === 'PASSWORD_BCRYPT') {
$saltedPassword = password_hash($newPassword, PASSWORD_BCRYPT);
} else {
Thrower::userFormException('Password hashing type not recognized.', 'The following password hashing type is not recognized: ' . $type);
}
return $saltedPassword;
}
......@@ -94,43 +96,7 @@ class T3Handler {
* @throws \UserFormException
*/
public static function checkPassword($saltedPassword, $password) {
$success = null;
self::t3AutoloadIfNotRunning();
// Restore T3 ErrorHandler. T3 throws exceptions - those should be handled by T3!
restore_error_handler();
if (class_exists('\TYPO3\CMS\Core\Utility\GeneralUtility')
&& class_exists('\TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory')) {
// Typo3 version >=9
$success = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory::class)
->get($saltedPassword, 'FE') # or getDefaultHashInstance($mode)
->checkPassword($password, $saltedPassword);
} elseif (class_exists('\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility') && class_exists('\TYPO3\CMS\Saltedpasswords\Salt\SaltFactory')) {
// Typo3 version <=8
// Legacy code based on https://docs.typo3.org/typo3cms/extensions/saltedpasswords/8.7/DevelopersGuide/Index.html
if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
$objSalt2 = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltedPassword);
if (is_object($objSalt2)) {
$success = $objSalt2->checkPassword($password, $saltedPassword);
}
}
}
// Activate QFQ ErrorHandler again.
Support::setQfqErrorHandler();
if (is_null($success)) {
// fallback use php function directly
$success = password_verify($password, $saltedPassword);
}
return $success;
return password_verify($password, $saltedPassword);
}
/**
......
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