Search code examples
typo3typo3-8.7.x

TYPO3 login fail with \Saltedpasswords vs correct with felogin


My client has an old TYPO3 6.2 installation which has been rebuild in TYPO3 8.7.

In the old TYPO3 6.2 installation the fe_users table owns about 15.000 users with MD5/crypt(3) encrypted passwords (starting with $1$). The rebuild fe_users for the client in TYPO3 8.7 now has passwords based on the new crypt (starting with $pbkdf2-sha256$). So far, so good.

The old TYPO3 6.2 fe_users will be imported into the new database but I'm having issues on logging in with them using our own REST API (build in TYPO3 8.7), where the login using felogin are all successfull. After a successfull login by felogin the passwords are converted to their new encryption and I am able to login with the REST API. -- Logging in 15.000 users by felogin before the possibility of using the REST API is definitely not an option :)

The REST API does a comparison using \TYPO3\CMS\Saltedpasswords\.

tl;dr: How do I check for a successfull encryption by \TYPO3\CMS\Saltedpasswords\ without first forcing them the usage of felogin?

Sample code of the REST API

The $byPasswordDecrypt in the code below is a decrypted value of the password, which is send encrypted using RNCryptor

$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('fe_users');
    $queryRows = $queryBuilder
            ->select('uid', 'username', 'password')
            ->from('fe_users')
            ->where(
                    $queryBuilder->expr()->eq('username', $queryBuilder->createNamedParameter($ogUser))
            )
            ->execute();

    // Fetch the rows
    $queryFetch = $user = $queryRows->fetch();

    // Now, check the salted-password from the database against the given password
    if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
        $objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltedPassword);
        if (is_object($objSalt)) {
            $success = $objSalt->checkPassword($byPasswordDecrypt, $queryFetch['password']);
        }
    }

If somebody could point me into the right direction to a successfull password-hash check, that would be absolutely great and I'd be so thankfull!


Solution

  • I have managed to fix this problem myself and posting the solution to my own question, hoping to help someone else with this issue.

    TYPO3 6.2 (and probably lower) is hashing the passwords using a MD5-hash, starting with $1$. If everything set-up correctly, TYPO3 8.7 will hash the passwords using something like $pbkdf2-sha256$.

    To check for old passwords, you should make an instance of the TYPO3\CMS\Saltedpasswords\Salt\Md5Salt. After you've done a successfull check using checkPassword by this instance, I'd recommend you update your database table using the given password and encrypting it by using \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory.

    An examplecode for checking the old MD5 encrypted password:

    $md5PasswordProcessor = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Saltedpasswords\\Salt\\Md5Salt');
    
    $sampleLoginData = array(
        'uname' => $usernameSample
        'uident' => $unencryptedPassword,
        'status' => 'login'
    );
    
    $frontEndUserAuth = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Authentication\\FrontendUserAuthentication');
    $frontEndUserAuth->checkPid = false;
    
    $info = $frontEndUserAuth->getAuthInfoArray();
    $info['db_user']['username_column'] = 'email';
    
    $user_db = $frontEndUserAuth->fetchUserRecord($info['db_user'], $sampleLoginData['uname']);
    
    $passwordByMd5 = $md5PasswordProcessor->checkPassword($byPasswordDecrypt, $user_db['password']);
    
    if($passwordByMd5 === true) {
        // Check is correct, update your database here by, for example:
        $objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null);
        $saltedPassword = $objSalt->getHashedPassword($unencryptedPassword);
    
        // And your queryBuilder should be written here
    }
    

    I hope I helped anyone else out, having this problem.