Commit 366392b1 authored by Andreas Beutel's avatar Andreas Beutel

[TASK] Provide password hashing method CRYPT SHA512

parent b5c0e9f4
Pipeline #7385 passed with stages
in 2 minutes and 31 seconds
......@@ -159,34 +159,39 @@ class Ldap implements \Psr\Log\LoggerAwareInterface
* to syslog.
*
* @param string $username Username for bind
* @param array $values The password array
* @param array $values The password hashes as array
* @return bool
*/
public function setLdapPasswords($username, $values)
public function setLdapPasswords(string $username, array $values): bool
{
$ret = false;
// Create LDAP connection
if ($this->createLdapConnection() === true) {
// Try to bind as admin
if ($this->ldapBind($this->ldapConnection, $this->ldapBindDn, $this->ldapBindPassword) === true) {
$dn = $this->getDnForUserName($username);
// TODO Check if user exists and create if not exists?
// Finally try to update passwords
$result = $this->updateLdapAttribute($dn, 'userPassword', $values, true);
if ($result === false) {
$this->logger->error(ldap_error($this->ldapConnection));
try {
if ($this->createLdapConnection() === true) {
// Try to bind as admin
if ($this->ldapBind($this->ldapConnection, $this->ldapBindDn, $this->ldapBindPassword) === true) {
$dn = $this->getDnForUserName($username);
// Unset userPassword to remove deprecated password hashes
$unsetPasswordResult = ldap_mod_del($this->ldapConnection, trim($dn), ['userPassword' => []]);
if ($unsetPasswordResult === false) {
$this->logger->error(ldap_error($this->ldapConnection));
} else {
$updatePasswordResult = $this->updateLdapAttribute($dn, 'userPassword', $values, true);
if ($updatePasswordResult === false) {
$this->logger->error(ldap_error($this->ldapConnection));
} else {
return true;
}
}
} else {
$this->logger->error('Unable to bind to LDAP using: ' . ldap_error($this->ldapConnection));
}
} else {
$this->logger->error('Unable to bind to LDAP using: ' . ldap_error($this->ldapConnection));
$this->logger->error('No active LDAP connection available');
}
} else {
$this->logger->error('No active LDAP connection available');
} catch (\Exception $e) {
$this->logger->error('Could not create LDAP connection');
}
return $ret;
return false;
}
/**
......@@ -256,7 +261,7 @@ class Ldap implements \Psr\Log\LoggerAwareInterface
private function createLdapConnection()
{
$ret = false;
$port = intval($this->ldapServerPort);
$port = (int)$this->ldapServerPort;
try {
if (function_exists('ldap_connect')) {
$this->ldapConnection = @ldap_connect($this->ldapServer, ($port > 0 ? $port : null));
......@@ -274,12 +279,12 @@ class Ldap implements \Psr\Log\LoggerAwareInterface
}
}
} else {
throw new \RuntimeException(
throw new \Exception(
'Could not create LDAP connection: ' . ldap_error($this->ldapConnection),
1453993539
);
}
} catch (\RuntimeException $e) {
} catch (\Exception $e) {
$this->logger->error($e->getMessage());
}
......
......@@ -25,10 +25,10 @@ class PasswordHashing
*
* @param string $clearText Cleartext representation of the password
* @param string $algorithm The hashing mechanism
* @param string $salt Optional salt
* @param int $rounds The number of rounds for Crypt Salt
* @return bool|string False on failure or the hashed password as string
*/
public function getPasswordHash($clearText, $algorithm = 'crypt', $salt = 'xy')
public function getPasswordHash($clearText, $algorithm = 'crypt_sha512', $rounds = 5000)
{
$ret = false;
if (trim($clearText) !== '') {
......@@ -37,12 +37,19 @@ class PasswordHashing
$passwordHash = sha1($clearText, true);
$ret = '{SHA}' . base64_encode($passwordHash);
break;
case 'md5':
$passwordHash = md5($clearText, true);
$ret = '{MD5}' . base64_encode($passwordHash);
break;
case 'crypt':
$passwordHash = crypt($clearText, $salt);
case 'crypt_sha512':
$characters = array_merge(
range('0', '9'),
range('a', 'z'),
range('A', 'Z'),
['.', '/']
);
$salt = '';
$length = count($characters) - 1;
for ($i = 0; $i < 16; $i++) {
$salt .= $characters[rand(0, $length)];
}
$passwordHash = crypt($clearText, '$6$rounds=' . (int)$rounds . '$' . $salt . '$');
$ret = '{CRYPT}' . $passwordHash;
// no break
default:
......
......@@ -12,6 +12,8 @@ namespace T3o\T3oLdap\Utility;
* LICENSE.txt file that was distributed with this source code.
*/
use T3o\T3oLdap\Connectors\Ldap;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
......@@ -21,16 +23,18 @@ class PasswordUpdate implements \Psr\Log\LoggerAwareInterface
{
use \Psr\Log\LoggerAwareTrait;
const PASSWORD_METHODS = ['md5', 'sha1', 'crypt'];
const PASSWORD_METHODS = ['crypt_sha512'];
/**
* Update a password in various places (LDAP, TYPO3)
*
* @param string $username The username to update the password for
* @param string $clearTextPassword Cleartext password to hash and update
* @return bool
*/
public function updatePassword(string $username, string $clearTextPassword)
public function updatePassword(string $username, string $clearTextPassword): bool
{
$ret = false;
if (version_compare(TYPO3_version, '9.0', '<')) {
$extensionConfiguration = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['t3o_ldap'] ?? '') ?? [];
} else {
......@@ -39,15 +43,24 @@ class PasswordUpdate implements \Psr\Log\LoggerAwareInterface
// Check if LDAP updates are enabled in extension configuration
if ((int)$extensionConfiguration['enableLdapPasswordUpdates'] === 1) {
/** @var \T3o\T3oLdap\Connectors\Ldap $ldap */
$ldap = GeneralUtility::makeInstance(\T3o\T3oLdap\Connectors\Ldap::class);
if ($ldap->setLdapPasswords($username, $this->getHashedPasswords($clearTextPassword))) {
$this->logger = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__);
/** @var Ldap $ldap */
$ldap = GeneralUtility::makeInstance(Ldap::class);
$passwordUpdateResult = $ldap->setLdapPasswords($username, $this->getHashedPasswords($clearTextPassword));
$this->logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
if ($passwordUpdateResult === true) {
$this->logger->info('Password successfully updated (Mechanisms: ' . strtoupper(implode(', ', self::PASSWORD_METHODS)) . ')');
$ret = true;
} else {
$this->logger->info('Password has not been updated (Mechanisms: ' . strtoupper(implode(', ', self::PASSWORD_METHODS)) . ')');
}
}
return $ret;
}
/**
* @param string $clearTextPassword
* @return array
*/
public function getHashedPasswords(string $clearTextPassword): array
{
$passwords = [];
......
......@@ -13,6 +13,7 @@ namespace T3o\T3oLdap\Utility;
* LICENSE.txt file that was distributed with this source code.
*/
use T3o\T3oLdap\Connectors\Ldap;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
use TYPO3\CMS\Core\Utility\GeneralUtility;
......@@ -38,9 +39,9 @@ class UserCreateUpdateDelete
{
$ret = false;
/** @var \T3o\T3oLdap\Connectors\Ldap $ldap */
/** @var Ldap $ldap */
try {
$ldap = new \T3o\T3oLdap\Connectors\Ldap();
$ldap = new Ldap();
} catch (\Exception $e) {
throw $e;
}
......
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