2

I'm learning Symfony2 by moving some wordpress blog to Symfony. I'm stuck with login procedure. Wordpress uses non standard password hashing like $P$.... and I want to check users against old password hash when they login and when password is correct, rehash it to bcrypt. So far I created custome encoder class to use with symfony security mechanism.

<?php
namespace Pkr\BlogUserBundle\Service\Encoder;

use PHPassLib\Application\Context;
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder;
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
use Symfony\Component\Security\Core\Util\SecureRandom;

class WpTransitionalEncoder implements PasswordEncoderInterface
{

    public function __construct($cost = 13)
    {
        $secure = new SecureRandom();
        $this->_bcryptEncoder = new BCryptPasswordEncoder($secure, $cost);
    }

    public function isPasswordValid($encoded, $raw, $salt)
    {
        if (preg_match('^\$P\$', $encoded)) {
            $context = new Context();
            $context->addConfig('portable');
            return $context->verify($raw, $encoded);
        }
        return $this->_bcryptEncoder->isPasswordValid($encoded, $raw, $salt);
    }

    public function encodePassword($raw, $salt)
    {
        return $this->_bcryptEncoder->encodePassword($raw, $salt);
    }
}

I'm using it as a service:

#/src/Pkr/BlogUserBundle/Resources/config/services.yml
services:
    pkr_blog_user.wp_transitional_encoder:
        class: Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder

And in security.yml:

#/app/config/security.yml
security:
encoders:
    Pkr\BlogUserBoundle\Entity\User:
        id:   pkr_blog_user.wp_transitional_encoder
        cost: 15

My questions are:

How do I pass parameters to my encoder service form within security.yml?

I'm asking because cost: 15 does not work.

Where should I put password hash update logic? I was thinking that maby just after password validation something like this:

public function isPasswordValid($encoded, $raw, $salt)
{
    if (preg_match('^\$P\$', $encoded)) {
        $context = new Context();
        $context->addConfig('portable');
        $isValid = $context->verify($raw, $encoded);
        if ($isValid) {
            // put logic here...
        }
        return $isValid;
    }
    return $this->_bcryptEncoder->isPasswordValid($encoded, $raw, $salt);
}

but it seem somehow like wrong place for it. So what is the right way?

1 Answer 1

2

I'll answer my own question.

I placed parameters for my encoder service inside config.yml

pkr_blog_user:
    password_encoder:
        cost: 17

They will be passed to my bundle extension class:

# /src/Pkr/BlogUserBundle/DependencyInjection/PkrBlogUserExtension.php
namespace Pkr\BlogUserBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class PkrBlogUserExtension extends Extension
{
    /**
    * {@inheritDoc}
    */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');

        if ($config['password_encoder']['cost'] < 10) {
            $config['password_encoder']['cost'] = sprintf('%02d', $config['password_encoder']['cost']);
        }
        $container->setParameter('pkr_blog_user.wp_transitional_encoder.cost', $config['password_encoder']['cost']);

    }
}

I found out that I could use my own authentication success handler so there is a good place to put password rehash logic. Unfortunately when using custom handler symfony2 won't pass config to class constructor but I found a way to make it work. I described it here:

https://stackoverflow.com/a/15988399/1089412

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.