From c0c89724b04632fa68e08e482fe7c29c28cc6a44 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 5 Jul 2012 17:51:07 +0200 Subject: [PATCH] simplified the Prng code --- .../Security/DoctrineSeedProvider.php | 68 ------------------- .../EventListener/PrngSchemaListener.php | 33 --------- .../Bridge/Doctrine/Security/PrngSchema.php | 43 ------------ .../Security/DoctrineSeedProviderTest.php | 48 ------------- .../Command/InitPrngCommand.php | 57 ---------------- .../DependencyInjection/MainConfiguration.php | 1 - .../DependencyInjection/SecurityExtension.php | 4 -- .../Resources/config/security.xml | 2 +- .../Fixtures/php/container1.php | 1 - .../Fixtures/xml/container1.xml | 2 +- .../Fixtures/yml/container1.yml | 1 - .../SecurityExtensionTest.php | 7 -- .../Component/Security/Core/Util/Prng.php | 43 ++++++++---- .../Core/Util/SeedProviderInterface.php | 37 ---------- .../Security/Tests/Core/Util/PrngTest.php | 4 +- 15 files changed, 32 insertions(+), 319 deletions(-) delete mode 100644 src/Symfony/Bridge/Doctrine/Security/DoctrineSeedProvider.php delete mode 100644 src/Symfony/Bridge/Doctrine/Security/EventListener/PrngSchemaListener.php delete mode 100644 src/Symfony/Bridge/Doctrine/Security/PrngSchema.php delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Security/DoctrineSeedProviderTest.php delete mode 100755 src/Symfony/Bundle/SecurityBundle/Command/InitPrngCommand.php delete mode 100644 src/Symfony/Component/Security/Core/Util/SeedProviderInterface.php diff --git a/src/Symfony/Bridge/Doctrine/Security/DoctrineSeedProvider.php b/src/Symfony/Bridge/Doctrine/Security/DoctrineSeedProvider.php deleted file mode 100644 index 80f131321c1a..000000000000 --- a/src/Symfony/Bridge/Doctrine/Security/DoctrineSeedProvider.php +++ /dev/null @@ -1,68 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Security; - -use Doctrine\DBAL\Types\Type; -use Doctrine\DBAL\Connection; -use Symfony\Component\Security\Core\Util\SeedProviderInterface; - -/** - * Doctrine Seed Provider. - * - * @author Johannes M. Schmitt - * @author Fabien Potencier - */ -class DoctrineSeedProvider implements SeedProviderInterface -{ - private $con; - private $seedTableName; - - /** - * Constructor. - * - * @param Connection $con - * @param string $tableName - */ - public function __construct(Connection $con, $tableName) - { - $this->con = $con; - $this->seedTableName = $tableName; - } - - /** - * {@inheritdoc} - */ - public function loadSeed() - { - $stmt = $this->con->executeQuery("SELECT seed, updated_at FROM {$this->seedTableName}"); - - if (false === $seed = $stmt->fetchColumn(0)) { - throw new \RuntimeException('You need to initialize the generator by running the console command "init:prng".'); - } - - $seedLastUpdatedAt = new \DateTime($stmt->fetchColumn(1)); - - return array($seed, $seedLastUpdatedAt); - } - - /** - * {@inheritdoc} - */ - public function updateSeed($seed) - { - $params = array(':seed' => $seed, ':updatedAt' => new \DateTime()); - $types = array(':updatedAt' => Type::DATETIME); - if (!$this->con->executeUpdate("UPDATE {$this->seedTableName} SET seed = :seed, updated_at = :updatedAt", $params, $types)) { - $this->con->executeUpdate("INSERT INTO {$this->seedTableName} VALUES (:seed, :updatedAt)", $params, $types); - } - } -} diff --git a/src/Symfony/Bridge/Doctrine/Security/EventListener/PrngSchemaListener.php b/src/Symfony/Bridge/Doctrine/Security/EventListener/PrngSchemaListener.php deleted file mode 100644 index 61d956e7119a..000000000000 --- a/src/Symfony/Bridge/Doctrine/Security/EventListener/PrngSchemaListener.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Security\EventListener; - -use Symfony\Bridge\Doctrine\Security\PrngSchema; -use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs; - -/** - * @author Johannes M. Schmitt - */ -class PrngSchemaListener -{ - private $schema; - - public function __construct(PrngSchema $schema) - { - $this->schema = $schema; - } - - public function postGenerateSchema(GenerateSchemaEventArgs $args) - { - $this->schema->addToSchema($args->getSchema()); - } -} diff --git a/src/Symfony/Bridge/Doctrine/Security/PrngSchema.php b/src/Symfony/Bridge/Doctrine/Security/PrngSchema.php deleted file mode 100644 index e4d3745f1e4f..000000000000 --- a/src/Symfony/Bridge/Doctrine/Security/PrngSchema.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Security; - -use Doctrine\DBAL\Schema\Schema; - -/** - * The DBAL schema that will be used if you choose the database-based seed provider. - * - * @author Johannes M. Schmitt - */ -final class PrngSchema extends Schema -{ - public function __construct($tableName) - { - parent::__construct(); - - $table = $this->createTable($tableName); - $table->addColumn('seed', 'string', array( - 'length' => 88, - 'not_null' => true, - )); - $table->addColumn('updated_at', 'datetime', array( - 'not_null' => true, - )); - } - - public function addToSchema(Schema $schema) - { - foreach ($this->getTables() as $table) { - $schema->_addTable($table); - } - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/DoctrineSeedProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/DoctrineSeedProviderTest.php deleted file mode 100644 index e4ad1cdc9911..000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/DoctrineSeedProviderTest.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Doctrine\Tests\Security; - -use Symfony\Bridge\Doctrine\Security\DoctrineSeedProvider; -use Symfony\Bridge\Doctrine\Security\PrngSchema; -use Symfony\Component\Security\Core\Util\Prng; -use Symfony\Component\Security\Tests\Core\Util\PrngTest; -use Doctrine\DBAL\DriverManager; -use Doctrine\DBAL\Connection; - -class DoctrineSeedProviderTest extends PrngTest -{ - public function getPrngs() - { - $con = DriverManager::getConnection(array( - 'driver' => 'pdo_sqlite', - 'memory' => true - )); - - $schema = new PrngSchema('seed_table'); - foreach ($schema->toSql($con->getDatabasePlatform()) as $sql) { - $con->executeQuery($sql); - } - $con->executeQuery("INSERT INTO seed_table VALUES (:seed, :updatedAt)", array( - ':seed' => base64_encode(hash('sha512', uniqid(mt_rand(), true), true)), - ':updatedAt' => date('Y-m-d H:i:s'), - )); - - // no-openssl with database seed provider - $prng = new Prng(new DoctrineSeedProvider($con, 'seed_table')); - $this->disableOpenSsl($prng); - - $prngs = parent::getPrngs(); - $prngs[] = array($prng); - - return $prngs; - } -} diff --git a/src/Symfony/Bundle/SecurityBundle/Command/InitPrngCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/InitPrngCommand.php deleted file mode 100755 index 6cff60d7b149..000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Command/InitPrngCommand.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\SecurityBundle\Command; - -use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputArgument; - -/** - * Initializes a custom PRNG seed provider. - * - * @author Fabien Potencier - */ -class InitPrngCommand extends ContainerAwareCommand -{ - protected function configure() - { - $this - ->setName('init:prng'); - ->addArgument('phrase', InputArgument::REQUIRED, 'A random string'); - ->setDescription('Initialize a custom PRNG seed provider') - ->setHelp(<<%command.name% command initializes a custom PRNG seed provider: - -php %command.full_name% ABCDE... - -The argument should be a random string, whatever comes to your mind right now. -You do not need to remember it, it does not need to be cryptic, or long, and it -will not be stored in a decipherable way. One restriction however, you should -not let this be generated in an automated fashion. -EOF - ) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - if (!$this->getContainer()->has('security.prng_seed_provider')) { - throw new \RuntimeException('No seed provider has been configured under path "secure.prng".'); - } - - $this->getContainer()->get('security.prng_seed_provider')->updateSeed(base64_encode(hash('sha512', $input->getArgument('phrase'), true))); - - $output->writeln('The CSPRNG has been initialized successfully.'); - } -} diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index acdcec531ea9..267e60482846 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -87,7 +87,6 @@ private function addAclSection(ArrayNodeDefinition $rootNode) { $rootNode ->children() - ->scalarNode('prng_seed_provider')->defaultNull()->end() ->arrayNode('acl') ->children() ->scalarNode('connection') diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 9749dad780bd..fd8fe2355a3f 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -88,10 +88,6 @@ public function load(array $configs, ContainerBuilder $container) $this->aclLoad($config['acl'], $container); } - if (null !== $config['prng_seed_provider']) { - $container->setAlias('security.prng_seed_provider', $config['prng_seed_provider']); - } - // add some required classes for compilation $this->addClassesToCompile(array( 'Symfony\\Component\\Security\\Http\\Firewall', diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 52aa35f7f333..12f0ca827df6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -142,7 +142,7 @@ - + %kernel.cache_dir%/prng.seed diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php index d3ea91c969c6..826b621bb4e0 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php @@ -2,7 +2,6 @@ $container->loadFromExtension('security', array( 'acl' => array(), - 'prng_seed_provider' => 'custom_seed_provider', 'encoders' => array( 'JMS\FooBundle\Entity\User1' => 'plaintext', 'JMS\FooBundle\Entity\User2' => array( diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml index 6e76bb400ace..7180503f3ce4 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml @@ -5,7 +5,7 @@ xmlns:srv="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml index c78a7b0f745b..bf05e049f7c8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml @@ -1,6 +1,5 @@ security: acl: ~ - prng_seed_provider: custom_seed_provider encoders: JMS\FooBundle\Entity\User1: plaintext JMS\FooBundle\Entity\User2: diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index cde9a8f452b1..1d486d60204a 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -168,13 +168,6 @@ public function testCustomAclProvider() $this->assertEquals('foo', (string) $container->getAlias('security.acl.provider')); } - public function testSeedProvider() - { - $container = $this->getContainer('container1'); - - $this->assertEquals('custom_seed_provider', (string) $container->getAlias('security.prng_seed_provider')); - } - protected function getContainer($file) { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/Security/Core/Util/Prng.php b/src/Symfony/Component/Security/Core/Util/Prng.php index ab8baa7f1498..f3a0b2430a9d 100644 --- a/src/Symfony/Component/Security/Core/Util/Prng.php +++ b/src/Symfony/Component/Security/Core/Util/Prng.php @@ -16,6 +16,7 @@ /** * A secure random number generator implementation. * + * @author Fabien Potencier * @author Johannes M. Schmitt */ final class Prng @@ -25,7 +26,7 @@ final class Prng private $seed; private $seedUpdated; private $seedLastUpdatedAt; - private $seedProvider; + private $seedFile; /** * Constructor. @@ -33,12 +34,12 @@ final class Prng * Be aware that a guessable seed will severely compromise the PRNG * algorithm that is employed. * - * @param SeedProviderInterface $provider - * @param LoggerInterface $logger + * @param string $seedFile + * @param LoggerInterface $logger */ - public function __construct(SeedProviderInterface $provider = null, LoggerInterface $logger = null) + public function __construct($seedFile = null, LoggerInterface $logger = null) { - $this->seedProvider = $provider; + $this->seedFile = $seedFile; $this->logger = $logger; // determine whether to use OpenSSL @@ -77,11 +78,16 @@ public function nextBytes($nbBytes) // initialize seed if (null === $this->seed) { - if (null === $this->seedProvider) { - throw new \RuntimeException('You need to specify a custom seed provider.'); + if (null === $this->seedFile) { + throw new \RuntimeException('You need to specify a file path to store the seed.'); } - list($this->seed, $this->seedLastUpdatedAt) = $this->seedProvider->loadSeed(); + if (is_file($this->seedFile)) { + list($this->seed, $this->seedLastUpdatedAt) = $this->readSeed(); + } else { + $this->seed = uniqid(mt_rand(), true); + $this->updateSeed(); + } } $bytes = ''; @@ -89,16 +95,23 @@ public function nextBytes($nbBytes) static $incr = 1; $bytes .= hash('sha512', $incr++.$this->seed.uniqid(mt_rand(), true).$nbBytes, true); $this->seed = base64_encode(hash('sha512', $this->seed.$bytes.$nbBytes, true)); + $this->updateSeed(); + } - if (!$this->seedUpdated && $this->seedLastUpdatedAt->getTimestamp() < time() - mt_rand(1, 10)) { - if (null !== $this->seedProvider) { - $this->seedProvider->updateSeed($this->seed); - } + return substr($bytes, 0, $nbBytes); + } - $this->seedUpdated = true; - } + private function readSeed() + { + return json_decode(file_get_contents($this->seedFile)); + } + + private function updateSeed() + { + if (!$this->seedUpdated && $this->seedLastUpdatedAt < time() - mt_rand(1, 10)) { + file_put_contents($this->seedFile, json_encode(array($this->seed, microtime(true)))); } - return substr($bytes, 0, $nbBytes); + $this->seedUpdated = true; } } diff --git a/src/Symfony/Component/Security/Core/Util/SeedProviderInterface.php b/src/Symfony/Component/Security/Core/Util/SeedProviderInterface.php deleted file mode 100644 index dd960b94313c..000000000000 --- a/src/Symfony/Component/Security/Core/Util/SeedProviderInterface.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Security\Core\Util; - -/** - * Seed Provider Interface. - * - * @author Johannes M. Schmitt - */ -interface SeedProviderInterface -{ - /** - * Loads the initial seed. - * - * Whatever is returned from this method, it should not be guessable. - * - * @return array of the format array(string, DateTime) where string is the - * initial seed, and DateTime is the last time it was updated - */ - function loadSeed(); - - /** - * Updates the seed. - * - * @param string $seed - */ - function updateSeed($seed); -} diff --git a/src/Symfony/Component/Security/Tests/Core/Util/PrngTest.php b/src/Symfony/Component/Security/Tests/Core/Util/PrngTest.php index 7c9b2e2a3bd8..23afd30f8ec3 100755 --- a/src/Symfony/Component/Security/Tests/Core/Util/PrngTest.php +++ b/src/Symfony/Component/Security/Tests/Core/Util/PrngTest.php @@ -147,11 +147,11 @@ public function getPrngs() $prngs = array(); // openssl with fallback - $prng = new Prng(new NullSeedProvider()); + $prng = new Prng(); $prngs[] = array($prng); // no-openssl with custom seed provider - $prng = new Prng(new NullSeedProvider()); + $prng = new Prng(sys_get_temp_dir().'/_sf2.seed'); $this->disableOpenSsl($prng); $prngs[] = array($prng);