Commit 8a350d89 authored by Marc Egger's avatar Marc Egger
Browse files

Refs #12516 password hashing algorithm is configured in QFQ config.

parent d1414af7
Pipeline #5221 passed with stages
in 4 minutes and 4 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,46 +42,27 @@ 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;
self::t3AutoloadIfNotRunning();
if (class_exists('\TYPO3\CMS\Core\Utility\GeneralUtility')
&& class_exists('\TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory')) {
$type = Config::get(SYSTEM_PASWORD_HASH_TYPE) ?? 'PASSWORD_ARGON2I';
// 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 (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
$objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(NULL);
if (is_object($objSalt)) {
$saltedPassword = $objSalt->getHashedPassword($newPassword);
}
}
}
// Activate QFQ ErrorHandler again.
Support::setQfqErrorHandler();
if (is_null($saltedPassword)) {
// Fallback, use Argon2i algorithm (with current default options of typo3 in year 2020)
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 +77,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