diff options
-rw-r--r-- | Acl/Domain/ObjectIdentity.php | 4 | ||||
-rw-r--r-- | Acl/Tests/Domain/EntryTest.php | 2 | ||||
-rw-r--r-- | Acl/Tests/Domain/ObjectIdentityTest.php | 24 | ||||
-rw-r--r-- | Core/Authorization/AccessDecisionManager.php | 16 | ||||
-rw-r--r-- | Core/Tests/Authorization/AccessDecisionManagerTest.php | 8 | ||||
-rw-r--r-- | Http/Firewall/ExceptionListener.php | 2 | ||||
-rw-r--r-- | Http/RememberMe/AbstractRememberMeServices.php | 8 | ||||
-rw-r--r-- | Http/RememberMe/PersistentTokenBasedRememberMeServices.php | 1 | ||||
-rw-r--r-- | Http/RememberMe/TokenBasedRememberMeServices.php | 6 | ||||
-rw-r--r-- | Http/Tests/RememberMe/AbstractRememberMeServicesTest.php | 34 | ||||
-rw-r--r-- | Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php | 19 | ||||
-rw-r--r-- | Resources/translations/security.fr.xlf | 12 |
12 files changed, 104 insertions, 32 deletions
diff --git a/Acl/Domain/ObjectIdentity.php b/Acl/Domain/ObjectIdentity.php index 907b1d8..fc5b9c6 100644 --- a/Acl/Domain/ObjectIdentity.php +++ b/Acl/Domain/ObjectIdentity.php @@ -36,7 +36,7 @@ final class ObjectIdentity implements ObjectIdentityInterface */ public function __construct($identifier, $type) { - if (empty($identifier)) { + if ('' === $identifier) { throw new \InvalidArgumentException('$identifier cannot be empty.'); } if (empty($type)) { @@ -66,7 +66,7 @@ final class ObjectIdentity implements ObjectIdentityInterface if ($domainObject instanceof DomainObjectInterface) { return new self($domainObject->getObjectIdentifier(), ClassUtils::getRealClass($domainObject)); } elseif (method_exists($domainObject, 'getId')) { - return new self($domainObject->getId(), ClassUtils::getRealClass($domainObject)); + return new self((string) $domainObject->getId(), ClassUtils::getRealClass($domainObject)); } } catch (\InvalidArgumentException $invalid) { throw new InvalidDomainObjectException($invalid->getMessage(), 0, $invalid); diff --git a/Acl/Tests/Domain/EntryTest.php b/Acl/Tests/Domain/EntryTest.php index 6a2aac0..ab8e481 100644 --- a/Acl/Tests/Domain/EntryTest.php +++ b/Acl/Tests/Domain/EntryTest.php @@ -36,7 +36,7 @@ class EntryTest extends \PHPUnit_Framework_TestCase $this->assertTrue($ace->isAuditSuccess()); $ace->setAuditSuccess(false); $this->assertFalse($ace->isAuditSuccess()); - $ace->setAuditsuccess(true); + $ace->setAuditSuccess(true); $this->assertTrue($ace->isAuditSuccess()); } diff --git a/Acl/Tests/Domain/ObjectIdentityTest.php b/Acl/Tests/Domain/ObjectIdentityTest.php index 4eab7b2..325bb91 100644 --- a/Acl/Tests/Domain/ObjectIdentityTest.php +++ b/Acl/Tests/Domain/ObjectIdentityTest.php @@ -64,6 +64,26 @@ namespace Symfony\Component\Security\Acl\Tests\Domain $this->assertEquals('Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType()); } + public function testFromDomainObjectWithoutInterfaceEnforcesStringIdentifier() + { + $domainObject = new TestDomainObject(); + $domainObject->id = 1; + $id = ObjectIdentity::fromDomainObject($domainObject); + + $this->assertSame('1', $id->getIdentifier()); + $this->assertEquals('Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + } + + public function testFromDomainObjectWithoutInterfaceAllowsZeroAsIdentifier() + { + $domainObject = new TestDomainObject(); + $domainObject->id = '0'; + $id = ObjectIdentity::fromDomainObject($domainObject); + + $this->assertSame('0', $id->getIdentifier()); + $this->assertEquals('Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + } + /** * @dataProvider getCompareData */ @@ -89,6 +109,8 @@ namespace Symfony\Component\Security\Acl\Tests\Domain class TestDomainObject { + public $id = 'getId()'; + public function getObjectIdentifier() { return 'getObjectIdentifier()'; @@ -96,7 +118,7 @@ namespace Symfony\Component\Security\Acl\Tests\Domain public function getId() { - return 'getId()'; + return $this->id; } } } diff --git a/Core/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php index b8b6a77..61debe3 100644 --- a/Core/Authorization/AccessDecisionManager.php +++ b/Core/Authorization/AccessDecisionManager.php @@ -41,12 +41,8 @@ class AccessDecisionManager implements AccessDecisionManagerInterface * * @throws \InvalidArgumentException */ - public function __construct(array $voters, $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true) + public function __construct(array $voters = array(), $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true) { - if (!$voters) { - throw new \InvalidArgumentException('You must at least add one voter.'); - } - $strategyMethod = 'decide'.ucfirst($strategy); if (!is_callable(array($this, $strategyMethod))) { throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.', $strategy)); @@ -59,6 +55,16 @@ class AccessDecisionManager implements AccessDecisionManagerInterface } /** + * Configures the voters. + * + * @param VoterInterface[] $voters An array of VoterInterface instances + */ + public function setVoters(array $voters) + { + $this->voters = $voters; + } + + /** * {@inheritdoc} */ public function decide(TokenInterface $token, array $attributes, $object = null) diff --git a/Core/Tests/Authorization/AccessDecisionManagerTest.php b/Core/Tests/Authorization/AccessDecisionManagerTest.php index 3c970d1..bd876c7 100644 --- a/Core/Tests/Authorization/AccessDecisionManagerTest.php +++ b/Core/Tests/Authorization/AccessDecisionManagerTest.php @@ -49,14 +49,6 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase /** * @expectedException \InvalidArgumentException */ - public function testSetVotersEmpty() - { - $manager = new AccessDecisionManager(array()); - } - - /** - * @expectedException \InvalidArgumentException - */ public function testSetUnsupportedStrategy() { new AccessDecisionManager(array($this->getVoter(VoterInterface::ACCESS_GRANTED)), 'fooBar'); diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php index 213a837..6d1f27d 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -205,7 +205,7 @@ class ExceptionListener protected function setTargetPath(Request $request) { // session isn't required when using HTTP basic authentication mechanism for example - if ($request->hasSession() && $request->isMethodSafe()) { + if ($request->hasSession() && $request->isMethodSafe() && !$request->isXmlHttpRequest()) { $request->getSession()->set('_security.'.$this->providerKey.'.target_path', $request->getUri()); } } diff --git a/Http/RememberMe/AbstractRememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php index 3ac584a..5df82fa 100644 --- a/Http/RememberMe/AbstractRememberMeServices.php +++ b/Http/RememberMe/AbstractRememberMeServices.php @@ -268,9 +268,17 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface * @param array $cookieParts * * @return string + * + * @throws \InvalidArgumentException When $cookieParts contain the cookie delimiter. Extending class should either remove or escape it. */ protected function encodeCookie(array $cookieParts) { + foreach ($cookieParts as $cookiePart) { + if (false !== strpos($cookiePart, self::COOKIE_DELIMITER)) { + throw new \InvalidArgumentException(sprintf('$cookieParts should not contain the cookie delimiter "%s"', self::COOKIE_DELIMITER)); + } + } + return base64_encode(implode(self::COOKIE_DELIMITER, $cookieParts)); } diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index f800668..4fb7e09 100644 --- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -98,7 +98,6 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices throw new AuthenticationException('The cookie has expired.'); } - $series = $persistentToken->getSeries(); $tokenValue = base64_encode($this->secureRandom->nextBytes(64)); $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime()); $request->attributes->set(self::COOKIE_ATTR_NAME, diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php index 3fe39ac..65bac0a 100644 --- a/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/Http/RememberMe/TokenBasedRememberMeServices.php @@ -95,12 +95,12 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices * @param int $expires The Unix timestamp when the cookie expires * @param string $password The encoded password * - * @throws \RuntimeException if username contains invalid chars - * * @return string */ protected function generateCookieValue($class, $username, $expires, $password) { + // $username is encoded because it might contain COOKIE_DELIMITER, + // we assume other values don't return $this->encodeCookie(array( $class, base64_encode($username), @@ -117,8 +117,6 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices * @param int $expires The Unix timestamp when the cookie expires * @param string $password The encoded password * - * @throws \RuntimeException when the private key is empty - * * @return string */ protected function generateCookieHash($class, $username, $expires, $password) diff --git a/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index c3d9260..2225b6c 100644 --- a/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php +++ b/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Http\Tests\RememberMe; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Http\RememberMe\AbstractRememberMeServices; class AbstractRememberMeServicesTest extends \PHPUnit_Framework_TestCase { @@ -236,6 +237,30 @@ class AbstractRememberMeServicesTest extends \PHPUnit_Framework_TestCase ); } + public function testEncodeCookieAndDecodeCookieAreInvertible() + { + $cookieParts = array('aa', 'bb', 'cc'); + $service = $this->getService(); + + $encoded = $this->callProtected($service, 'encodeCookie', array($cookieParts)); + $this->assertInternalType('string', $encoded); + + $decoded = $this->callProtected($service, 'decodeCookie', array($encoded)); + $this->assertSame($cookieParts, $decoded); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage cookie delimiter + */ + public function testThereShouldBeNoCookieDelimiterInCookieParts() + { + $cookieParts = array('aa', 'b'.AbstractRememberMeServices::COOKIE_DELIMITER.'b', 'cc'); + $service = $this->getService(); + + $this->callProtected($service, 'encodeCookie', array($cookieParts)); + } + protected function getService($userProvider = null, $options = array(), $logger = null) { if (null === $userProvider) { @@ -258,4 +283,13 @@ class AbstractRememberMeServicesTest extends \PHPUnit_Framework_TestCase return $provider; } + + private function callProtected($object, $method, array $args) + { + $reflection = new \ReflectionClass(get_class($object)); + $reflectionMethod = $reflection->getMethod($method); + $reflectionMethod->setAccessible(true); + + return $reflectionMethod->invokeArgs($object, $args); + } } diff --git a/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php index 9801bc8..8383cec 100644 --- a/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php +++ b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php @@ -105,7 +105,12 @@ class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase $this->assertTrue($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)->isCleared()); } - public function testAutoLogin() + /** + * @dataProvider provideUsernamesForAutoLogin + * + * @param string $username + */ + public function testAutoLogin($username) { $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); $user @@ -123,13 +128,13 @@ class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase $userProvider ->expects($this->once()) ->method('loadUserByUsername') - ->with($this->equalTo('foouser')) + ->with($this->equalTo($username)) ->will($this->returnValue($user)) ; $service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600)); $request = new Request(); - $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time() + 3600, 'foopass')); + $request->cookies->set('foo', $this->getCookie('fooclass', $username, time() + 3600, 'foopass')); $returnedToken = $service->autoLogin($request); @@ -138,6 +143,14 @@ class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('fookey', $returnedToken->getKey()); } + public function provideUsernamesForAutoLogin() + { + return array( + array('foouser', 'Simple username'), + array('foo'.TokenBasedRememberMeServices::COOKIE_DELIMITER.'user', 'Username might contain the delimiter'), + ); + } + public function testLogout() { $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null)); diff --git a/Resources/translations/security.fr.xlf b/Resources/translations/security.fr.xlf index f3965d3..5a77c6e 100644 --- a/Resources/translations/security.fr.xlf +++ b/Resources/translations/security.fr.xlf @@ -8,7 +8,7 @@ </trans-unit> <trans-unit id="2"> <source>Authentication credentials could not be found.</source> - <target>Les droits d'authentification n'ont pas pu être trouvés.</target> + <target>Les identifiants d'authentification n'ont pas pu être trouvés.</target> </trans-unit> <trans-unit id="3"> <source>Authentication request could not be processed due to a system problem.</source> @@ -16,7 +16,7 @@ </trans-unit> <trans-unit id="4"> <source>Invalid credentials.</source> - <target>Droits invalides.</target> + <target>Identifiants invalides.</target> </trans-unit> <trans-unit id="5"> <source>Cookie has already been used by someone else.</source> @@ -24,7 +24,7 @@ </trans-unit> <trans-unit id="6"> <source>Not privileged to request the resource.</source> - <target>Pas de privilèges pour accéder à la ressource.</target> + <target>Privilèges insuffisants pour accéder à la ressource.</target> </trans-unit> <trans-unit id="7"> <source>Invalid CSRF token.</source> @@ -40,7 +40,7 @@ </trans-unit> <trans-unit id="10"> <source>No session available, it either timed out or cookies are not enabled.</source> - <target>Pas de session disponible, celle-ci a expiré ou les cookies ne sont pas activés.</target> + <target>Aucune session disponible, celle-ci a expiré ou les cookies ne sont pas activés.</target> </trans-unit> <trans-unit id="11"> <source>No token could be found.</source> @@ -48,7 +48,7 @@ </trans-unit> <trans-unit id="12"> <source>Username could not be found.</source> - <target>Le nom d'utilisateur ne peut pas être trouvé.</target> + <target>Le nom d'utilisateur n'a pas pu être trouvé.</target> </trans-unit> <trans-unit id="13"> <source>Account has expired.</source> @@ -56,7 +56,7 @@ </trans-unit> <trans-unit id="14"> <source>Credentials have expired.</source> - <target>Les droits ont expirés.</target> + <target>Les identifiants ont expiré.</target> </trans-unit> <trans-unit id="15"> <source>Account is disabled.</source> |