├── .gitignore ├── .travis.yml ├── DependencyInjection ├── Compiler │ └── SecurityEncoderFactoryPass.php ├── Configuration.php └── FOSAdvancedEncoderExtension.php ├── FOSAdvancedEncoderBundle.php ├── README.md ├── Resources ├── config │ └── encoder.xml ├── doc │ └── index.md └── meta │ └── LICENSE ├── Security └── Encoder │ ├── EncoderAwareInterface.php │ └── EncoderFactory.php ├── Tests ├── DependencyInjection │ ├── Compiler │ │ └── SecurityEncoderFactoryPassTest.php │ └── FOSAdvancedEncoderExtensionTest.php └── Security │ └── Encoder │ └── EncoderFactoryTest.php ├── composer.json └── phpunit.xml.dist /.gitignore: -------------------------------------------------------------------------------- 1 | phpunit.xml 2 | vendor/ 3 | composer.lock 4 | composer.phar 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - hhvm 9 | 10 | matrix: 11 | include: 12 | - php: 5.5 13 | env: SYMFONY_VERSION='2.3.*' 14 | - php: 5.5 15 | env: SYMFONY_VERSION='2.5.*@dev' 16 | 17 | before_script: 18 | - sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require --no-update symfony/symfony=$SYMFONY_VERSION; fi;' 19 | - composer install --no-interaction --prefer-source 20 | 21 | 22 | script: phpunit -v --coverage-clover=coverage.clover 23 | 24 | after_script: 25 | - wget https://scrutinizer-ci.com/ocular.phar 26 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 27 | 28 | notifications: 29 | email: 30 | - friendsofsymfony-dev@googlegroups.com 31 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/SecurityEncoderFactoryPass.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\DependencyInjection\Compiler; 13 | 14 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Alias; 17 | 18 | /** 19 | * Overwrites the existing encoder factory and injects the old one in the FOSAdvancedEncoderBundle implementation 20 | * 21 | * @author Christophe Coevoet 22 | */ 23 | class SecurityEncoderFactoryPass implements CompilerPassInterface 24 | { 25 | public function process(ContainerBuilder $container) 26 | { 27 | if ($container->hasAlias('security.encoder_factory')) { 28 | // security.encoder_factory is an alias. 29 | // Register a private alias for this service to inject it as the parent 30 | $container->setAlias('fos_advanced_encoder.encoder_factory.parent', new Alias((string) $container->getAlias('security.encoder_factory'), false)); 31 | } else { 32 | // security.encoder_factory is a definition. 33 | // Register it again as a private service to inject it as the parent 34 | $definition = $container->getDefinition('security.encoder_factory'); 35 | $definition->setPublic(false); 36 | $container->setDefinition('fos_advanced_encoder.encoder_factory.parent', $definition); 37 | } 38 | 39 | $container->setAlias('security.encoder_factory', 'fos_advanced_encoder.encoder_factory'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\DependencyInjection; 13 | 14 | use Symfony\Component\Config\Definition\Builder\TreeBuilder; 15 | use Symfony\Component\Config\Definition\ConfigurationInterface; 16 | 17 | /** 18 | * This class contains the configuration information for the bundle 19 | * 20 | * This information is solely responsible for how the different configuration 21 | * sections are normalized, and merged. 22 | * 23 | * @author Christophe Coevoet 24 | */ 25 | class Configuration implements ConfigurationInterface 26 | { 27 | /** 28 | * Generates the configuration tree. 29 | * 30 | * @return TreeBuilder 31 | */ 32 | public function getConfigTreeBuilder() 33 | { 34 | $treeBuilder = new TreeBuilder(); 35 | $rootNode = $treeBuilder->root('fos_advanced_encoder'); 36 | 37 | $rootNode 38 | ->fixXmlConfig('encoder') 39 | ->children() 40 | ->arrayNode('encoders') 41 | ->useAttributeAsKey('name') 42 | ->prototype('array') 43 | ->canBeUnset() 44 | ->performNoDeepMerging() 45 | ->beforeNormalization() 46 | ->ifString() 47 | ->then(function ($v) { return array('algorithm' => $v); }) 48 | ->end() 49 | ->children() 50 | ->scalarNode('algorithm')->cannotBeEmpty()->end() 51 | ->booleanNode('ignore_case')->defaultFalse()->end() 52 | ->booleanNode('encode_as_base64')->defaultTrue()->end() 53 | ->scalarNode('iterations')->defaultValue(5000)->end() 54 | ->scalarNode('cost')->defaultValue(13)->end() 55 | ->scalarNode('hash_algorithm')->defaultValue('sha512')->end() 56 | ->scalarNode('key_length')->defaultValue(40)->end() 57 | ->scalarNode('id')->end() 58 | ->end() 59 | ->end() 60 | ->end() 61 | ->end() 62 | ; 63 | 64 | return $treeBuilder; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /DependencyInjection/FOSAdvancedEncoderExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\DependencyInjection; 13 | 14 | use Symfony\Component\Config\FileLocator; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; 17 | use Symfony\Component\DependencyInjection\Parameter; 18 | use Symfony\Component\DependencyInjection\Reference; 19 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; 20 | 21 | class FOSAdvancedEncoderExtension extends Extension 22 | { 23 | public function load(array $configs, ContainerBuilder $container) 24 | { 25 | $configuration = new Configuration(); 26 | $config = $this->processConfiguration($configuration, $configs); 27 | 28 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 29 | $loader->load('encoder.xml'); 30 | 31 | $encoders = array(); 32 | foreach ($config['encoders'] as $name => $encoder) { 33 | $encoders[$name] = $this->createEncoder($encoder); 34 | } 35 | 36 | $container->getDefinition('fos_advanced_encoder.encoder_factory')->replaceArgument(1, $encoders); 37 | } 38 | 39 | private function createEncoder($config) 40 | { 41 | // a custom encoder service 42 | if (isset($config['id'])) { 43 | return new Reference($config['id']); 44 | } 45 | 46 | // plaintext encoder 47 | if ('plaintext' === $config['algorithm']) { 48 | $arguments = array($config['ignore_case']); 49 | 50 | return array( 51 | 'class' => new Parameter('security.encoder.plain.class'), 52 | 'arguments' => $arguments, 53 | ); 54 | } 55 | 56 | // bcrypt encoder 57 | if ('bcrypt' === $config['algorithm']) { 58 | $arguments = array($config['cost']); 59 | 60 | return array( 61 | 'class' => new Parameter('security.encoder.bcrypt.class'), 62 | 'arguments' => $arguments, 63 | ); 64 | } 65 | 66 | // pbkdf2 encoder 67 | if ('pbkdf2' === $config['algorithm']) { 68 | $arguments = array( 69 | $config['hash_algorithm'], 70 | $config['encode_as_base64'], 71 | $config['iterations'], 72 | $config['key_length'], 73 | ); 74 | 75 | return array( 76 | 'class' => new Parameter('security.encoder.pbkdf2.class'), 77 | 'arguments' => $arguments, 78 | ); 79 | } 80 | 81 | // message digest encoder 82 | $arguments = array( 83 | $config['algorithm'], 84 | $config['encode_as_base64'], 85 | $config['iterations'], 86 | ); 87 | 88 | return array( 89 | 'class' => new Parameter('security.encoder.digest.class'), 90 | 'arguments' => $arguments, 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /FOSAdvancedEncoderBundle.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle; 13 | 14 | use Symfony\Component\HttpKernel\Bundle\Bundle; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use FOS\AdvancedEncoderBundle\DependencyInjection\Compiler\SecurityEncoderFactoryPass; 17 | 18 | class FOSAdvancedEncoderBundle extends Bundle 19 | { 20 | public function build(ContainerBuilder $container) 21 | { 22 | parent::build($container); 23 | 24 | $container->addCompilerPass(new SecurityEncoderFactoryPass()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FOSAdvancedEncoderBundle 2 | ======================== 3 | 4 | The FOSAdvancedEncoderBundle adds support for changing the encoder on an 5 | instance basis instead of using the same encoder for all instances of a class. 6 | 7 | [![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSAdvancedEncoderBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSAdvancedEncoderBundle) 8 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSAdvancedEncoderBundle/badges/quality-score.png?s=dccf1912b87c5739d73100a09997fcf3204f551b)](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSAdvancedEncoderBundle/) 9 | [![Code Coverage](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSAdvancedEncoderBundle/badges/coverage.png?s=27e29c5ea428937a7527343676ccc304281b049f)](https://scrutinizer-ci.com/g/FriendsOfSymfony/FOSAdvancedEncoderBundle/) 10 | 11 | > **Note:** this bundle is not necessary as of Symfony 2.5. The same feature is available in the Security component itself. 12 | 13 | Documentation 14 | ------------- 15 | 16 | The bulk of the documentation is stored in the `Resources/doc/index.md` 17 | file in this bundle: 18 | 19 | [Read the Documentation](https://github.com/friendsofsymfony/FOSAdvancedEncoderBundle/blob/master/Resources/doc/index.md) 20 | 21 | Installation 22 | ------------ 23 | 24 | All the installation instructions are located in [documentation](Resources/doc/index.md). 25 | 26 | License 27 | ------- 28 | 29 | This bundle is under the MIT license. See the complete license in the bundle: [Resources/meta/LICENSE](Resources/meta/LICENSE) 30 | 31 | Reporting an issue or a feature request 32 | --------------------------------------- 33 | 34 | Issues and feature requests are tracked in the [Github issue tracker](https://github.com/friendsofsymfony/FOSAdvancedEncoderBundle/issues). 35 | 36 | When reporting a bug, it may be a good idea to reproduce it in a basic project 37 | built using the [Symfony Standard Edition](https://github.com/symfony/symfony-standard) 38 | to allow developers of the bundle to reproduce the issue by simply cloning it 39 | and following some steps. 40 | -------------------------------------------------------------------------------- /Resources/config/encoder.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Resources/doc/index.md: -------------------------------------------------------------------------------- 1 | FOSAdvancedEncoderBundle 2 | ======================== 3 | 4 | ## Features 5 | 6 | The FOSAdvancedEncoderBundle adds support for changing the encoder on an 7 | instance basis instead of using the same encoder for all instances of a class. 8 | 9 | ## Installation 10 | 11 | 12 | ### Add FOSAdvancedEncoderBundle to your project 13 | 14 | The recommended way to install the bundle is through Composer. 15 | 16 | ```bash 17 | $ composer require 'friendsofsymfony/advanced-encoder-bundle:~1.0' 18 | ``` 19 | 20 | ### Add FOSAdvancedEncoderBundle to your application kernel 21 | 22 | ```php 23 | // app/AppKernel.php 24 | public function registerBundles() 25 | { 26 | return array( 27 | // ... 28 | new FOS\AdvancedEncoderBundle\FOSAdvancedEncoderBundle(), 29 | // ... 30 | ); 31 | } 32 | ``` 33 | 34 | ## Configure the encoders 35 | 36 | You now need to configure the encoders available for the factory used by 37 | the bundle. They are identified by a name used to reference them later. The 38 | configuration keys available are exactly the same than for the SecurityBundle 39 | encoder configuration. 40 | 41 | ```yaml 42 | fos_advanced_encoder: 43 | encoders: 44 | my_encoder: 45 | algorithm: sha512 46 | iterations: 5000 47 | encode_as_base64: true 48 | another_encoder: sha1 # shortcut for the previous way 49 | my_plain_encoder: 50 | algorithm: plaintext 51 | ignore_case: false 52 | my_custom_encoder: 53 | id: some_service_id 54 | ``` 55 | 56 | ## Use the bundle 57 | 58 | You can now implement the `FOS\AdvancedEncoderBundle\Security\Encoder\EncoderAwareInterface` 59 | interface in your User class. It consist of a single method `getEncoderName` 60 | returning the name of an encoder defined previously or `null`. 61 | 62 | If you return `null`, the standard factory of SecurityBundle will be used 63 | (as if you were not using the interface at all). Otherwise, the encoder will 64 | be retrieved by its name. 65 | -------------------------------------------------------------------------------- /Resources/meta/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Christophe Coevoet 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Security/Encoder/EncoderAwareInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\Security\Encoder; 13 | 14 | /** 15 | * @author Christophe Coevoet 16 | */ 17 | interface EncoderAwareInterface 18 | { 19 | /** 20 | * Gets the name of the encoder used to encode the password. 21 | * 22 | * If the method returns null, the standard way to retrieve the encoder 23 | * will be used instead. 24 | * 25 | * @return string 26 | */ 27 | public function getEncoderName(); 28 | } 29 | -------------------------------------------------------------------------------- /Security/Encoder/EncoderFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\Security\Encoder; 13 | 14 | use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; 15 | use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; 16 | 17 | /** 18 | * @author Christophe Coevoet 19 | */ 20 | class EncoderFactory implements EncoderFactoryInterface 21 | { 22 | private $genericFactory; 23 | private $encoders; 24 | 25 | /** 26 | * Constructor. 27 | * 28 | * @param EncoderFactoryInterface $genericFactory 29 | * @param array $encoders 30 | */ 31 | public function __construct(EncoderFactoryInterface $genericFactory, array $encoders) 32 | { 33 | $this->genericFactory = $genericFactory; 34 | $this->encoders = $encoders; 35 | } 36 | 37 | public function getEncoder($user) 38 | { 39 | if (!$user instanceof EncoderAwareInterface) { 40 | return $this->genericFactory->getEncoder($user); 41 | } 42 | 43 | $encoderName = $user->getEncoderName(); 44 | 45 | if (null === $encoderName) { 46 | return $this->genericFactory->getEncoder($user); 47 | } 48 | 49 | if (!isset($this->encoders[$encoderName])) { 50 | throw new \RuntimeException(sprintf('The encoder named "%s" does not exist in the advanced encoder factory. Check your configuration.', $encoderName)); 51 | } 52 | 53 | if (!$this->encoders[$encoderName] instanceof PasswordEncoderInterface) { 54 | $this->encoders[$encoderName] = $this->createEncoder($this->encoders[$encoderName]); 55 | } 56 | 57 | return $this->encoders[$encoderName]; 58 | } 59 | 60 | /** 61 | * Creates an encoder for the given algorithm. 62 | * 63 | * @param array $config 64 | * @return PasswordEncoderInterface 65 | */ 66 | protected function createEncoder(array $config) 67 | { 68 | if (!isset($config['class'])) { 69 | throw new \InvalidArgumentException(sprintf('"class" must be set in %s.', json_encode($config))); 70 | } 71 | if (!isset($config['arguments'])) { 72 | throw new \InvalidArgumentException(sprintf('"arguments" must be set in %s.', json_encode($config))); 73 | } 74 | 75 | $reflection = new \ReflectionClass($config['class']); 76 | 77 | return $reflection->newInstanceArgs($config['arguments']); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/Compiler/SecurityEncoderFactoryPassTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\Tests\DependencyInjection\Compiler; 13 | 14 | use FOS\AdvancedEncoderBundle\DependencyInjection\Compiler\SecurityEncoderFactoryPass; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Definition; 17 | 18 | class SecurityEncoderFactoryPassTest extends \PHPUnit_Framework_TestCase 19 | { 20 | private $container; 21 | private $pass; 22 | 23 | public function setUp() 24 | { 25 | $this->container = new ContainerBuilder(); 26 | $this->pass = new SecurityEncoderFactoryPass(); 27 | } 28 | 29 | public function testShouldComposeAlias() 30 | { 31 | $this->container->setDefinition('security.encoder_factory.real', new Definition()); 32 | $this->container->setAlias('security.encoder_factory', 'security.encoder_factory.real'); 33 | 34 | $this->pass->process($this->container); 35 | 36 | $this->assertServiceHasAlias('security.encoder_factory.real', 'fos_advanced_encoder.encoder_factory.parent'); 37 | $this->assertFalse($this->container->getAlias('fos_advanced_encoder.encoder_factory.parent')->isPublic()); 38 | $this->assertServiceHasAlias('fos_advanced_encoder.encoder_factory', 'security.encoder_factory'); 39 | } 40 | 41 | public function testShouldComposeDefinition() 42 | { 43 | $this->container->setDefinition('security.encoder_factory', $originalDefinition = new Definition()); 44 | 45 | $this->pass->process($this->container); 46 | 47 | $newDefinition = $this->container->getDefinition('fos_advanced_encoder.encoder_factory.parent'); 48 | $this->assertFalse($newDefinition->isPublic()); 49 | $this->assertSame($originalDefinition, $newDefinition); 50 | 51 | $this->assertServiceHasAlias('fos_advanced_encoder.encoder_factory', 'security.encoder_factory'); 52 | } 53 | 54 | private function assertServiceHasAlias($serviceId, $aliasId) 55 | { 56 | $this->assertEquals($serviceId, (string) $this->container->getAlias($aliasId), sprintf('Service "%s" has alias "%s"', $serviceId, $aliasId)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/FOSAdvancedEncoderExtensionTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\Tests\DependencyInjection; 13 | 14 | use FOS\AdvancedEncoderBundle\DependencyInjection\FOSAdvancedEncoderExtension; 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\DependencyInjection\Definition; 17 | use Symfony\Component\DependencyInjection\Parameter; 18 | use Symfony\Component\DependencyInjection\Reference; 19 | 20 | class FOSAdvancedEncoderExtensionTest extends \PHPUnit_Framework_TestCase 21 | { 22 | public function testLoadEmptyConfiguration() 23 | { 24 | $container = new ContainerBuilder(); 25 | $loader = new FOSAdvancedEncoderExtension(); 26 | $loader->load(array(array()), $container); 27 | $this->assertTrue($container->hasDefinition('fos_advanced_encoder.encoder_factory')); 28 | } 29 | 30 | public function testLoadFullConfiguration() 31 | { 32 | $container = new ContainerBuilder(); 33 | $loader = new FOSAdvancedEncoderExtension(); 34 | $config = array( 35 | 'encoders' => array( 36 | 'sha1' => 'sha1', 37 | 'md5' => array( 38 | 'algorithm' => 'md5', 39 | 'iterations' => 10, 40 | 'encode_as_base64' => false, 41 | ), 42 | 'plaintext' => 'plaintext', 43 | 'custom' => array( 44 | 'id' => 'acme_demo.encoder', 45 | ), 46 | 'bcrypt' => array( 47 | 'algorithm' => 'bcrypt', 48 | 'cost' => 16, 49 | ), 50 | 'pbkdf2' => array( 51 | 'algorithm' => 'pbkdf2', 52 | 'hash_algorithm' => 'sha512', 53 | 'encode_as_base64' => false, 54 | 'iterations' => 2, 55 | 'key_length' => 40, 56 | ), 57 | ), 58 | ); 59 | $loader->load(array($config), $container); 60 | $this->assertTrue($container->hasDefinition('fos_advanced_encoder.encoder_factory')); 61 | $this->assertDefinitionConstructorArguments( 62 | $container->getDefinition('fos_advanced_encoder.encoder_factory'), 63 | array( 64 | new Reference('fos_advanced_encoder.encoder_factory.parent'), 65 | array( 66 | 'sha1' => array( 67 | 'class' => new Parameter('security.encoder.digest.class'), 68 | 'arguments' => array('sha1', true, 5000), 69 | ), 70 | 'md5' => array( 71 | 'class' => new Parameter('security.encoder.digest.class'), 72 | 'arguments' => array('md5', false, 10), 73 | ), 74 | 'plaintext' => array( 75 | 'class' => new Parameter('security.encoder.plain.class'), 76 | 'arguments' => array(false), 77 | ), 78 | 'custom' => new Reference('acme_demo.encoder'), 79 | 'bcrypt' => array( 80 | 'class' => new Parameter('security.encoder.bcrypt.class'), 81 | 'arguments' => array(16), 82 | ), 83 | 'pbkdf2' => array( 84 | 'class' => new Parameter('security.encoder.pbkdf2.class'), 85 | 'arguments' => array('sha512', false, 2, 40), 86 | ), 87 | ) 88 | ) 89 | ); 90 | } 91 | 92 | private function assertDefinitionConstructorArguments(Definition $definition, array $args) 93 | { 94 | $this->assertEquals($args, $definition->getArguments(), "Expected and actual DIC Service constructor arguments of definition '".$definition->getClass()."' don't match."); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Tests/Security/Encoder/EncoderFactoryTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace FOS\AdvancedEncoderBundle\Tests\Security\Encoder; 13 | 14 | use FOS\AdvancedEncoderBundle\Security\Encoder\EncoderAwareInterface; 15 | use FOS\AdvancedEncoderBundle\Security\Encoder\EncoderFactory; 16 | use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; 17 | use Symfony\Component\Security\Core\User\UserInterface; 18 | 19 | class EncoderFactoryTest extends \PHPUnit_Framework_TestCase 20 | { 21 | public function testGetEncoderWithMessageDigestEncoder() 22 | { 23 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 24 | $innerFactory->expects($this->never()) 25 | ->method('getEncoder') 26 | ; 27 | 28 | $factory = new EncoderFactory($innerFactory, array('test' => array( 29 | 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', 30 | 'arguments' => array('sha512', true, 5), 31 | ))); 32 | 33 | $user = $this->getMock('FOS\AdvancedEncoderBundle\Tests\Security\Encoder\StubUserInterface'); 34 | $user->expects($this->once()) 35 | ->method('getEncoderName') 36 | ->will($this->returnValue('test')) 37 | ; 38 | $expectedEncoder = new MessageDigestPasswordEncoder('sha512', true, 5); 39 | 40 | $this->assertEquals($expectedEncoder, $factory->getEncoder($user)); 41 | } 42 | 43 | /** 44 | * @expectedException InvalidArgumentException 45 | */ 46 | public function testGetEncoderWithMissingClass() 47 | { 48 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 49 | $innerFactory->expects($this->never()) 50 | ->method('getEncoder') 51 | ; 52 | 53 | $factory = new EncoderFactory($innerFactory, array('test' => array( 54 | 'arguments' => array('sha512', true, 5), 55 | ))); 56 | 57 | $user = $this->getMock('FOS\AdvancedEncoderBundle\Tests\Security\Encoder\StubUserInterface'); 58 | $user->expects($this->once()) 59 | ->method('getEncoderName') 60 | ->will($this->returnValue('test')) 61 | ; 62 | 63 | $factory->getEncoder($user); 64 | } 65 | 66 | /** 67 | * @expectedException InvalidArgumentException 68 | */ 69 | public function testGetEncoderWithMissingArguments() 70 | { 71 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 72 | $innerFactory->expects($this->never()) 73 | ->method('getEncoder') 74 | ; 75 | 76 | $factory = new EncoderFactory($innerFactory, array('test' => array( 77 | 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', 78 | ))); 79 | 80 | $user = $this->getMock('FOS\AdvancedEncoderBundle\Tests\Security\Encoder\StubUserInterface'); 81 | $user->expects($this->once()) 82 | ->method('getEncoderName') 83 | ->will($this->returnValue('test')) 84 | ; 85 | 86 | $factory->getEncoder($user); 87 | } 88 | 89 | public function testGetEncoderWithService() 90 | { 91 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 92 | $innerFactory->expects($this->never()) 93 | ->method('getEncoder') 94 | ; 95 | 96 | $encoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); 97 | $factory = new EncoderFactory($innerFactory, array( 98 | 'test' => $encoder, 99 | )); 100 | 101 | $user = $this->getMock('FOS\AdvancedEncoderBundle\Tests\Security\Encoder\StubUserInterface'); 102 | $user->expects($this->once()) 103 | ->method('getEncoderName') 104 | ->will($this->returnValue('test')) 105 | ; 106 | 107 | $this->assertSame($encoder, $factory->getEncoder($user)); 108 | } 109 | 110 | public function testGetEncoderWithNullName() 111 | { 112 | $user = $this->getMock('FOS\AdvancedEncoderBundle\Tests\Security\Encoder\StubUserInterface'); 113 | $user->expects($this->once()) 114 | ->method('getEncoderName') 115 | ->will($this->returnValue(null)) 116 | ; 117 | 118 | $encoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); 119 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 120 | $innerFactory->expects($this->once()) 121 | ->method('getEncoder') 122 | ->with($this->equalTo($user)) 123 | ->will($this->returnValue($encoder)) 124 | ; 125 | 126 | $factory = new EncoderFactory($innerFactory, array('test' => array( 127 | 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', 128 | 'arguments' => array('sha512', true, 5), 129 | ))); 130 | 131 | $this->assertSame($encoder, $factory->getEncoder($user)); 132 | } 133 | 134 | public function testGetEncoderWithStandardUser() 135 | { 136 | $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); 137 | $encoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); 138 | 139 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 140 | $innerFactory->expects($this->once()) 141 | ->method('getEncoder') 142 | ->with($this->equalTo($user)) 143 | ->will($this->returnValue($encoder)) 144 | ; 145 | 146 | $factory = new EncoderFactory($innerFactory, array('test' => array( 147 | 'class' => 'Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder', 148 | 'arguments' => array('sha512', true, 5), 149 | ))); 150 | 151 | $this->assertSame($encoder, $factory->getEncoder($user)); 152 | } 153 | 154 | /** 155 | * @expectedException RuntimeException 156 | */ 157 | public function testGetEncoderWithInvalidName() 158 | { 159 | $innerFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); 160 | $innerFactory->expects($this->never()) 161 | ->method('getEncoder') 162 | ; 163 | 164 | $encoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); 165 | $factory = new EncoderFactory($innerFactory, array( 166 | 'test' => $encoder, 167 | )); 168 | 169 | $user = $this->getMock('FOS\AdvancedEncoderBundle\Tests\Security\Encoder\StubUserInterface'); 170 | $user->expects($this->once()) 171 | ->method('getEncoderName') 172 | ->will($this->returnValue('foo')) 173 | ; 174 | 175 | $factory->getEncoder($user); 176 | } 177 | } 178 | 179 | interface StubUserInterface extends UserInterface, EncoderAwareInterface {} 180 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "friendsofsymfony/advanced-encoder-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Symfony2 bundle adding a way to specify the encoder on a user instance basis", 5 | "keywords": ["Symfony2", "security", "encoder"], 6 | "homepage": "https://github.com/friendsofsymfony/FOSAdvancedEncoderBundle", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Christophe Coevoet", 11 | "email": "stof@notk.org" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=5.3.2", 16 | "symfony/framework-bundle": "~2.1", 17 | "symfony/security-bundle": "~2.1" 18 | }, 19 | "extra": { 20 | "branch-alias": { 21 | "dev-master": "1.1.x-dev" 22 | } 23 | }, 24 | "autoload": { 25 | "psr-4": { "FOS\\AdvancedEncoderBundle\\": "" } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./Tests 7 | 8 | 9 | 10 | 11 | 12 | ./ 13 | 14 | ./Resources 15 | ./Tests 16 | ./vendor 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------