Skip to content

Commit

Permalink
Merge pull request #2 from nicolasmure/multiple-encryptors-declaration
Browse files Browse the repository at this point in the history
multiple encryptors declaration
  • Loading branch information
Nicolas MURE committed Apr 7, 2016
2 parents 0d23155 + 795f81d commit d314eb2
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 91 deletions.
18 changes: 13 additions & 5 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@ public function getConfigTreeBuilder()

$rootNode
->children()
->scalarNode('secret')
->arrayNode('encryptors')
->isRequired()
->cannotBeEmpty()
->end()
->booleanNode('prefer_base64')
->defaultTrue()
->requiresAtLeastOneElement()
->prototype('array')
->children()
->scalarNode('secret')
->isRequired()
->cannotBeEmpty()
->end()
->booleanNode('prefer_base64')
->defaultTrue()
->end()
->end()
->end()
->end()
->end()
;
Expand Down
43 changes: 35 additions & 8 deletions DependencyInjection/NmureEncryptorExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Reference;

/**
* This is the class that loads and manages your bundle configuration.
Expand All @@ -14,6 +14,13 @@
*/
class NmureEncryptorExtension extends Extension
{
/**
* Indicates if the compilation of the container is required.
*
* @var boolean
*/
private $isCompilationRequired;

/**
* {@inheritdoc}
*/
Expand All @@ -22,15 +29,35 @@ public function load(array $configs, ContainerBuilder $container)
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);

$container->setParameter('nmure_encryptor.secret', $config['secret']);
foreach ($config['encryptors'] as $name => $settings) {
$this->configureEncryptor($name, $settings, $container);
}

// resolving decorated services if needed
if ($this->isCompilationRequired) {
$container->compile();
}
}

/**
* @param string $name Encryptor's name
* @param array $settings Encryptor's settings
* @param ContainerBuilder $container
*/
private function configureEncryptor($name, array $settings, ContainerBuilder $container)
{
$serviceName = sprintf('nmure_encryptor.%s', $name);
$container->register($serviceName, 'Nmure\EncryptorBundle\Encryptor\Encryptor')
->addArgument($settings['secret']);

$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');
if ($settings['prefer_base64']) {
$decoratorServiceName = sprintf('nmure_encryptor.adapter.base64.%s', $name);
$container->register($decoratorServiceName, 'Nmure\EncryptorBundle\Adapter\Base64Adapter')
->addArgument(new Reference(sprintf('%s.inner', $decoratorServiceName)))
->setPublic(false)
->setDecoratedService($serviceName);

if ($config['prefer_base64']) {
$container->setAlias('nmure_encryptor.encryptor', 'nmure_encryptor.adapter.base64');
} else {
$container->setAlias('nmure_encryptor.encryptor', 'nmure_encryptor.encryptor.original');
$this->isCompilationRequired = true;
}
}
}
33 changes: 16 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:

```bash
$ composer require nmure/encryptor-bundle "~0.1.0"
$ composer require nmure/encryptor-bundle "~0.2.0"
```

This command requires you to have Composer installed globally, as explained
Expand Down Expand Up @@ -45,17 +45,25 @@ Add the following configuration to your `config.yml` file :
```yaml
# app/config/config.yml
nmure_encryptor:
secret: theSecretKeyGoesHere # should be a complex key defined in your parameters.yml file
prefer_base64: true # optional, default true. Indicates if the encrypted data should be converted to base64
encryptors:
my_encryptor:
secret: theSecretKeyGoesHere # should be a complex key defined in your parameters.yml file
# you can add as many encryptors as you want
my_other_encryptor:
secret: myOtherSecretKey # you should use one unique secret key by encryptor
prefer_base64: false # optional, default true.
# Indicates if the encrypted data should be converted to base64
```

## Usage
The encryptor is defined as a service under the `nmure_encryptor.encryptor` key.
You can access to the encryptors defined in the `config.yml` file by specifying your encryptor's name, e.g. :
accessing to `nmure_encryptor.my_encryptor` will return the encryptor defined under the `my_encryptor` key.

Simply access to this service and call the `encrypt` / `decrypt` functions :
All the encryptors are implementing the `Nmure\EncryptorBundle\Encryptor\EncryptorInterface`.
To use them, call the `encrypt` / `decrypt` functions :
```php
// from a controller :
$encryptor = $this->get('nmure_encryptor.encryptor');
$encryptor = $this->get('nmure_encryptor.my_encryptor');
$encrypted = $encryptor->encrypt('hello world');
// ...
$decrypted = $encryptor->decrypt($encrypted);
Expand All @@ -70,8 +78,8 @@ otherwise, your data won't be readable.

You can access to the initialization vector on the encryptor using these functions:
```php
string Encryptor::getIv();
void Encryptor::setIv(string $iv);
string EncryptorInterface::getIv();
void EncryptorInterface::setIv(string $iv);
```
Be sure to store the initialization vector used to crypt data along side to the crypted data
to be able to decrypt it later.
Expand All @@ -80,15 +88,6 @@ If the `prefer_base64` config setting is set to `true`, the encrypted data will
instead of staying a binary string.
The itinialization vector will also be converted to a base64 string.

## Services
This Bundle exposes the following services which are returning a `Nmure\EncryptorBundle\Encryptor\EncryptorInterface`:
- `nmure_encryptor.encryptor`: alias for `nmure_encryptor.encryptor.original` or `nmure_encryptor.adapter.base64`
(depends on the value of the `prefer_base64` config parameter).
- `nmure_encryptor.encryptor.original`: the original encryptor which returns encrypted data as a binary string
(`Nmure\EncryptorBundle\Encryptor\Encryptor`).
- `nmure_encryptor.adapter.base64`: the base64 adapter which returns encrypted data as a MIME base64 string
(`Nmure\EncryptorBundle\Adapter\Base64Adapter`).

## Informations
Useful informations about:
- [PHP's openssl](http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-instead-of "Using openssl_en/decrypt() in PHP instead of Mcrypt")
Expand Down
22 changes: 0 additions & 22 deletions Resources/config/services.xml

This file was deleted.

115 changes: 77 additions & 38 deletions Tests/DependencyInjection/NmureEncryptorExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,41 @@

class NmureEncryptorExtensionTest extends TestCase
{
/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testEncryptorsArrayMustBeDefined()
{
$loader = new NmureEncryptorExtension();
$config = array();
$loader->load(array($config), new ContainerBuilder());
}

/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testEncryptorsArrayMustNotBeEmpty()
{
$loader = new NmureEncryptorExtension();
$config = array(
'encryptors' => array(),
);
$loader->load(array($config), new ContainerBuilder());
}

/**
* @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
*/
public function testSecretMustNotBeEmpty()
{
$loader = new NmureEncryptorExtension();
$config = $this->getEmptySecretConfig();
$config = array(
'encryptors' => array(
'first_encryptor' => array(
'secret' => null
),
),
);
$loader->load(array($config), new ContainerBuilder());
}

Expand All @@ -25,65 +53,76 @@ public function testSecretMustNotBeEmpty()
public function testSecretMustBeDefined()
{
$loader = new NmureEncryptorExtension();
$config = $this->getEmptySecretConfig();
unset($config['secret']);
$config = array(
'encryptors' => array(
'first_encryptor' => array(),
),
);
$loader->load(array($config), new ContainerBuilder());
}

public function testValidConfiguration()
{
$configuration = new ContainerBuilder();
$loader = new NmureEncryptorExtension();
$config = $this->getValidConfig();
$config = array(
'encryptors' => array(
'first_encryptor' => array(
'secret' => 'iAmTheFirstSecretKey',
),
),
);
$loader->load(array($config), $configuration);

$this->assertEquals($configuration->getParameter('nmure_encryptor.secret'), 'iAmTheSecretKey');

$this->assertInstanceOf('Nmure\EncryptorBundle\Encryptor\EncryptorInterface', $configuration->get('nmure_encryptor.encryptor'));
$this->assertInstanceOf('Nmure\EncryptorBundle\Encryptor\EncryptorInterface', $configuration->get('nmure_encryptor.first_encryptor'));
// default setting
$this->assertInstanceOf('Nmure\EncryptorBundle\Adapter\Base64Adapter', $configuration->get('nmure_encryptor.encryptor'));
// assert same instance (alias)
$this->assertTrue($configuration->get('nmure_encryptor.encryptor') === $configuration->get('nmure_encryptor.adapter.base64'));
$this->assertInstanceOf('Nmure\EncryptorBundle\Adapter\Base64Adapter', $configuration->get('nmure_encryptor.first_encryptor'));
}

public function testPreferOriginalEncryptor()
{
$configuration = new ContainerBuilder();
$loader = new NmureEncryptorExtension();
$config = $this->getOriginalEncryptorConfig();
$config = array(
'encryptors' => array(
'first_encryptor' => array(
'secret' => 'iAmTheFirstSecretKey',
'prefer_base64' => false,
),
),
);
$loader->load(array($config), $configuration);

$this->assertInstanceOf('Nmure\EncryptorBundle\Encryptor\EncryptorInterface', $configuration->get('nmure_encryptor.encryptor'));
$this->assertInstanceOf('Nmure\EncryptorBundle\Encryptor\Encryptor', $configuration->get('nmure_encryptor.encryptor'));
// assert same instance (alias)
$this->assertTrue($configuration->get('nmure_encryptor.encryptor') === $configuration->get('nmure_encryptor.encryptor.original'));
$this->assertInstanceOf('Nmure\EncryptorBundle\Encryptor\EncryptorInterface', $configuration->get('nmure_encryptor.first_encryptor'));
$this->assertInstanceOf('Nmure\EncryptorBundle\Encryptor\Encryptor', $configuration->get('nmure_encryptor.first_encryptor'));
}

private function getEmptySecretConfig()
public function testMultipleEncryptorsDeclaration()
{
$yaml = <<<EOF
secret:
EOF;
$parser = new Parser();
return $parser->parse($yaml);
}
$configuration = new ContainerBuilder();
$loader = new NmureEncryptorExtension();
$config = array(
'encryptors' => array(
'first_encryptor' => array(
'secret' => 'iAmTheFirstSecretKey',
),
'second_encryptor' => array(
'secret' => 'iAmTheSecondSecretKey',
),
),
);
$loader->load(array($config), $configuration);

private function getValidConfig()
{
$yaml = <<<EOF
secret: iAmTheSecretKey
EOF;
$parser = new Parser();
return $parser->parse($yaml);
}
$first = $configuration->get('nmure_encryptor.first_encryptor');
$second = $configuration->get('nmure_encryptor.second_encryptor');

private function getOriginalEncryptorConfig()
{
$yaml = <<<EOF
secret: iAmTheSecretKey
prefer_base64: false
EOF;
$parser = new Parser();
return $parser->parse($yaml);
// assert two encryptor instances of the same class
$this->assertFalse($first === $second);
$this->assertTrue(get_class($first) === get_class($second));

// assert secret key is different
$data = 'Lorem ipsum dolor';
$second->setIv($first->getIv());
$this->assertNotEquals($first->encrypt($data), $second->encrypt($data));
}
}
1 change: 0 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
<directory>./</directory>
<exclude>
<directory>./build</directory>
<directory>./Resources</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
Expand Down

0 comments on commit d314eb2

Please sign in to comment.