summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Acl/Dbal/MutableAclProvider.php1
-rw-r--r--Acl/Domain/AclCollectionCache.php6
-rw-r--r--Acl/Domain/PermissionGrantingStrategy.php1
-rw-r--r--CHANGELOG.md3
-rw-r--r--Core/Authentication/RememberMe/PersistentToken.php10
-rw-r--r--Core/Authentication/RememberMe/TokenProviderInterface.php6
-rw-r--r--Core/Encoder/BasePasswordEncoder.php13
-rw-r--r--Core/Util/SecureRandom.php114
-rw-r--r--Core/Util/SecureRandomInterface.php31
-rw-r--r--Core/Util/StringUtils.php48
-rw-r--r--Http/Firewall.php2
-rw-r--r--Http/Firewall/AbstractAuthenticationListener.php1
-rw-r--r--Http/RememberMe/PersistentTokenBasedRememberMeServices.php47
-rw-r--r--Http/RememberMe/ResponseListener.php1
-rw-r--r--Tests/Core/Util/ClassUtilsTest.php9
-rwxr-xr-xTests/Core/Util/SecureRandomTest.php202
-rwxr-xr-xTests/Core/Util/StringUtilsTest.php23
-rw-r--r--Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php3
18 files changed, 468 insertions, 53 deletions
diff --git a/Acl/Dbal/MutableAclProvider.php b/Acl/Dbal/MutableAclProvider.php
index 0d46f3a..9a20f61 100644
--- a/Acl/Dbal/MutableAclProvider.php
+++ b/Acl/Dbal/MutableAclProvider.php
@@ -17,7 +17,6 @@ use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
use Symfony\Component\Security\Acl\Exception\ConcurrentModificationException;
-use Symfony\Component\Security\Acl\Exception\Exception;
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
diff --git a/Acl/Domain/AclCollectionCache.php b/Acl/Domain/AclCollectionCache.php
index be082c1..88c017c 100644
--- a/Acl/Domain/AclCollectionCache.php
+++ b/Acl/Domain/AclCollectionCache.php
@@ -29,9 +29,9 @@ class AclCollectionCache
/**
* Constructor.
*
- * @param AclProviderInterface $aclProvider
- * @param ObjectIdentityRetrievalStrategy $oidRetrievalStrategy
- * @param SecurityIdentityRetrievalStrategy $sidRetrievalStrategy
+ * @param AclProviderInterface $aclProvider
+ * @param ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy
+ * @param SecurityIdentityRetrievalStrategyInterface $sidRetrievalStrategy
*/
public function __construct(AclProviderInterface $aclProvider, ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy, SecurityIdentityRetrievalStrategyInterface $sidRetrievalStrategy)
{
diff --git a/Acl/Domain/PermissionGrantingStrategy.php b/Acl/Domain/PermissionGrantingStrategy.php
index c34db2a..3b4e99a 100644
--- a/Acl/Domain/PermissionGrantingStrategy.php
+++ b/Acl/Domain/PermissionGrantingStrategy.php
@@ -16,7 +16,6 @@ use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\AuditLoggerInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
-use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* The permission granting strategy to apply to the access control list.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1c8192..279c614 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,8 @@ CHANGELOG
2.2.0
-----
-* Added PBKDF2 Password encoder
+ * added secure random number generator
+ * added PBKDF2 Password encoder
2.1.0
-----
diff --git a/Core/Authentication/RememberMe/PersistentToken.php b/Core/Authentication/RememberMe/PersistentToken.php
index a31c878..88b0413 100644
--- a/Core/Authentication/RememberMe/PersistentToken.php
+++ b/Core/Authentication/RememberMe/PersistentToken.php
@@ -27,11 +27,11 @@ final class PersistentToken implements PersistentTokenInterface
/**
* Constructor
*
- * @param string $class
- * @param string $username
- * @param string $series
- * @param string $tokenValue
- * @param DateTime $lastUsed
+ * @param string $class
+ * @param string $username
+ * @param string $series
+ * @param string $tokenValue
+ * @param \DateTime $lastUsed
*/
public function __construct($class, $username, $series, $tokenValue, \DateTime $lastUsed)
{
diff --git a/Core/Authentication/RememberMe/TokenProviderInterface.php b/Core/Authentication/RememberMe/TokenProviderInterface.php
index c8cfbd1..0c6f75e 100644
--- a/Core/Authentication/RememberMe/TokenProviderInterface.php
+++ b/Core/Authentication/RememberMe/TokenProviderInterface.php
@@ -39,9 +39,9 @@ interface TokenProviderInterface
/**
* Updates the token according to this data.
*
- * @param string $series
- * @param string $tokenValue
- * @param DateTime $lastUsed
+ * @param string $series
+ * @param string $tokenValue
+ * @param \DateTime $lastUsed
*/
public function updateToken($series, $tokenValue, \DateTime $lastUsed);
diff --git a/Core/Encoder/BasePasswordEncoder.php b/Core/Encoder/BasePasswordEncoder.php
index ae1c7d4..1ef134b 100644
--- a/Core/Encoder/BasePasswordEncoder.php
+++ b/Core/Encoder/BasePasswordEncoder.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Core\Encoder;
+use Symfony\Component\Security\Core\Util\StringUtils;
+
/**
* BasePasswordEncoder is the base class for all password encoders.
*
@@ -77,15 +79,6 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
*/
protected function comparePasswords($password1, $password2)
{
- if (strlen($password1) !== strlen($password2)) {
- return false;
- }
-
- $result = 0;
- for ($i = 0; $i < strlen($password1); $i++) {
- $result |= ord($password1[$i]) ^ ord($password2[$i]);
- }
-
- return 0 === $result;
+ return StringUtils::equals($password1, $password2);
}
}
diff --git a/Core/Util/SecureRandom.php b/Core/Util/SecureRandom.php
new file mode 100644
index 0000000..77f1d8c
--- /dev/null
+++ b/Core/Util/SecureRandom.php
@@ -0,0 +1,114 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * 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;
+
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+
+/**
+ * A secure random number generator implementation.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+final class SecureRandom implements SecureRandomInterface
+{
+ private $logger;
+ private $useOpenSsl;
+ private $seed;
+ private $seedUpdated;
+ private $seedLastUpdatedAt;
+ private $seedFile;
+
+ /**
+ * Constructor.
+ *
+ * Be aware that a guessable seed will severely compromise the PRNG
+ * algorithm that is employed.
+ *
+ * @param string $seedFile
+ * @param LoggerInterface $logger
+ */
+ public function __construct($seedFile = null, LoggerInterface $logger = null)
+ {
+ $this->seedFile = $seedFile;
+ $this->logger = $logger;
+
+ // determine whether to use OpenSSL
+ if (defined('PHP_WINDOWS_VERSION_BUILD') && version_compare(PHP_VERSION, '5.3.4', '<')) {
+ $this->useOpenSsl = false;
+ } elseif (!function_exists('openssl_random_pseudo_bytes')) {
+ if (null !== $this->logger) {
+ $this->logger->notice('It is recommended that you enable the "openssl" extension for random number generation.');
+ }
+ $this->useOpenSsl = false;
+ } else {
+ $this->useOpenSsl = true;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function nextBytes($nbBytes)
+ {
+ // try OpenSSL
+ if ($this->useOpenSsl) {
+ $bytes = openssl_random_pseudo_bytes($nbBytes, $strong);
+
+ if (false !== $bytes && true === $strong) {
+ return $bytes;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->info('OpenSSL did not produce a secure random number.');
+ }
+ }
+
+ // initialize seed
+ if (null === $this->seed) {
+ if (null === $this->seedFile) {
+ throw new \RuntimeException('You need to specify a file path to store the seed.');
+ }
+
+ if (is_file($this->seedFile)) {
+ list($this->seed, $this->seedLastUpdatedAt) = $this->readSeed();
+ } else {
+ $this->seed = uniqid(mt_rand(), true);
+ $this->updateSeed();
+ }
+ }
+
+ $bytes = '';
+ while (strlen($bytes) < $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();
+ }
+
+ return substr($bytes, 0, $nbBytes);
+ }
+
+ 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))));
+ }
+
+ $this->seedUpdated = true;
+ }
+}
diff --git a/Core/Util/SecureRandomInterface.php b/Core/Util/SecureRandomInterface.php
new file mode 100644
index 0000000..64830a9
--- /dev/null
+++ b/Core/Util/SecureRandomInterface.php
@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * 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;
+
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
+
+/**
+ * Interface that needs to be implemented by all secure random number generators.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+interface SecureRandomInterface
+{
+ /**
+ * Generates the specified number of secure random bytes.
+ *
+ * @param integer $nbBytes
+ *
+ * @return string
+ */
+ public function nextBytes($nbBytes);
+}
diff --git a/Core/Util/StringUtils.php b/Core/Util/StringUtils.php
new file mode 100644
index 0000000..a73b471
--- /dev/null
+++ b/Core/Util/StringUtils.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * 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;
+
+/**
+ * String utility functions.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+final class StringUtils
+{
+ final private function __construct()
+ {
+ }
+
+ /**
+ * Compares two strings.
+ *
+ * This method implements a constant-time algorithm to compare strings.
+ *
+ * @param string $str1 The first string
+ * @param string $str2 The second string
+ *
+ * @return Boolean true if the two strings are the same, false otherwise
+ */
+ public static function equals($str1, $str2)
+ {
+ if (strlen($str1) !== $c = strlen($str2)) {
+ return false;
+ }
+
+ $result = 0;
+ for ($i = 0; $i < $c; $i++) {
+ $result |= ord($str1[$i]) ^ ord($str2[$i]);
+ }
+
+ return 0 === $result;
+ }
+}
diff --git a/Http/Firewall.php b/Http/Firewall.php
index 91eb6a9..a590fd9 100644
--- a/Http/Firewall.php
+++ b/Http/Firewall.php
@@ -33,7 +33,7 @@ class Firewall
/**
* Constructor.
*
- * @param FirewallMap $map A FirewallMap instance
+ * @param FirewallMapInterface $map A FirewallMapInterface instance
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
*/
public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher)
diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php
index 1af1646..410fb73 100644
--- a/Http/Firewall/AbstractAuthenticationListener.php
+++ b/Http/Firewall/AbstractAuthenticationListener.php
@@ -20,7 +20,6 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\SessionUnavailableException;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
index 8944672..dbb6429 100644
--- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
+++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
@@ -19,6 +19,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CookieTheftException;
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Util\SecureRandomInterface;
/**
* Concrete implementation of the RememberMeServicesInterface which needs
@@ -30,6 +31,24 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
{
private $tokenProvider;
+ private $secureRandom;
+
+ /**
+ * Constructor.
+ *
+ * @param array $userProviders
+ * @param string $key
+ * @param string $providerKey
+ * @param array $options
+ * @param LoggerInterface $logger
+ * @param SecureRandomInterface $secureRandom
+ */
+ public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null, SecureRandomInterface $secureRandom)
+ {
+ parent::__construct($userProviders, $key, $providerKey, $options, $logger);
+
+ $this->secureRandom = $secureRandom;
+ }
/**
* Sets the token provider
@@ -79,7 +98,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
}
$series = $persistentToken->getSeries();
- $tokenValue = $this->generateRandomValue();
+ $tokenValue = $this->secureRandom->nextBytes(64);
$this->tokenProvider->updateToken($series, $tokenValue, new \DateTime());
$request->attributes->set(self::COOKIE_ATTR_NAME,
new Cookie(
@@ -101,8 +120,8 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
*/
protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
{
- $series = $this->generateRandomValue();
- $tokenValue = $this->generateRandomValue();
+ $series = $this->secureRandom->nextBytes(64);
+ $tokenValue = $this->secureRandom->nextBytes(64);
$this->tokenProvider->createNewToken(
new PersistentToken(
@@ -126,26 +145,4 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
)
);
}
-
- /**
- * Generates a cryptographically strong random value
- *
- * @return string
- */
- protected function generateRandomValue()
- {
- if (function_exists('openssl_random_pseudo_bytes')) {
- $bytes = openssl_random_pseudo_bytes(64, $strong);
-
- if (true === $strong && false !== $bytes) {
- return base64_encode($bytes);
- }
- }
-
- if (null !== $this->logger) {
- $this->logger->warn('Could not produce a cryptographically strong random value. Please install/update the OpenSSL extension.');
- }
-
- return base64_encode(hash('sha512', uniqid(mt_rand(), true), true));
- }
}
diff --git a/Http/RememberMe/ResponseListener.php b/Http/RememberMe/ResponseListener.php
index 11ea790..6cbdcb3 100644
--- a/Http/RememberMe/ResponseListener.php
+++ b/Http/RememberMe/ResponseListener.php
@@ -11,7 +11,6 @@
namespace Symfony\Component\Security\Http\RememberMe;
-use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
/**
diff --git a/Tests/Core/Util/ClassUtilsTest.php b/Tests/Core/Util/ClassUtilsTest.php
index 16378a6..edfd779 100644
--- a/Tests/Core/Util/ClassUtilsTest.php
+++ b/Tests/Core/Util/ClassUtilsTest.php
@@ -1,5 +1,14 @@
<?php
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
namespace Symfony\Component\Security\Tests\Core\Util
{
use Symfony\Component\Security\Core\Util\ClassUtils;
diff --git a/Tests/Core/Util/SecureRandomTest.php b/Tests/Core/Util/SecureRandomTest.php
new file mode 100755
index 0000000..230a26a
--- /dev/null
+++ b/Tests/Core/Util/SecureRandomTest.php
@@ -0,0 +1,202 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Tests\Core\Util;
+
+use Symfony\Component\Security\Core\Util\NullSeedProvider;
+use Symfony\Component\Security\Core\Util\SecureRandom;
+
+class SecureRandomTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * T1: Monobit test
+ *
+ * @dataProvider getSecureRandoms
+ */
+ public function testMonobit($secureRandom)
+ {
+ $nbOnBits = substr_count($this->getBitSequence($secureRandom, 20000), '1');
+ $this->assertTrue($nbOnBits > 9654 && $nbOnBits < 10346, 'Monobit test failed, number of turned on bits: '.$nbOnBits);
+ }
+
+ /**
+ * T2: Chi-square test with 15 degrees of freedom (chi-Quadrat-Anpassungstest)
+ *
+ * @dataProvider getSecureRandoms
+ */
+ public function testPoker($secureRandom)
+ {
+ $b = $this->getBitSequence($secureRandom, 20000);
+ $c = array();
+ for ($i = 0; $i <= 15; $i++) {
+ $c[$i] = 0;
+ }
+
+ for ($j = 1; $j <= 5000; $j++) {
+ $k = 4 * $j - 1;
+ $c[8 * $b[$k - 3] + 4 * $b[$k - 2] + 2 * $b[$k - 1] + $b[$k]] += 1;
+ }
+
+ $f = 0;
+ for ($i = 0; $i <= 15; $i++) {
+ $f += $c[$i] * $c[$i];
+ }
+
+ $Y = 16/5000 * $f - 5000;
+
+ $this->assertTrue($Y > 1.03 && $Y < 57.4, 'Poker test failed, Y = '.$Y);
+ }
+
+ /**
+ * Run test
+ *
+ * @dataProvider getSecureRandoms
+ */
+ public function testRun($secureRandom)
+ {
+ $b = $this->getBitSequence($secureRandom, 20000);
+
+ $runs = array();
+ for ($i = 1; $i <= 6; $i++) {
+ $runs[$i] = 0;
+ }
+
+ $addRun = function($run) use (&$runs) {
+ if ($run > 6) {
+ $run = 6;
+ }
+
+ $runs[$run] += 1;
+ };
+
+ $currentRun = 0;
+ $lastBit = null;
+ for ($i = 0; $i < 20000; $i++) {
+ if ($lastBit === $b[$i]) {
+ $currentRun += 1;
+ } else {
+ if ($currentRun > 0) {
+ $addRun($currentRun);
+ }
+
+ $lastBit = $b[$i];
+ $currentRun = 0;
+ }
+ }
+ if ($currentRun > 0) {
+ $addRun($currentRun);
+ }
+
+ $this->assertTrue($runs[1] > 2267 && $runs[1] < 2733, 'Runs of length 1 outside of defined interval: '.$runs[1]);
+ $this->assertTrue($runs[2] > 1079 && $runs[2] < 1421, 'Runs of length 2 outside of defined interval: '.$runs[2]);
+ $this->assertTrue($runs[3] > 502 && $runs[3] < 748, 'Runs of length 3 outside of defined interval: '.$runs[3]);
+ $this->assertTrue($runs[4] > 233 && $runs[4] < 402, 'Runs of length 4 outside of defined interval: '.$runs[4]);
+ $this->assertTrue($runs[5] > 90 && $runs[5] < 223, 'Runs of length 5 outside of defined interval: '.$runs[5]);
+ $this->assertTrue($runs[6] > 90 && $runs[6] < 233, 'Runs of length 6 outside of defined interval: '.$runs[6]);
+ }
+
+ /**
+ * Long-run test
+ *
+ * @dataProvider getSecureRandoms
+ */
+ public function testLongRun($secureRandom)
+ {
+ $b = $this->getBitSequence($secureRandom, 20000);
+
+ $longestRun = 0;
+ $currentRun = $lastBit = null;
+ for ($i = 0; $i < 20000; $i++) {
+ if ($lastBit === $b[$i]) {
+ $currentRun += 1;
+ } else {
+ if ($currentRun > $longestRun) {
+ $longestRun = $currentRun;
+ }
+ $lastBit = $b[$i];
+ $currentRun = 0;
+ }
+ }
+ if ($currentRun > $longestRun) {
+ $longestRun = $currentRun;
+ }
+
+ $this->assertTrue($longestRun < 34, 'Failed longest run test: '.$longestRun);
+ }
+
+ /**
+ * Serial Correlation (Autokorrelationstest)
+ *
+ * @dataProvider getSecureRandoms
+ */
+ public function testSerialCorrelation($secureRandom)
+ {
+ $shift = rand(1, 5000);
+ $b = $this->getBitSequence($secureRandom, 20000);
+
+ $Z = 0;
+ for ($i = 0; $i < 5000; $i++) {
+ $Z += $b[$i] === $b[$i + $shift] ? 1 : 0;
+ }
+
+ $this->assertTrue($Z > 2326 && $Z < 2674, 'Failed serial correlation test: '.$Z);
+ }
+
+ public function getSecureRandoms()
+ {
+ $secureRandoms = array();
+
+ // only add if openssl is indeed present
+ $secureRandom = new SecureRandom();
+ if ($this->hasOpenSsl($secureRandom)) {
+ $secureRandoms[] = array($secureRandom);
+ }
+
+ // no-openssl with custom seed provider
+ $secureRandom = new SecureRandom(sys_get_temp_dir().'/_sf2.seed');
+ $this->disableOpenSsl($secureRandom);
+ $secureRandoms[] = array($secureRandom);
+
+ return $secureRandoms;
+ }
+
+ protected function disableOpenSsl($secureRandom)
+ {
+ $ref = new \ReflectionProperty($secureRandom, 'useOpenSsl');
+ $ref->setAccessible(true);
+ $ref->setValue($secureRandom, false);
+ $ref->setAccessible(false);
+ }
+
+ protected function hasOpenSsl($secureRandom)
+ {
+ $ref = new \ReflectionProperty($secureRandom, 'useOpenSsl');
+ $ref->setAccessible(true);
+
+ $ret = $ref->getValue($secureRandom);
+
+ $ref->setAccessible(false);
+
+ return $ret;
+ }
+
+ private function getBitSequence($secureRandom, $length)
+ {
+ $bitSequence = '';
+ for ($i = 0; $i < $length; $i += 40) {
+ $value = unpack('H*', $secureRandom->nextBytes(5));
+ $value = str_pad(base_convert($value[1], 16, 2), 40, '0', STR_PAD_LEFT);
+ $bitSequence .= $value;
+ }
+
+ return substr($bitSequence, 0, $length);
+ }
+}
diff --git a/Tests/Core/Util/StringUtilsTest.php b/Tests/Core/Util/StringUtilsTest.php
new file mode 100755
index 0000000..aac4139
--- /dev/null
+++ b/Tests/Core/Util/StringUtilsTest.php
@@ -0,0 +1,23 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Tests\Core\Util;
+
+use Symfony\Component\Security\Core\Util\StringUtils;
+
+class StringUtilsTest extends \PHPUnit_Framework_TestCase
+{
+ public function testEquals()
+ {
+ $this->assertTrue(StringUtils::equals('password', 'password'));
+ $this->assertFalse(StringUtils::equals('password', 'foo'));
+ }
+}
diff --git a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php b/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
index 3b3691d..7fc3021 100644
--- a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
+++ b/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
@@ -22,6 +22,7 @@ use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
use Symfony\Component\Security\Core\Exception\CookieTheftException;
+use Symfony\Component\Security\Core\Util\SecureRandom;
class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
{
@@ -318,7 +319,7 @@ class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_Test
$userProvider = $this->getProvider();
}
- return new PersistentTokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger);
+ return new PersistentTokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger, new SecureRandom(sys_get_temp_dir().'/_sf2.seed'));
}
protected function getProvider()