diff options
-rw-r--r-- | Core/Authentication/Token/AbstractToken.php | 9 | ||||
-rw-r--r-- | Core/Tests/Authentication/Token/AbstractTokenTest.php | 41 | ||||
-rw-r--r-- | Core/Tests/Authorization/Voter/ExpressionVoterTest.php | 97 | ||||
-rw-r--r-- | Core/composer.json | 1 | ||||
-rw-r--r-- | Http/Firewall/ContextListener.php | 7 |
5 files changed, 151 insertions, 4 deletions
diff --git a/Core/Authentication/Token/AbstractToken.php b/Core/Authentication/Token/AbstractToken.php index e62f73c..59510ee 100644 --- a/Core/Authentication/Token/AbstractToken.php +++ b/Core/Authentication/Token/AbstractToken.php @@ -142,7 +142,14 @@ abstract class AbstractToken implements TokenInterface */ public function serialize() { - return serialize(array($this->user, $this->authenticated, $this->roles, $this->attributes)); + return serialize( + array( + is_object($this->user) ? clone $this->user : $this->user, + $this->authenticated, + $this->roles, + $this->attributes + ) + ); } /** diff --git a/Core/Tests/Authentication/Token/AbstractTokenTest.php b/Core/Tests/Authentication/Token/AbstractTokenTest.php index 928ee40..098017e 100644 --- a/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Security\Core\Tests\Authentication\Token; +use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Security\Core\Role\SwitchUserRole; class TestUser { @@ -28,6 +30,31 @@ class TestUser } } +class ConcreteToken extends AbstractToken +{ + private $credentials = 'credentials_value'; + + public function __construct($user, array $roles = array()) + { + parent::__construct($roles); + + $this->setUser($user); + } + + public function serialize() + { + return serialize(array($this->credentials, parent::serialize())); + } + + public function unserialize($serialized) + { + list($this->credentials, $parentStr) = unserialize($serialized); + parent::unserialize($parentStr); + } + + public function getCredentials() {} +} + class AbstractTokenTest extends \PHPUnit_Framework_TestCase { public function testGetUsername() @@ -71,6 +98,20 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase $this->assertEquals($token->getAttributes(), $uToken->getAttributes()); } + public function testSerializeParent() + { + $user = new TestUser('fabien'); + $token = new ConcreteToken($user, array('ROLE_FOO')); + + $parentToken = new ConcreteToken($user, array(new SwitchUserRole('ROLE_PREVIOUS', $token))); + $uToken = unserialize(serialize($parentToken)); + + $this->assertEquals( + current($parentToken->getRoles())->getSource()->getUser(), + current($uToken->getRoles())->getSource()->getUser() + ); + } + /** * @covers Symfony\Component\Security\Core\Authentication\Token\AbstractToken::__construct */ diff --git a/Core/Tests/Authorization/Voter/ExpressionVoterTest.php b/Core/Tests/Authorization/Voter/ExpressionVoterTest.php new file mode 100644 index 0000000..dc8ea79 --- /dev/null +++ b/Core/Tests/Authorization/Voter/ExpressionVoterTest.php @@ -0,0 +1,97 @@ +<?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\Tests\Authorization\Voter; + +use Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +use Symfony\Component\Security\Core\Role\Role; + +class ExpressionVoterTest extends \PHPUnit_Framework_TestCase +{ + public function testSupportsAttribute() + { + $expression = $this->createExpression(); + $expressionLanguage = $this->getMock('Symfony\Component\Security\Core\Authorization\ExpressionLanguage'); + $voter = new ExpressionVoter($expressionLanguage, $this->createTrustResolver(), $this->createRoleHierarchy()); + + $this->assertTrue($voter->supportsAttribute($expression)); + } + + /** + * @dataProvider getVoteTests + */ + public function testVote($roles, $attributes, $expected, $tokenExpectsGetRoles = true, $expressionLanguageExpectsEvaluate = true) + { + $voter = new ExpressionVoter($this->createExpressionLanguage($expressionLanguageExpectsEvaluate), $this->createTrustResolver()); + + $this->assertSame($expected, $voter->vote($this->getToken($roles, $tokenExpectsGetRoles), null, $attributes)); + } + + public function getVoteTests() + { + return array( + array(array(), array(), VoterInterface::ACCESS_ABSTAIN, false, false), + array(array(), array('FOO'), VoterInterface::ACCESS_ABSTAIN, false, false), + + array(array(), array($this->createExpression()), VoterInterface::ACCESS_DENIED, true, false), + + array(array('ROLE_FOO'), array($this->createExpression(), $this->createExpression()), VoterInterface::ACCESS_GRANTED), + array(array('ROLE_BAR', 'ROLE_FOO'), array($this->createExpression()), VoterInterface::ACCESS_GRANTED), + ); + } + + protected function getToken(array $roles, $tokenExpectsGetRoles = true) + { + foreach ($roles as $i => $role) { + $roles[$i] = new Role($role); + } + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + + if ($tokenExpectsGetRoles) { + $token->expects($this->once()) + ->method('getRoles') + ->will($this->returnValue($roles)); + } + + return $token; + } + + protected function createExpressionLanguage($expressionLanguageExpectsEvaluate = true) + { + $mock = $this->getMock('Symfony\Component\Security\Core\Authorization\ExpressionLanguage'); + + if ($expressionLanguageExpectsEvaluate) { + $mock->expects($this->once()) + ->method('evaluate') + ->will($this->returnValue(true)); + } + + return $mock; + } + + protected function createTrustResolver() + { + return $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface'); + } + + protected function createRoleHierarchy() + { + return $this->getMock('Symfony\Component\Security\Core\Role\RoleHierarchyInterface'); + } + + protected function createExpression() + { + return $this->getMockBuilder('Symfony\Component\ExpressionLanguage\Expression') + ->disableOriginalConstructor() + ->getMock(); + } +} diff --git a/Core/composer.json b/Core/composer.json index 09b9765..249d4c1 100644 --- a/Core/composer.json +++ b/Core/composer.json @@ -20,6 +20,7 @@ }, "require-dev": { "symfony/event-dispatcher": "~2.1", + "symfony/expression-language": "~2.4", "symfony/http-foundation": "~2.4", "symfony/validator": "~2.2", "psr/log": "~1.0", diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php index 2db79f3..05e260e 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -155,10 +155,11 @@ class ContextListener implements ListenerInterface foreach ($this->userProviders as $provider) { try { - $token->setUser($provider->refreshUser($user)); + $refreshedUser = $provider->refreshUser($user); + $token->setUser($refreshedUser); if (null !== $this->logger) { - $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $user->getUsername())); + $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $refreshedUser->getUsername())); } return $token; @@ -166,7 +167,7 @@ class ContextListener implements ListenerInterface // let's try the next user provider } catch (UsernameNotFoundException $notFound) { if (null !== $this->logger) { - $this->logger->warning(sprintf('Username "%s" could not be found.', $user->getUsername())); + $this->logger->warning(sprintf('Username "%s" could not be found.', $notFound->getUsername())); } return null; |