1

We've rewritten an EE site on Craft and now need to import the members.

My understanding is that since passwords are hashed & not encrypted there is no way to transfer the passwords from EE to Craft without having to force members to reset their passwords.

Is that correct ?

2 Answers 2

5

It would be possible to write a plugin that provides an alternative login controller action, based on UsersController::actionLogin(). The difference would be that, if normal login fails, it could try checking the old ExpressionEngine database to see if the user exists there, and if so, it could hash up the password in the same way EE does it, and see if it matches. When a password matches, the plugin could then A) update the user's password in the Craft database, and B) log the user in.

The only caveat (besides that this is a bit of work) is that it will only work for front-end login forms; you can’t change where the CP login form is submitted to.

So, your plugin would need a custom controller class, with the following code:

namespace Craft;

class CustomLoginController extends BaseController
{
    protected $allowAnonymous = true;

    public function actionLogin()
    {
        // Attempt to log the user in
        $this->_login();

        // Now pass back to the normal login controller
        craft()->runController('users/login');
    }

    private function _login()
    {
        if (craft()->userSession->isLoggedIn())
        {
            return;
        }

        if (craft()->request->isPostRequest())
        {
            $loginName = craft()->request->getPost('loginName');
            $password = craft()->request->getPost('password');
            $rememberMe = (bool) craft()->request->getPost('rememberMe');

            // Try logging them in normally
            if (craft()->userSession->login($loginName, $password, $rememberMe))
            {
                return;
            }

            // Is it an actual user account, at least?
            $user = craft()->users->getUserByUsernameOrEmail($loginName);

            if ($user)
            {
                // See if they had an EE user account
                $host = craft()->config->get('server', ConfigFile::Db);
                $port = craft()->config->get('port', ConfigFile::Db);
                $dbName = 'ee_database_name';
                $dbUser = 'ee_database_username';
                $dbPass = 'ee_database_password';
                $db = new DbConnection('mysql:host='.$host.';dbname='.$dbName.';port='.$port.';', $dbUser, $dbPass);

                $row = $db->createCommand()
                    ->select('member_id, password, salt')
                    ->from('exp_members')
                    ->where(array('or', 'username=:login', 'email=:login'), array(':login' => $loginName))
                    ->queryRow();

                if ($row)
                {
                    $hashedPassword = $this->_hashEEPassword($password);

                    if ($hashedPassword == $row['password'])
                    {
                        // Eureka! Now update the local user account
                        $user->newPassword = $password;
                        craft()->users->changePassword($user);

                        // Delete the old user row so their old password stops working
                        $db->createCommand()->delete('exp_members',
                            array('member_id=:id'),
                            array(':id' => $row['member_id']));
                    }
                }
            }
        }
    }

    private function _hashEEPassword($password)
    {
        // Hash the password using EE's hashing technique
        // ...

        return $hashedPassword;
    }
}

The actual code that would go into _hashEEPassword() depends on your EE version. In EE 3.1 it lives in system/ee/legacy/libraries/Auth.php, function hash_password(). Not going to repost it here as it is copyrighted, though.

With the plugin in place and installed, you can start pointing front-end login forms to the new controller action by changing the action hidden input value:

<input type="hidden" name="action" value="customLogin/login">
2

Check out the Legacy Login plugin...

https://github.com/TopShelfCraft/Legacy-Login

It's designed to handle a migration of users between EE and Craft.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.