diff --git a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php index b578710546..76bbbe7c57 100755 --- a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php +++ b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -172,7 +172,7 @@ class HttpClientDataCollectorTest extends TestCase foreach ($tracedRequests as $request) { $response = $httpClient->request($request['method'], $request['url'], $request['options'] ?? []); - $response->getContent(false); // To avoid exception in ResponseTrait::doDestruct + $response->getContent(false); // disables exceptions from destructors } return $httpClient; diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 7c1f36f7aa..f5e64651ba 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -408,11 +408,11 @@ class PropertyAccessor implements PropertyAccessorInterface // handle uninitialized properties in PHP >= 7 if (__FILE__ === $trace['file'] - && $access[self::ACCESS_NAME] === $trace['function'] + && $name === $trace['function'] && $object instanceof $trace['class'] && preg_match((sprintf('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/')), $e->getMessage(), $matches) ) { - throw new UninitializedPropertyException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: 'class').'@anonymous', $access[self::ACCESS_NAME], $matches[1]), 0, $e); + throw new UninitializedPropertyException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: key(class_implements($object)) ?: 'class').'@anonymous', $name, $matches[1]), 0, $e); } throw $e; diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index 94c37aab4d..9106334b99 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -270,10 +270,13 @@ abstract class AbstractToken implements TokenInterface return true; } - $currentUserRoles = array_map('strval', (array) $this->user->getRoles()); $userRoles = array_map('strval', (array) $user->getRoles()); - if (\count($userRoles) !== \count($currentUserRoles) || \count($userRoles) !== \count(array_intersect($userRoles, $currentUserRoles))) { + if ($this instanceof SwitchUserToken) { + $userRoles[] = 'ROLE_PREVIOUS_ADMIN'; + } + + if (\count($userRoles) !== \count($this->getRoleNames()) || \count($userRoles) !== \count(array_intersect($userRoles, $this->getRoleNames()))) { return true; } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 769646c1a3..2cd992737d 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -152,7 +152,7 @@ class AbstractTokenTest extends TestCase */ public function testSetUserDoesNotSetAuthenticatedToFalseWhenUserDoesNotChange($user) { - $token = new ConcreteToken(['ROLE_FOO']); + $token = new ConcreteToken(); $token->setAuthenticated(true); $this->assertTrue($token->isAuthenticated()); @@ -162,6 +162,21 @@ class AbstractTokenTest extends TestCase $token->setUser($user); $this->assertTrue($token->isAuthenticated()); } + + public function testIsUserChangedWhenSerializing() + { + $token = new ConcreteToken(['ROLE_ADMIN']); + $token->setAuthenticated(true); + $this->assertTrue($token->isAuthenticated()); + + $user = new SerializableUser('wouter', ['ROLE_ADMIN']); + $token->setUser($user); + $this->assertTrue($token->isAuthenticated()); + + $token = unserialize(serialize($token)); + $token->setUser($user); + $this->assertTrue($token->isAuthenticated()); + } } class TestUser @@ -179,6 +194,56 @@ class TestUser } } +class SerializableUser implements UserInterface, \Serializable +{ + private $roles; + private $name; + + public function __construct($name, array $roles = []) + { + $this->name = $name; + $this->roles = $roles; + } + + public function getUsername() + { + return $this->name; + } + + public function getPassword() + { + return '***'; + } + + public function getRoles() + { + if (empty($this->roles)) { + return ['ROLE_USER']; + } + + return $this->roles; + } + + public function eraseCredentials() + { + } + + public function getSalt() + { + return null; + } + + public function serialize() + { + return serialize($this->name); + } + + public function unserialize($serialized) + { + $this->name = unserialize($serialized); + } +} + class ConcreteToken extends AbstractToken { private $credentials = 'credentials_value'; diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php index eab003854d..50790fba05 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php @@ -29,8 +29,7 @@ class ExpressionLanguageSyntax extends Constraint public $message = 'This value should be a valid expression.'; public $service; - public $validateNames = true; - public $names = []; + public $allowedVariables = null; /** * {@inheritdoc} diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php index e7104452e7..4b67da2c2b 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php @@ -16,6 +16,7 @@ use Symfony\Component\ExpressionLanguage\SyntaxError; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; /** * @author Andrey Sevastianov @@ -39,7 +40,7 @@ class ExpressionLanguageSyntaxValidator extends ConstraintValidator } if (!\is_string($expression)) { - throw new UnexpectedTypeException($expression, 'string'); + throw new UnexpectedValueException($expression, 'string'); } if (null === $this->expressionLanguage) { @@ -47,7 +48,7 @@ class ExpressionLanguageSyntaxValidator extends ConstraintValidator } try { - $this->expressionLanguage->lint($expression, ($constraint->validateNames ? ($constraint->names ?? []) : null)); + $this->expressionLanguage->lint($expression, $constraint->allowedVariables); } catch (SyntaxError $exception) { $this->context->buildViolation($constraint->message) ->setParameter('{{ syntax_error }}', $this->formatValue($exception->getMessage())) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxValidatorTest.php similarity index 94% rename from src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxTest.php rename to src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxValidatorTest.php index dc80288c38..7db835b333 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxValidatorTest.php @@ -18,7 +18,7 @@ use Symfony\Component\Validator\Constraints\ExpressionLanguageSyntax; use Symfony\Component\Validator\Constraints\ExpressionLanguageSyntaxValidator; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; -class ExpressionLanguageSyntaxTest extends ConstraintValidatorTestCase +class ExpressionLanguageSyntaxValidatorTest extends ConstraintValidatorTestCase { /** * @var \PHPUnit\Framework\MockObject\MockObject|ExpressionLanguage @@ -45,6 +45,7 @@ class ExpressionLanguageSyntaxTest extends ConstraintValidatorTestCase $this->validator->validate($this->value, new ExpressionLanguageSyntax([ 'message' => 'myMessage', + 'allowedVariables' => [], ])); $this->assertNoViolation(); @@ -58,7 +59,6 @@ class ExpressionLanguageSyntaxTest extends ConstraintValidatorTestCase $this->validator->validate($this->value, new ExpressionLanguageSyntax([ 'message' => 'myMessage', - 'validateNames' => false, ])); $this->assertNoViolation(); @@ -73,6 +73,7 @@ class ExpressionLanguageSyntaxTest extends ConstraintValidatorTestCase $this->validator->validate($this->value, new ExpressionLanguageSyntax([ 'message' => 'myMessage', + 'allowedVariables' => [], ])); $this->buildViolation('myMessage')