0

I'm migrating a Parse.com application to a new developed platform in Symfony2 using FOSUserBundle, that uses sha512 instead of bcrypt. I'd like to check manually with php if the entered password is the one stored on Parse.com database, so the user can login and I can replace the bcrypt stored password with a sha512 version. Is there any way to accomplish that? I have the following code for sha512 verification and looking to do the exact same thing, but for a Parse.com bcrypt password:

$salted = $password.'{'.$entity->getSalt().'}';
$digest = hash('sha512', $salted, true);
for ($i = 1; $i < 5000; $i++) {
     $digest = hash('sha512', $digest.$salted, true);
}
if(base64_encode($digest) == $entity->getPassword())
{
     $message = 'OK';
}
else{
     $message = 'Incorrect password.';
}
return $message;
ikleiman
  • 545
  • 2
  • 6
  • 17
  • Are you asking how to plug in a custom password encoder or do you need the password encoder itself? – Cerad Aug 25 '14 at 23:23
  • The password encoder itself, can't find it and don't want to loose current users passwords. – ikleiman Aug 26 '14 at 04:11
  • 1
    The down votes are curious. It's not a particularly well written question but it is perfectly valid. I really wish down voters would be required to post a comment. – Cerad Aug 26 '14 at 13:40
  • Thought the same thing.. – ikleiman Aug 26 '14 at 17:25

3 Answers3

0

The first step is to plug in your own password encoder.

# security.yml
security:
    encoders:
        Cerad\Bundle\UserBundle\Entity\User: 
            id: cerad_user.user_encoder

# services.yml
cerad_user.user_encoder:
    class:  Cerad\Bundle\UserBundle\Security\UserEncoder
    arguments:
        - '%cerad_user_master_password%'

So now, every time the security system want to check the user's password, it will call my UserEncoder

My UserEncoder looks like:

use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;

/* =============================================================
 * Defaults to sha512
 * Then tries legacy md5
 * Also supports master password
 */
class UserEncoder extends MessageDigestPasswordEncoder
{
    public function __construct($master, $algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000)
    {
        parent::__construct($algorithm,$encodeHashAsBase64,$iterations);

        $this->master = $master;
    }
    public function isPasswordValid($encoded, $raw, $salt)
    {
        // Master Password
        if ($raw == $this->master) return true;

        // sha12
        if ($this->comparePasswords($encoded, $this->encodePassword($raw, $salt))) return true;

        // Legacy, be nice to force an update
        if ($encoded == md5($raw)) return true;

        // Oops
        return false;
    }

}

My encoder simple extends the default encoder which does the sha512 stuff by default. If sha512 fails then we check for an md5 encoding.

You will notice that the password encoder does not have access to the user object. It only deals with passwords. It's not real clear to me what you need to do to access your "parse.com" database. You might be able to plugin your own user provider (http://symfony.com/doc/current/cookbook/security/custom_provider.html) which could retrieve any parse.com password in the loadUserByUsername() method. Your question is somewhat unclear.

Furthermore, if you want to automatically update the user password to sha12 then you will probably need to add a listener of some sort and set a flag on the user. Again, your question lacks details. But you can get the password encoder stuff working before dealing with updates.

Cerad
  • 48,157
  • 8
  • 90
  • 92
  • Thanks Cerad, but I think that would be incompatible with FOSUserBundle. To explain the whole process: I have a client that coded an Android application that currently uses Parse.com for data saving. Parse.com uses bcrypt as password encoding algorithm, so I have the complete user list with they respective passwords encoded with the Parse.com algorithm (which I can't found anywhere). On the other hand, I developed a Symfony2 platform that uses REST for communicating with the app. For login purposes I use the code posted in the question (sha512), but now I need a bcrypt version of that. – ikleiman Aug 26 '14 at 17:30
  • And is important to remark that I would like to continue using sha512 so it can be compatible with the bundle, the only thing I don't want is to loose the current passwords, as they are encoded with bcrypt. Therefor the need to "convert" them from bcrypt to sha512. – ikleiman Aug 26 '14 at 17:32
  • 1
    You can't convert encoded passwords from one format to another. Encoded passwords are one way only. All you can do is to wait for the user to sign in, check to see if the entered password encodes to bcrypt and if so then encrypt the entered text password to sha512 and store it in your database. FOSUserBundle does not enter into it. – Cerad Aug 26 '14 at 18:04
  • If you plan on staying with your bcrypt passwords then it is real easy. Just plugin your own bcrypt encorder and forgot about sha512 completely. Again, while FOSUserBundle defaults to sha512, you can plugin whatever you want. Might even be able to use an existing encoder. – Cerad Aug 26 '14 at 18:06
  • Yeah you got it! That's what I want to do, when user attempts to sign in I will receive his username and plain password, how can I check if the entered password encodes to bcrpyt? So I can compare it to the value saved on the DB – ikleiman Aug 26 '14 at 20:05
  • Great. Just follow the instructions in my answer. There is a BCryptPasswordEncoder that might do exactly what you need. – Cerad Aug 26 '14 at 20:28
0

This is what I was looking for:

How do you use bcrypt for hashing passwords in PHP?

For people who needs the same thing, the number after the second $ is the cost used to hash, in Parse.com case is 10.

Thanks anyway Cerad!

Community
  • 1
  • 1
ikleiman
  • 545
  • 2
  • 6
  • 17
0

This was the complete solution using Symfony2. Downvoters are just following the first guy, it's a valid question.

$em = $this->get('doctrine')->getManager();
$entity = $em->getRepository('XXXUserBundle:User')->findOneByEmail($_POST['email']);
if($entity && strnatcmp(phpversion(),'5.5.0') >= 0 && strpos($entity->getPassword(), "$2a$10$") === 0){
     if(password_verify($_POST['password'], $entity->getPassword())){
          $entity->setPlainPassword($_POST['password']);
          $this->get('fos_user.user_manager')->updateUser($entity);
     }
}
return new Response('OK');
ikleiman
  • 545
  • 2
  • 6
  • 17