<p>Check out the <strong>Legacy Login</strong> plugin...</p>

<blockquote>
  <p><a href="https://github.com/TopShelfCraft/Legacy-Login" rel="nofollow">https://github.com/TopShelfCraft/Legacy-Login</a></p>
</blockquote>

<p>It's designed to handle a migration of users between EE and Craft.</p>

CC BY-SA 3.0
2016-07-29T16:58:17.437Z
2016-07-29T16:58:17.437Z
Lindsey D
<p>It would be possible to write a plugin that provides an alternative login controller action, based on <a href="https://craftcms.com/classreference/controllers/UsersController#actionLogin-detail">UsersController::actionLogin()</a>. 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.</p>

<p>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.</p>

<p>So, your plugin would need a custom <a href="https://craftcms.com/docs/plugins/controllers">controller</a> class, with the following code:</p>

<p>

<pre><code>namespace Craft;

class CustomLoginController extends BaseController
{
    protected $allowAnonymous = true;

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

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

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

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

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

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

            if ($user)
            {
                // See if they had an EE user account
                $host = craft()-&gt;config-&gt;get('server', ConfigFile::Db);
                $port = craft()-&gt;config-&gt;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-&gt;createCommand()
                    -&gt;select('member_id, password, salt')
                    -&gt;from('exp_members')
                    -&gt;where(array('or', 'username=:login', 'email=:login'), array(':login' =&gt; $loginName))
                    -&gt;queryRow();

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

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

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

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

        return $hashedPassword;
    }
}
</code></pre>

<p>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 <code>hash_password()</code>. Not going to repost it here as it is copyrighted, though.</p>

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

<pre><code>&lt;input type="hidden" name="action" value="customLogin/login"&gt;
</code></pre>

CC BY-SA 3.0
2016-07-29T13:17:22.060Z
2016-07-29T13:17:22.060Z
Brandon Kelly
<p>We've rewritten an EE site on Craft and now need to import the members.</p>

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

<p>Is that correct ? </p>

<migration><password><member><hash>
Importing members from EE without password reset
# Importing members from EE without password reset

(Asked by: username_0 on 2016-07-29)

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 ?

**Tags:** migration, password, member, hash

---

## 2 answers

### Answer by username_2 on 2016-07-29. Score: 5 | Accepted answer

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:


---

### Answer by username_1 on 2016-07-29. Score: 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.


---

