summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Acl/Dbal/AclProvider.php8
-rw-r--r--Acl/Dbal/MutableAclProvider.php6
-rw-r--r--Core/Authorization/Voter/VoterInterface.php2
-rw-r--r--Core/Encoder/BCryptPasswordEncoder.php2
-rw-r--r--Core/Encoder/BasePasswordEncoder.php2
-rw-r--r--Core/User/InMemoryUserProvider.php2
-rw-r--r--Core/User/UserInterface.php2
-rw-r--r--Core/Util/SecureRandom.php91
-rw-r--r--Http/EntryPoint/AuthenticationEntryPointInterface.php12
-rw-r--r--Http/Firewall/DigestAuthenticationListener.php9
-rw-r--r--Http/Firewall/RememberMeListener.php8
-rw-r--r--Http/RememberMe/PersistentTokenBasedRememberMeServices.php3
-rw-r--r--Http/RememberMe/TokenBasedRememberMeServices.php28
-rw-r--r--LICENSE2
-rw-r--r--README.md27
-rw-r--r--Resources/translations/security.no.xlf4
-rw-r--r--Tests/Core/Authentication/Token/AbstractTokenTest.php18
-rw-r--r--Tests/Core/Encoder/BCryptPasswordEncoderTest.php9
-rw-r--r--Tests/Core/Encoder/EncoderFactoryTest.php4
-rw-r--r--Tests/Core/SecurityContextTest.php2
-rw-r--r--Tests/Core/User/UserTest.php31
-rw-r--r--Tests/Core/Util/SecureRandomTest.php201
-rw-r--r--Tests/Http/Firewall/RememberMeListenerTest.php63
-rw-r--r--Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php9
-rw-r--r--Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php3
-rw-r--r--Tests/Resources/TranslationFilesTest.php31
-rw-r--r--composer.json9
-rw-r--r--phpunit.xml.dist5
28 files changed, 181 insertions, 412 deletions
diff --git a/Acl/Dbal/AclProvider.php b/Acl/Dbal/AclProvider.php
index 1fade3b..bba5824 100644
--- a/Acl/Dbal/AclProvider.php
+++ b/Acl/Dbal/AclProvider.php
@@ -367,7 +367,7 @@ FINDCHILDREN;
*/
protected function getSelectObjectIdentityIdSql(ObjectIdentityInterface $oid)
{
- $query = <<<QUERY
+ $query = <<<'QUERY'
SELECT o.id
FROM %s o
INNER JOIN %s c ON c.id = o.class_id
@@ -571,7 +571,7 @@ QUERY;
$oidCache[$oidLookupKey] = new ObjectIdentity($objectIdentifier, $classType);
}
- $acl = new Acl((int) $aclId, $oidCache[$oidLookupKey], $permissionGrantingStrategy, $emptyArray, !!$entriesInheriting);
+ $acl = new Acl((int) $aclId, $oidCache[$oidLookupKey], $permissionGrantingStrategy, $emptyArray, (bool) $entriesInheriting);
// keep a local, and global reference to this ACL
$loadedAcls[$classType][$objectIdentifier] = $acl;
@@ -613,9 +613,9 @@ QUERY;
}
if (null === $fieldName) {
- $loadedAces[$aceId] = new Entry((int) $aceId, $acl, $sids[$key], $grantingStrategy, (int) $mask, !!$granting, !!$auditFailure, !!$auditSuccess);
+ $loadedAces[$aceId] = new Entry((int) $aceId, $acl, $sids[$key], $grantingStrategy, (int) $mask, (bool) $granting, (bool) $auditFailure, (bool) $auditSuccess);
} else {
- $loadedAces[$aceId] = new FieldEntry((int) $aceId, $acl, $fieldName, $sids[$key], $grantingStrategy, (int) $mask, !!$granting, !!$auditFailure, !!$auditSuccess);
+ $loadedAces[$aceId] = new FieldEntry((int) $aceId, $acl, $fieldName, $sids[$key], $grantingStrategy, (int) $mask, (bool) $granting, (bool) $auditFailure, (bool) $auditSuccess);
}
}
$ace = $loadedAces[$aceId];
diff --git a/Acl/Dbal/MutableAclProvider.php b/Acl/Dbal/MutableAclProvider.php
index b871443..40ed471 100644
--- a/Acl/Dbal/MutableAclProvider.php
+++ b/Acl/Dbal/MutableAclProvider.php
@@ -433,7 +433,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
*/
protected function getInsertAccessControlEntrySql($classId, $objectIdentityId, $field, $aceOrder, $securityIdentityId, $strategy, $mask, $granting, $auditSuccess, $auditFailure)
{
- $query = <<<QUERY
+ $query = <<<'QUERY'
INSERT INTO %s (
class_id,
object_identity_id,
@@ -510,7 +510,7 @@ QUERY;
*/
protected function getInsertObjectIdentitySql($identifier, $classId, $entriesInheriting)
{
- $query = <<<QUERY
+ $query = <<<'QUERY'
INSERT INTO %s (class_id, object_identifier, entries_inheriting)
VALUES (%d, %s, %s)
QUERY;
@@ -856,7 +856,7 @@ QUERY;
*/
private function updateNewAceProperty($name, array $changes)
{
- list($old, $new) = $changes;
+ list(, $new) = $changes;
$sids = new \SplObjectStorage();
$classIds = new \SplObjectStorage();
diff --git a/Core/Authorization/Voter/VoterInterface.php b/Core/Authorization/Voter/VoterInterface.php
index d00ff1c..1032cb2 100644
--- a/Core/Authorization/Voter/VoterInterface.php
+++ b/Core/Authorization/Voter/VoterInterface.php
@@ -27,7 +27,7 @@ interface VoterInterface
/**
* Checks if the voter supports the given attribute.
*
- * @param string $attribute An attribute
+ * @param mixed $attribute An attribute (usually the attribute name string)
*
* @return bool true if this Voter supports the attribute, false otherwise
*/
diff --git a/Core/Encoder/BCryptPasswordEncoder.php b/Core/Encoder/BCryptPasswordEncoder.php
index d2b0319..83ae334 100644
--- a/Core/Encoder/BCryptPasswordEncoder.php
+++ b/Core/Encoder/BCryptPasswordEncoder.php
@@ -19,6 +19,8 @@ use Symfony\Component\Security\Core\Exception\BadCredentialsException;
*/
class BCryptPasswordEncoder extends BasePasswordEncoder
{
+ const MAX_PASSWORD_LENGTH = 72;
+
/**
* @var string
*/
diff --git a/Core/Encoder/BasePasswordEncoder.php b/Core/Encoder/BasePasswordEncoder.php
index 1c9ada1..fcf2e47 100644
--- a/Core/Encoder/BasePasswordEncoder.php
+++ b/Core/Encoder/BasePasswordEncoder.php
@@ -95,6 +95,6 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
*/
protected function isPasswordTooLong($password)
{
- return strlen($password) > self::MAX_PASSWORD_LENGTH;
+ return strlen($password) > static::MAX_PASSWORD_LENGTH;
}
}
diff --git a/Core/User/InMemoryUserProvider.php b/Core/User/InMemoryUserProvider.php
index 9aa39ca..c1981de 100644
--- a/Core/User/InMemoryUserProvider.php
+++ b/Core/User/InMemoryUserProvider.php
@@ -97,7 +97,7 @@ class InMemoryUserProvider implements UserProviderInterface
/**
* Returns the user by given username.
*
- * @param string $username The username.
+ * @param string $username The username.
*
* @return User
*
diff --git a/Core/User/UserInterface.php b/Core/User/UserInterface.php
index 1b52dab..7478842 100644
--- a/Core/User/UserInterface.php
+++ b/Core/User/UserInterface.php
@@ -47,7 +47,7 @@ interface UserInterface
* and populated in any number of different ways when the user object
* is created.
*
- * @return Role[] The user roles
+ * @return (Role|string)[] The user roles
*/
public function getRoles();
diff --git a/Core/Util/SecureRandom.php b/Core/Util/SecureRandom.php
index 3461b4e..478f556 100644
--- a/Core/Util/SecureRandom.php
+++ b/Core/Util/SecureRandom.php
@@ -11,8 +11,6 @@
namespace Symfony\Component\Security\Core\Util;
-use Psr\Log\LoggerInterface;
-
/**
* A secure random number generator implementation.
*
@@ -21,98 +19,11 @@ use Psr\Log\LoggerInterface;
*/
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;
-
- $isUnsupportedPhp = '\\' === DIRECTORY_SEPARATOR && PHP_VERSION_ID < 50304;
-
- // determine whether to use OpenSSL
- if (!function_exists('random_bytes') && ($isUnsupportedPhp || !function_exists('openssl_random_pseudo_bytes'))) {
- if (null !== $this->logger) {
- $this->logger->notice('It is recommended that you install the "paragonie/random_compat" library or enable the "openssl" extension for random number generation.');
- }
- $this->useOpenSsl = false;
- } else {
- $this->useOpenSsl = true;
- }
- }
-
/**
* {@inheritdoc}
*/
public function nextBytes($nbBytes)
{
- if (function_exists('random_bytes')) {
- return random_bytes($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;
+ return random_bytes($nbBytes);
}
}
diff --git a/Http/EntryPoint/AuthenticationEntryPointInterface.php b/Http/EntryPoint/AuthenticationEntryPointInterface.php
index 0d7595d..c8e43e5 100644
--- a/Http/EntryPoint/AuthenticationEntryPointInterface.php
+++ b/Http/EntryPoint/AuthenticationEntryPointInterface.php
@@ -24,7 +24,17 @@ use Symfony\Component\HttpFoundation\Response;
interface AuthenticationEntryPointInterface
{
/**
- * Starts the authentication scheme.
+ * Returns a response that directs the user to authenticate.
+ *
+ * This is called when an anonymous request accesses a resource that
+ * requires authentication. The job of this method is to return some
+ * response that "helps" the user start into the authentication process.
+ *
+ * Examples:
+ * A) For a form login, you might redirect to the login page
+ * return new RedirectResponse('/login');
+ * B) For an API token authentication system, you return a 401 response
+ * return new Response('Auth header required', 401);
*
* @param Request $request The request that resulted in an AuthenticationException
* @param AuthenticationException $authException The exception that started the authentication process
diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php
index a88250b..4e57667 100644
--- a/Http/Firewall/DigestAuthenticationListener.php
+++ b/Http/Firewall/DigestAuthenticationListener.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
+use Symfony\Component\Security\Core\Util\StringUtils;
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -99,7 +100,7 @@ class DigestAuthenticationListener implements ListenerInterface
return;
}
- if ($serverDigestMd5 !== $digestAuth->getResponse()) {
+ if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Expected response: "%s" but received: "%s"; is AuthenticationDao returning clear text passwords?', $serverDigestMd5, $digestAuth->getResponse()));
}
@@ -171,10 +172,8 @@ class DigestData
throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s" (%s)', $this->header, implode(', ', $keys)));
}
- if ('auth' === $this->elements['qop']) {
- if (!isset($this->elements['nc']) || !isset($this->elements['cnonce'])) {
- throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s"', $this->header));
- }
+ if ('auth' === $this->elements['qop'] && !isset($this->elements['nc'], $this->elements['cnonce'])) {
+ throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s"', $this->header));
}
if ($expectedRealm !== $this->elements['realm']) {
diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php
index 942e537..52a231c 100644
--- a/Http/Firewall/RememberMeListener.php
+++ b/Http/Firewall/RememberMeListener.php
@@ -20,6 +20,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
/**
* RememberMeListener implements authentication capabilities via a cookie.
@@ -33,6 +34,7 @@ class RememberMeListener implements ListenerInterface
private $authenticationManager;
private $logger;
private $dispatcher;
+ private $sessionStrategy;
/**
* Constructor.
@@ -50,6 +52,7 @@ class RememberMeListener implements ListenerInterface
$this->authenticationManager = $authenticationManager;
$this->logger = $logger;
$this->dispatcher = $dispatcher;
+ $this->sessionStrategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE);
}
/**
@@ -70,6 +73,11 @@ class RememberMeListener implements ListenerInterface
try {
$token = $this->authenticationManager->authenticate($token);
+
+ if ($request->hasSession() && $request->getSession()->isStarted()) {
+ $this->sessionStrategy->onAuthentication($request, $token);
+ }
+
$this->securityContext->setToken($token);
if (null !== $this->dispatcher) {
diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
index f800668..0fffbfe 100644
--- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
+++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php
@@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
use Psr\Log\LoggerInterface;
+use Symfony\Component\Security\Core\Util\StringUtils;
/**
* Concrete implementation of the RememberMeServicesInterface which needs
@@ -90,7 +91,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
list($series, $tokenValue) = $cookieParts;
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
- if ($persistentToken->getTokenValue() !== $tokenValue) {
+ if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) {
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
}
diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php
index de662fb..1aea5fd 100644
--- a/Http/RememberMe/TokenBasedRememberMeServices.php
+++ b/Http/RememberMe/TokenBasedRememberMeServices.php
@@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Core\Util\StringUtils;
/**
* Concrete implementation of the RememberMeServicesInterface providing
@@ -53,7 +54,7 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user)));
}
- if (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) {
+ if (!StringUtils::equals($this->generateCookieHash($class, $username, $expires, $user->getPassword()), $hash)) {
throw new AuthenticationException('The cookie\'s hash is invalid.');
}
@@ -65,31 +66,6 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
}
/**
- * Compares two hashes using a constant-time algorithm to avoid (remote)
- * timing attacks.
- *
- * This is the same implementation as used in the BasePasswordEncoder.
- *
- * @param string $hash1 The first hash
- * @param string $hash2 The second hash
- *
- * @return bool true if the two hashes are the same, false otherwise
- */
- private function compareHashes($hash1, $hash2)
- {
- if (strlen($hash1) !== $c = strlen($hash2)) {
- return false;
- }
-
- $result = 0;
- for ($i = 0; $i < $c; ++$i) {
- $result |= ord($hash1[$i]) ^ ord($hash2[$i]);
- }
-
- return 0 === $result;
- }
-
- /**
* {@inheritdoc}
*/
protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token)
diff --git a/LICENSE b/LICENSE
index 43028bc..12a7453 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2015 Fabien Potencier
+Copyright (c) 2004-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index e38bc33..b8bba12 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,18 @@
Security Component
==================
-Security provides an infrastructure for sophisticated authorization systems,
-which makes it possible to easily separate the actual authorization logic from
-so called user providers that hold the users credentials. It is inspired by
-the Java Spring framework.
+The Security component provides a complete security system for your web
+application. It ships with facilities for authenticating using HTTP basic or
+digest authentication, interactive form login or X.509 certificate login, but
+also allows you to implement your own authentication strategies. Furthermore,
+the component provides ways to authorize authenticated users based on their
+roles, and it contains an advanced ACL system.
Resources
---------
-Documentation:
-
-https://symfony.com/doc/2.3/book/security.html
-
-Resources
----------
-
-You can run the unit tests with the following command:
-
- $ cd path/to/Symfony/Component/Security/
- $ composer install
- $ phpunit
+ * [Documentation](https://symfony.com/doc/current/components/security/index.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/Resources/translations/security.no.xlf b/Resources/translations/security.no.xlf
index 3369d43..3635916 100644
--- a/Resources/translations/security.no.xlf
+++ b/Resources/translations/security.no.xlf
@@ -4,7 +4,7 @@
<body>
<trans-unit id="1">
<source>An authentication exception occurred.</source>
- <target>En autentiserings feil har skjedd.</target>
+ <target>En autentiseringsfeil har skjedd.</target>
</trans-unit>
<trans-unit id="2">
<source>Authentication credentials could not be found.</source>
@@ -24,7 +24,7 @@
</trans-unit>
<trans-unit id="6">
<source>Not privileged to request the resource.</source>
- <target>Ingen tilgang til å be om gitt kilde.</target>
+ <target>Ingen tilgang til å be om gitt ressurs.</target>
</trans-unit>
<trans-unit id="7">
<source>Invalid CSRF token.</source>
diff --git a/Tests/Core/Authentication/Token/AbstractTokenTest.php b/Tests/Core/Authentication/Token/AbstractTokenTest.php
index b8be628..efdad4c 100644
--- a/Tests/Core/Authentication/Token/AbstractTokenTest.php
+++ b/Tests/Core/Authentication/Token/AbstractTokenTest.php
@@ -85,10 +85,6 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase
$token->eraseCredentials();
}
- /**
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::serialize
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::unserialize
- */
public function testSerialize()
{
$token = $this->getToken(array('ROLE_FOO'));
@@ -114,9 +110,6 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase
);
}
- /**
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::__construct
- */
public function testConstructor()
{
$token = $this->getToken(array('ROLE_FOO'));
@@ -129,10 +122,6 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(new Role('ROLE_FOO'), new Role('ROLE_BAR')), $token->getRoles());
}
- /**
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::isAuthenticated
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::setAuthenticated
- */
public function testAuthenticatedFlag()
{
$token = $this->getToken();
@@ -145,13 +134,6 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($token->isAuthenticated());
}
- /**
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::getAttributes
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::setAttributes
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::hasAttribute
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::getAttribute
- * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::setAttribute
- */
public function testAttributes()
{
$attributes = array('foo' => 'bar');
diff --git a/Tests/Core/Encoder/BCryptPasswordEncoderTest.php b/Tests/Core/Encoder/BCryptPasswordEncoderTest.php
index 076d954..9894c6f 100644
--- a/Tests/Core/Encoder/BCryptPasswordEncoderTest.php
+++ b/Tests/Core/Encoder/BCryptPasswordEncoderTest.php
@@ -73,13 +73,18 @@ class BCryptPasswordEncoderTest extends \PHPUnit_Framework_TestCase
{
$encoder = new BCryptPasswordEncoder(self::VALID_COST);
- $encoder->encodePassword(str_repeat('a', 5000), 'salt');
+ $encoder->encodePassword(str_repeat('a', 73), 'salt');
}
+ /**
+ * @requires PHP 5.3.7
+ */
public function testCheckPasswordLength()
{
$encoder = new BCryptPasswordEncoder(self::VALID_COST);
+ $result = $encoder->encodePassword(str_repeat('a', 72), null);
- $this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
+ $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 73), 'salt'));
+ $this->assertTrue($encoder->isPasswordValid($result, str_repeat('a', 72), 'salt'));
}
}
diff --git a/Tests/Core/Encoder/EncoderFactoryTest.php b/Tests/Core/Encoder/EncoderFactoryTest.php
index 85d4e91..4fe60ad 100644
--- a/Tests/Core/Encoder/EncoderFactoryTest.php
+++ b/Tests/Core/Encoder/EncoderFactoryTest.php
@@ -85,15 +85,19 @@ class SomeUser implements UserInterface
public function getRoles()
{
}
+
public function getPassword()
{
}
+
public function getSalt()
{
}
+
public function getUsername()
{
}
+
public function eraseCredentials()
{
}
diff --git a/Tests/Core/SecurityContextTest.php b/Tests/Core/SecurityContextTest.php
index 6695889..3fba8d9 100644
--- a/Tests/Core/SecurityContextTest.php
+++ b/Tests/Core/SecurityContextTest.php
@@ -92,6 +92,6 @@ class SecurityContextTest extends \PHPUnit_Framework_TestCase
public function testTranslationsAreNotInCore()
{
- $this->assertFalse(file_exists(__DIR__.'/../../Core/Resources/translations/'));
+ $this->assertFileNotExists(__DIR__.'/../../Core/Resources/translations/');
}
}
diff --git a/Tests/Core/User/UserTest.php b/Tests/Core/User/UserTest.php
index d05f491..eb21503 100644
--- a/Tests/Core/User/UserTest.php
+++ b/Tests/Core/User/UserTest.php
@@ -16,7 +16,6 @@ use Symfony\Component\Security\Core\User\User;
class UserTest extends \PHPUnit_Framework_TestCase
{
/**
- * @covers Symfony\Component\Security\Core\User\User::__construct
* @expectedException \InvalidArgumentException
*/
public function testConstructorException()
@@ -24,10 +23,6 @@ class UserTest extends \PHPUnit_Framework_TestCase
new User('', 'superpass');
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::__construct
- * @covers Symfony\Component\Security\Core\User\User::getRoles
- */
public function testGetRoles()
{
$user = new User('fabien', 'superpass');
@@ -37,38 +32,24 @@ class UserTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('ROLE_ADMIN'), $user->getRoles());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::__construct
- * @covers Symfony\Component\Security\Core\User\User::getPassword
- */
public function testGetPassword()
{
$user = new User('fabien', 'superpass');
$this->assertEquals('superpass', $user->getPassword());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::__construct
- * @covers Symfony\Component\Security\Core\User\User::getUsername
- */
public function testGetUsername()
{
$user = new User('fabien', 'superpass');
$this->assertEquals('fabien', $user->getUsername());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::getSalt
- */
public function testGetSalt()
{
$user = new User('fabien', 'superpass');
$this->assertEquals('', $user->getSalt());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::isAccountNonExpired
- */
public function testIsAccountNonExpired()
{
$user = new User('fabien', 'superpass');
@@ -78,9 +59,6 @@ class UserTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($user->isAccountNonExpired());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::isCredentialsNonExpired
- */
public function testIsCredentialsNonExpired()
{
$user = new User('fabien', 'superpass');
@@ -90,9 +68,6 @@ class UserTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($user->isCredentialsNonExpired());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::isAccountNonLocked
- */
public function testIsAccountNonLocked()
{
$user = new User('fabien', 'superpass');
@@ -102,9 +77,6 @@ class UserTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($user->isAccountNonLocked());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::isEnabled
- */
public function testIsEnabled()
{
$user = new User('fabien', 'superpass');
@@ -114,9 +86,6 @@ class UserTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($user->isEnabled());
}
- /**
- * @covers Symfony\Component\Security\Core\User\User::eraseCredentials
- */
public function testEraseCredentials()
{
$user = new User('fabien', 'superpass');
diff --git a/Tests/Core/Util/SecureRandomTest.php b/Tests/Core/Util/SecureRandomTest.php
deleted file mode 100644
index 9fd1c16..0000000
--- a/Tests/Core/Util/SecureRandomTest.php
+++ /dev/null
@@ -1,201 +0,0 @@
-<?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\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]];
- }
-
- $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];
- };
-
- $currentRun = 0;
- $lastBit = null;
- for ($i = 0; $i < 20000; ++$i) {
- if ($lastBit === $b[$i]) {
- ++$currentRun;
- } 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 = $currentRun = 0;
- $lastBit = null;
- for ($i = 0; $i < 20000; ++$i) {
- if ($lastBit === $b[$i]) {
- ++$currentRun;
- } 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/Http/Firewall/RememberMeListenerTest.php b/Tests/Http/Firewall/RememberMeListenerTest.php
index 067cacb..8316a8c 100644
--- a/Tests/Http/Firewall/RememberMeListenerTest.php
+++ b/Tests/Http/Firewall/RememberMeListenerTest.php
@@ -138,6 +138,69 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase
$listener->handle($event);
}
+ public function testSessionStrategy()
+ {
+ list($listener, $tokenStorage, $service, $manager) = $this->getListener();
+
+ $tokenStorage
+ ->expects($this->once())
+ ->method('getToken')
+ ->will($this->returnValue(null))
+ ;
+
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $service
+ ->expects($this->once())
+ ->method('autoLogin')
+ ->will($this->returnValue($token))
+ ;
+
+ $tokenStorage
+ ->expects($this->once())
+ ->method('setToken')
+ ->with($this->equalTo($token))
+ ;
+
+ $manager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->will($this->returnValue($token))
+ ;
+
+ $session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface');
+ $session
+ ->expects($this->once())
+ ->method('isStarted')
+ ->will($this->returnValue(true))
+ ;
+ $session
+ ->expects($this->once())
+ ->method('migrate')
+ ;
+
+ $request = $this->getMock('\Symfony\Component\HttpFoundation\Request');
+ $request
+ ->expects($this->any())
+ ->method('hasSession')
+ ->will($this->returnValue(true))
+ ;
+
+ $request
+ ->expects($this->any())
+ ->method('getSession')
+ ->will($this->returnValue($session))
+ ;
+
+ $event = $this->getGetResponseEvent();
+ $event
+ ->expects($this->once())
+ ->method('getRequest')
+ ->will($this->returnValue($request))
+ ;
+
+ $listener->handle($event);
+ }
+
protected function getGetResponseEvent()
{
return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false);
diff --git a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php b/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
index 61c3559..3ba8f99 100644
--- a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
+++ b/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php
@@ -24,6 +24,15 @@ use Symfony\Component\Security\Core\Util\SecureRandom;
class PersistentTokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
{
+ public static function setUpBeforeClass()
+ {
+ try {
+ random_bytes(1);
+ } catch (\Exception $e) {
+ throw new \PHPUnit_Framework_SkippedTestError($e->getMessage());
+ }
+ }
+
public function testAutoLoginReturnsNullWhenNoCookie()
{
$service = $this->getService(null, array('name' => 'foo'));
diff --git a/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php b/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php
index b988c7d..d1ec9b2 100644
--- a/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php
+++ b/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php
@@ -172,9 +172,8 @@ class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
{
$service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
$request = new Request();
- $response = new Response();
- $service->loginFail($request, $response);
+ $service->loginFail($request);
$cookie = $request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME);
$this->assertTrue($cookie->isCleared());
diff --git a/Tests/Resources/TranslationFilesTest.php b/Tests/Resources/TranslationFilesTest.php
new file mode 100644
index 0000000..341ec87
--- /dev/null
+++ b/Tests/Resources/TranslationFilesTest.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\Tests\Resources;
+
+class TranslationFilesTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provideTranslationFiles
+ */
+ public function testTranslationFileIsValid($filePath)
+ {
+ \PHPUnit_Util_XML::loadfile($filePath, false, false, true);
+ }
+
+ public function provideTranslationFiles()
+ {
+ return array_map(
+ function ($filePath) { return (array) $filePath; },
+ glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf')
+ );
+ }
+}
diff --git a/composer.json b/composer.json
index bc15cc8..4f265fe 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,7 @@
],
"require": {
"php": ">=5.3.3",
+ "paragonie/random_compat": "~1.0",
"symfony/event-dispatcher": "~2.2",
"symfony/http-foundation": "~2.1",
"symfony/http-kernel": "~2.1"
@@ -43,11 +44,13 @@
"symfony/validator": "",
"symfony/routing": "",
"doctrine/dbal": "to use the built-in ACL implementation",
- "ircmaxell/password-compat": "",
- "paragonie/random_compat": ""
+ "ircmaxell/password-compat": ""
},
"autoload": {
- "psr-0": { "Symfony\\Component\\Security\\": "" }
+ "psr-0": { "Symfony\\Component\\Security\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
},
"target-dir": "Symfony/Component/Security",
"minimum-stability": "dev",
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 9a20f91..9d3cf4a 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -9,6 +9,7 @@
<php>
<ini name="error_reporting" value="-1" />
</php>
+
<testsuites>
<testsuite name="Symfony Security Component Test Suite">
<directory>./Tests/</directory>
@@ -19,8 +20,10 @@
<whitelist>
<directory>./</directory>
<exclude>
- <directory>./vendor</directory>
+ <directory>./Acl/Resources</directory>
+ <directory>./Resources</directory>
<directory>./Tests</directory>
+ <directory>./vendor</directory>
</exclude>
</whitelist>
</filter>