Jump to content

Import passwords into ProcessWire from non-PW site


DrQuincy
 Share

Recommended Posts

I have an old custom site I built myself where the passwords are hashed using BCrypt.

I'm assuming the answer is no due to the one-way nautre of hashing but is there any way to take my bcrypt-hashed passwords and import them into PW? Where as my passwords stored the BCrypt strength, hash and salt together, PW seems to store the hashed password in two parts.

I think it's further complicated by the $config->userAuthSalt value (this looks more like a pepper to me).

It can't be done, can it?

In which case, will just have to copy the emails, etc across into PW and send them each an email asking they set a new password or display a message on the website if a legcay email is used to attempt a login.

Link to comment
Share on other sites

Hi @DrQuincy I think you can do this by hooking in to PW's login flow. Here's how I'd attempt to do this - untested - just to give you some inspiration...

  1. Create a new field on the User template for their hashed password from your old system.
  2. Write a script to populate this field where there's an email match between the old system and the new one. If the new system doesn't have users in it yet, then great, you'll be creating user records for everyone from the old system. Make sure you create a long, random, password for the initial processwire password on any new users you create and leave existing user passwords untouched. Store the hash from your system in the new field on the matching user and save any changes.
  3. You need a before hook on the session::login method. Use the name param (in $event->argument(0)) to match on emails if that's how you did it in the old system, if you have exactly one match, and this user has a non-empty value for your old password hash, use your existing pwd checking algorithm to authenticate them from the pass ($event->arguments(1)) parameter. If that works, the plaintext password they submitted to you is the correct password. Now set the PW password on that account using the plaintext password you just verified is correct AND delete the old password hash value.
  4. Now the correct password has been stored in the User's PW pass field, just exit the hook and PW should process the login as normal, or call the forceLogin method to log them in and do your own redirect.

Basically, as people log in, they will auto-convert their accounts over to PWs way of doing things. Once they convert, the login process just reverts to using PWs method.

Potential gotcha: more than one account in the PW system with the same email (if there are already accounts in there.)

After a reasonable period has elapsed, you could then deal with seemingly dormant accounts by emailing non-converted users and asking them to login (or otherwise handle them as appropriate.)

Hope that helps.

  • Like 4
Link to comment
Share on other sites

That's really good, thanks for the suggestions! I'm going to keep that as a potential way. I like it, thinking outside the box. ? 

My somewhat liazier solution is simply to add a field to the user template: Legacy, Legacy converted, and New. If A Legacy user attempts a login it simply sends them to the password reset page. And when they do they become Legacy converted.

Your way is far slicker so I'll present the client with both options.

  • Like 1
Link to comment
Share on other sites

I had to do this just the other week. We had an old CMSMS site that we'd moved to PW.

We had a db table with the old user names and passwords in which we stuck on the new site, and then just created our own login page which first checked to see if we had the user in PW already. If the user isn't already in PW then check the password against the old table; If it matches then use that information to add a new user to PW. The users don't really notice that anything has changed.

Here's the code I used for that - you'll have to adapt to your circumstances of course but it worked well for our move.

if ($input->post('ml_name')) {

    // when processing form (POST request), check to see if token is present
	// (we have a CSRF field on our login form)

    if ($session->CSRF->hasValidToken()) {
        // form submission is valid
        // okay to process
    } else {
        // form submission is NOT valid
        throw new WireException('CSRF check failed!');
    }

    $ml_name = $sanitizer->name($input->post('ml_name'));
    $ml_pass = $input->post('ml_pass');

	// dont allow the guest username
	if ($ml_name === 'guest') {
         throw new WireException('Invalid username');
    };


    // do we have this user in PW already?
    $u_exists = $users->get("$ml_name");

    if ($u_exists->id) {

        // user exists
        // lets try and log them in
        try {

            if ($session->login($ml_name, $ml_pass)) {
                $session->redirect('/');
            } else {
                $ml_feedback = 'Unknown details.';
            }
        } catch (WireException $e) {
            // show some error messages:
            // $e->getMessage();
        }
    } else {

        // ok - well do we have this user in the old CMS table?
        $query = $this->database->prepare("SELECT *
        FROM `cms_module_feusers_users` WHERE username = :login_name LIMIT 1;");

        try {
            $query->execute(['login_name' => $ml_name]);
        } catch (PDOException $e) {
            die ('Error querying table : ' . $e->getMessage());
        }

            // we've got a user from the old table
            if($query && $row=$query->fetch()) {

                $ml_feedback='Is in old table';

                $hash=$row['password'];

                // handily the old auth just uses password_verify
                if(password_verify($ml_pass, $hash)){

                    // Add this user to the PW users
                    $new_user=$users->add($ml_name);

                    if($new_user){

                        $new_user->pass=$ml_pass;
                        $new_user->addRole('members');

                        $new_user->save();

                        $log->save("new_members_site", $ml_name . " added as user");

                        $u = $session->login($ml_name, $ml_pass);
                        if($u) {
                            $session->redirect('/');
                        } else {
                            die("Error in logging in. Please contact admin.");
                        }
                        
                        $ml_feedback='new user added to PW';
                    }else{

                        $ml_feedback='Unable to add new user. Please let admin know';
                    }

                }else{
                    $ml_feedback='No matching records found.';
                }
            }else{
                $ml_feedback='No record found.';
            }

    }
}

and this is the login form that the we had on our new login page - this and the above was all in a single template.

  <form id="ml_login_form" class="ml_login_form" method="POST">
            <?php
            echo $session->CSRF->renderInput();
            ?>

            <label for="ml_name">Username</label>
            <input id="ml_name" name="ml_name" type="text" value="<?= $ml_name ?>" required>
            <label for="ml_pass">Password</label>
            <input id="ml_pass" name="ml_pass" type="password" value="<?= $ml_pass ?>" required>
            <div style="display: none;">
                <label for="ml_pass_bear">Password</label>
                <input id="ml_pass_bear" name="ml_pass_bear" type="text" value="">
            </div>
            <button type="submit" name="ml_submit" class="butt">Submit</button>
            <div class="ml_feedback"><?= $ml_feedback ?></div>
        </form>

 

  • Like 5
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...