Merge branch '4.0'
* 4.0: (22 commits) [appveyor] use PHP 7.1 to run composer [HttpKernel] Don't clean legacy containers that are still loaded [VarDumper] Fix HtmlDumper classes match Make the simple auth provider the same as in Symfony 2.7. [PhpUnitBridge] silence wget fix merge [Security] guardAuthenticationProvider::authenticate cannot return null according to interface specification [PhpUnitBridge] Fix #26994 [VarDumper] Remove decoration from actual output in tests [PropertyInfo] Minor cleanup and perf improvement [Bridge/Doctrine] fix count() notice on PHP 7.2 [Security] Skip user checks if not implementing UserInterface [DI] Add check of internal type to ContainerBuilder::getReflectionClass [HttpFoundation] Add HTTP_EARLY_HINTS const [DoctrineBridge] Improve exception message at `IdReader::getIdValue()` Add type hints fixed CS Use new PHP7.2 functions in hasColorSupport [VarDumper] Fix dumping of SplObjectStorage [HttpFoundation] Add functional tests for Response::sendHeaders() ...
This commit is contained in:
commit
e035f45637
@ -45,7 +45,7 @@ install:
|
||||
- copy /Y .composer\* %APPDATA%\Composer\
|
||||
- php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit
|
||||
- IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev)
|
||||
- php -dmemory_limit=-1 composer.phar update --no-progress --no-suggest --ansi
|
||||
- php composer.phar update --no-progress --no-suggest --ansi
|
||||
- php phpunit install
|
||||
|
||||
test_script:
|
||||
|
@ -95,10 +95,7 @@ class IdReader
|
||||
}
|
||||
|
||||
if (!$this->om->contains($object)) {
|
||||
throw new RuntimeException(
|
||||
'Entities passed to the choice field must be managed. Maybe '.
|
||||
'persist them in the entity manager?'
|
||||
);
|
||||
throw new RuntimeException(sprintf('Entity of type "%s" passed to the choice field must be managed. Maybe you forget to persist it in the entity manager?', get_class($object)));
|
||||
}
|
||||
|
||||
$this->om->initializeObject($object);
|
||||
|
@ -630,6 +630,34 @@ class UniqueEntityValidatorTest extends ConstraintValidatorTestCase
|
||||
$this->validator->validate($entity, $constraint);
|
||||
}
|
||||
|
||||
public function testValidateUniquenessOnNullResult()
|
||||
{
|
||||
$repository = $this->createRepositoryMock();
|
||||
$repository
|
||||
->method('find')
|
||||
->will($this->returnValue(null))
|
||||
;
|
||||
|
||||
$this->em = $this->createEntityManagerMock($repository);
|
||||
$this->registry = $this->createRegistryMock($this->em);
|
||||
$this->validator = $this->createValidator();
|
||||
$this->validator->initialize($this->context);
|
||||
|
||||
$constraint = new UniqueEntity(array(
|
||||
'message' => 'myMessage',
|
||||
'fields' => array('name'),
|
||||
'em' => self::EM_NAME,
|
||||
));
|
||||
|
||||
$entity = new SingleIntIdEntity(1, null);
|
||||
|
||||
$this->em->persist($entity);
|
||||
$this->em->flush();
|
||||
|
||||
$this->validator->validate($entity, $constraint);
|
||||
$this->assertNoViolation();
|
||||
}
|
||||
|
||||
public function testValidateInheritanceUniqueness()
|
||||
{
|
||||
$constraint = new UniqueEntity(array(
|
||||
|
@ -148,15 +148,23 @@ class UniqueEntityValidator extends ConstraintValidator
|
||||
*/
|
||||
if ($result instanceof \Iterator) {
|
||||
$result->rewind();
|
||||
} elseif (is_array($result)) {
|
||||
if ($result instanceof \Countable && 1 < \count($result)) {
|
||||
$result = array($result->current(), $result->current());
|
||||
} else {
|
||||
$result = $result->current();
|
||||
$result = null === $result ? array() : array($result);
|
||||
}
|
||||
} elseif (\is_array($result)) {
|
||||
reset($result);
|
||||
} else {
|
||||
$result = null === $result ? array() : array($result);
|
||||
}
|
||||
|
||||
/* If no entity matched the query criteria or a single entity matched,
|
||||
* which is the same as the entity being validated, the criteria is
|
||||
* unique.
|
||||
*/
|
||||
if (0 === count($result) || (1 === count($result) && $entity === ($result instanceof \Iterator ? $result->current() : current($result)))) {
|
||||
if (!$result || (1 === \count($result) && current($result) === $entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -297,17 +297,38 @@ class DeprecationErrorHandler
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if STDOUT is defined and supports colorization.
|
||||
*
|
||||
* Reference: Composer\XdebugHandler\Process::supportsColor
|
||||
* https://github.com/composer/xdebug-handler
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function hasColorSupport()
|
||||
{
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
return
|
||||
defined('STDOUT') && function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(STDOUT)
|
||||
|| '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD
|
||||
if (!defined('STDOUT')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
return (function_exists('sapi_windows_vt100_support')
|
||||
&& sapi_windows_vt100_support(STDOUT))
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
}
|
||||
|
||||
return defined('STDOUT') && function_exists('posix_isatty') && @posix_isatty(STDOUT);
|
||||
if (function_exists('stream_isatty')) {
|
||||
return stream_isatty(STDOUT);
|
||||
}
|
||||
|
||||
if (function_exists('posix_isatty')) {
|
||||
return posix_isatty(STDOUT);
|
||||
}
|
||||
|
||||
$stat = fstat(STDOUT);
|
||||
// Check if formatted mode is S_IFCHR
|
||||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ namespace Symfony\Bridge\PhpUnit\Legacy;
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Command extends \PHPUnit_TextUI_Command
|
||||
class CommandForV5 extends \PHPUnit_TextUI_Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createRunner()
|
||||
{
|
||||
return new TestRunner($this->arguments['loader']);
|
||||
return new TestRunnerForV5($this->arguments['loader']);
|
||||
}
|
||||
}
|
32
src/Symfony/Bridge/PhpUnit/Legacy/CommandForV6.php
Normal file
32
src/Symfony/Bridge/PhpUnit/Legacy/CommandForV6.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?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\Bridge\PhpUnit\Legacy;
|
||||
|
||||
use PHPUnit\TextUI\Command as BaseCommand;
|
||||
use PHPUnit\TextUI\TestRunner as BaseRunner;
|
||||
use Symfony\Bridge\PhpUnit\TextUI\TestRunner;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CommandForV6 extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createRunner(): BaseRunner
|
||||
{
|
||||
return new TestRunner($this->arguments['loader']);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace Symfony\Bridge\PhpUnit\Legacy;
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TestRunner extends \PHPUnit_TextUI_TestRunner
|
||||
class TestRunnerForV5 extends \PHPUnit_TextUI_TestRunner
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
49
src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV6.php
Normal file
49
src/Symfony/Bridge/PhpUnit/Legacy/TestRunnerForV6.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?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\Bridge\PhpUnit\Legacy;
|
||||
|
||||
use PHPUnit\TextUI\TestRunner as BaseRunner;
|
||||
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TestRunnerForV6 extends BaseRunner
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function handleConfiguration(array &$arguments): void
|
||||
{
|
||||
$listener = new SymfonyTestsListener();
|
||||
|
||||
parent::handleConfiguration($arguments);
|
||||
|
||||
$arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array();
|
||||
|
||||
$registeredLocally = false;
|
||||
|
||||
foreach ($arguments['listeners'] as $registeredListener) {
|
||||
if ($registeredListener instanceof SymfonyTestsListener) {
|
||||
$registeredListener->globalListenerDisabled();
|
||||
$registeredLocally = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$registeredLocally) {
|
||||
$arguments['listeners'][] = $listener;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,24 +11,14 @@
|
||||
|
||||
namespace Symfony\Bridge\PhpUnit\TextUI;
|
||||
|
||||
use PHPUnit\TextUI\Command as BaseCommand;
|
||||
|
||||
if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) {
|
||||
class_alias('Symfony\Bridge\PhpUnit\Legacy\Command', 'Symfony\Bridge\PhpUnit\TextUI\Command');
|
||||
class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV5', 'Symfony\Bridge\PhpUnit\TextUI\Command');
|
||||
} else {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Command extends BaseCommand
|
||||
class_alias('Symfony\Bridge\PhpUnit\Legacy\CommandForV6', 'Symfony\Bridge\PhpUnit\TextUI\Command');
|
||||
}
|
||||
|
||||
if (false) {
|
||||
class Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createRunner()
|
||||
{
|
||||
return new TestRunner($this->arguments['loader']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,45 +11,14 @@
|
||||
|
||||
namespace Symfony\Bridge\PhpUnit\TextUI;
|
||||
|
||||
use PHPUnit\TextUI\TestRunner as BaseRunner;
|
||||
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
|
||||
|
||||
if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) {
|
||||
class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunner', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner');
|
||||
class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunnerForV5', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner');
|
||||
} else {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TestRunner extends BaseRunner
|
||||
class_alias('Symfony\Bridge\PhpUnit\Legacy\TestRunnerForV6', 'Symfony\Bridge\PhpUnit\TextUI\TestRunner');
|
||||
}
|
||||
|
||||
if (false) {
|
||||
class TestRunner
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function handleConfiguration(array &$arguments)
|
||||
{
|
||||
$listener = new SymfonyTestsListener();
|
||||
|
||||
$result = parent::handleConfiguration($arguments);
|
||||
|
||||
$arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array();
|
||||
|
||||
$registeredLocally = false;
|
||||
|
||||
foreach ($arguments['listeners'] as $registeredListener) {
|
||||
if ($registeredListener instanceof SymfonyTestsListener) {
|
||||
$registeredListener->globalListenerDisabled();
|
||||
$registeredLocally = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$registeredLocally) {
|
||||
$arguments['listeners'][] = $listener;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__
|
||||
stream_copy_to_stream($remoteZipStream, fopen("$PHPUNIT_VERSION.zip", 'wb'));
|
||||
} else {
|
||||
@unlink("$PHPUNIT_VERSION.zip");
|
||||
passthru("wget https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip");
|
||||
passthru("wget -q https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip");
|
||||
}
|
||||
if (!class_exists('ZipArchive')) {
|
||||
throw new \Exception('simple-phpunit requires the "zip" PHP extension to be installed and enabled in order to uncompress the downloaded PHPUnit packages.');
|
||||
|
@ -83,31 +83,34 @@ class StreamOutput extends Output
|
||||
*
|
||||
* Colorization is disabled if not supported by the stream:
|
||||
*
|
||||
* - the stream is redirected (eg php file.php >log)
|
||||
* - Windows without VT100 support, Ansicon, ConEmu, Mintty
|
||||
* - non tty consoles
|
||||
* This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
|
||||
* terminals via named pipes, so we can only check the environment.
|
||||
*
|
||||
* Reference: Composer\XdebugHandler\Process::supportsColor
|
||||
* https://github.com/composer/xdebug-handler
|
||||
*
|
||||
* @return bool true if the stream supports colorization, false otherwise
|
||||
*/
|
||||
protected function hasColorSupport()
|
||||
{
|
||||
if (function_exists('stream_isatty') && !@stream_isatty($this->stream)) {
|
||||
return false;
|
||||
}
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
if (function_exists('sapi_windows_vt100_support')) {
|
||||
$vt100Enabled = @sapi_windows_vt100_support($this->stream);
|
||||
} else {
|
||||
$vt100Enabled = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD;
|
||||
}
|
||||
|
||||
return
|
||||
$vt100Enabled
|
||||
return (function_exists('sapi_windows_vt100_support')
|
||||
&& @sapi_windows_vt100_support($this->stream))
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
}
|
||||
|
||||
return function_exists('posix_isatty') && @posix_isatty($this->stream);
|
||||
if (function_exists('stream_isatty')) {
|
||||
return @stream_isatty($this->stream);
|
||||
}
|
||||
|
||||
if (function_exists('posix_isatty')) {
|
||||
return @posix_isatty($this->stream);
|
||||
}
|
||||
|
||||
$stat = @fstat($this->stream);
|
||||
// Check if formatted mode is S_IFCHR
|
||||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,20 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
private $removedIds = array();
|
||||
private $alreadyLoading = array();
|
||||
|
||||
private static $internalTypes = array(
|
||||
'int' => true,
|
||||
'float' => true,
|
||||
'string' => true,
|
||||
'bool' => true,
|
||||
'resource' => true,
|
||||
'object' => true,
|
||||
'array' => true,
|
||||
'null' => true,
|
||||
'callable' => true,
|
||||
'iterable' => true,
|
||||
'mixed' => true,
|
||||
);
|
||||
|
||||
public function __construct(ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
parent::__construct($parameterBag);
|
||||
@ -321,6 +335,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
if (!$class = $this->getParameterBag()->resolveValue($class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset(self::$internalTypes[$class])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$resource = null;
|
||||
|
||||
try {
|
||||
|
@ -880,6 +880,23 @@ class ContainerBuilderTest extends TestCase
|
||||
$this->assertSame('BarMissingClass', (string) end($resources));
|
||||
}
|
||||
|
||||
public function testGetReflectionClassOnInternalTypes()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$this->assertNull($container->getReflectionClass('int'));
|
||||
$this->assertNull($container->getReflectionClass('float'));
|
||||
$this->assertNull($container->getReflectionClass('string'));
|
||||
$this->assertNull($container->getReflectionClass('bool'));
|
||||
$this->assertNull($container->getReflectionClass('resource'));
|
||||
$this->assertNull($container->getReflectionClass('object'));
|
||||
$this->assertNull($container->getReflectionClass('array'));
|
||||
$this->assertNull($container->getReflectionClass('null'));
|
||||
$this->assertNull($container->getReflectionClass('callable'));
|
||||
$this->assertNull($container->getReflectionClass('iterable'));
|
||||
$this->assertNull($container->getReflectionClass('mixed'));
|
||||
}
|
||||
|
||||
public function testCompilesClassDefinitionsOfLazyServices()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
@ -131,12 +131,12 @@ class Cookie
|
||||
$str = ($this->isRaw() ? $this->getName() : urlencode($this->getName())).'=';
|
||||
|
||||
if ('' === (string) $this->getValue()) {
|
||||
$str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; max-age=-31536001';
|
||||
$str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0';
|
||||
} else {
|
||||
$str .= $this->isRaw() ? $this->getValue() : rawurlencode($this->getValue());
|
||||
|
||||
if (0 !== $this->getExpiresTime()) {
|
||||
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime()).'; max-age='.$this->getMaxAge();
|
||||
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime()).'; Max-Age='.$this->getMaxAge();
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,7 +210,9 @@ class Cookie
|
||||
*/
|
||||
public function getMaxAge()
|
||||
{
|
||||
return 0 !== $this->expire ? $this->expire - time() : 0;
|
||||
$maxAge = $this->expire - time();
|
||||
|
||||
return 0 >= $maxAge ? 0 : $maxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@ class Response
|
||||
const HTTP_CONTINUE = 100;
|
||||
const HTTP_SWITCHING_PROTOCOLS = 101;
|
||||
const HTTP_PROCESSING = 102; // RFC2518
|
||||
const HTTP_EARLY_HINTS = 103; // RFC8297
|
||||
const HTTP_OK = 200;
|
||||
const HTTP_CREATED = 201;
|
||||
const HTTP_ACCEPTED = 202;
|
||||
@ -323,7 +324,7 @@ class Response
|
||||
}
|
||||
|
||||
// headers
|
||||
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
|
||||
foreach ($this->headers->allPreserveCase() as $name => $values) {
|
||||
foreach ($values as $value) {
|
||||
header($name.': '.$value, false, $this->statusCode);
|
||||
}
|
||||
@ -332,15 +333,6 @@ class Response
|
||||
// status
|
||||
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
|
||||
|
||||
// cookies
|
||||
foreach ($this->headers->getCookies() as $cookie) {
|
||||
if ($cookie->isRaw()) {
|
||||
setrawcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
|
||||
} else {
|
||||
setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -159,13 +159,13 @@ class CookieTest extends TestCase
|
||||
public function testToString()
|
||||
{
|
||||
$cookie = new Cookie('foo', 'bar', $expire = strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
|
||||
$this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; max-age='.($expire - time()).'; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie');
|
||||
$this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie');
|
||||
|
||||
$cookie = new Cookie('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
|
||||
$this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; max-age='.($expire - time()).'; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)');
|
||||
$this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)');
|
||||
|
||||
$cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com');
|
||||
$this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', $expire = time() - 31536001).'; max-age='.($expire - time()).'; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
|
||||
$this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', $expire = time() - 31536001).'; Max-Age=0; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
|
||||
|
||||
$cookie = new Cookie('foo', 'bar', 0, '/', '');
|
||||
$this->assertEquals('foo=bar; path=/; httponly', (string) $cookie);
|
||||
@ -191,7 +191,7 @@ class CookieTest extends TestCase
|
||||
$this->assertEquals($expire - time(), $cookie->getMaxAge());
|
||||
|
||||
$cookie = new Cookie('foo', 'bar', $expire = time() - 100);
|
||||
$this->assertEquals($expire - time(), $cookie->getMaxAge());
|
||||
$this->assertEquals(0, $cookie->getMaxAge());
|
||||
}
|
||||
|
||||
public function testFromString()
|
||||
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
$parent = __DIR__;
|
||||
while (!@file_exists($parent.'/vendor/autoload.php')) {
|
||||
if (!@file_exists($parent)) {
|
||||
// open_basedir restriction in effect
|
||||
break;
|
||||
}
|
||||
if ($parent === dirname($parent)) {
|
||||
echo "vendor/autoload.php not found\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$parent = dirname($parent);
|
||||
}
|
||||
|
||||
require $parent.'/vendor/autoload.php';
|
||||
|
||||
error_reporting(-1);
|
||||
ini_set('html_errors', 0);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
header_remove('X-Powered-By');
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
|
||||
register_shutdown_function(function () {
|
||||
echo "\n";
|
||||
session_write_close();
|
||||
print_r(headers_list());
|
||||
echo "shutdown\n";
|
||||
});
|
||||
ob_start();
|
||||
|
||||
$r = new Response();
|
||||
$r->headers->set('Date', 'Sat, 12 Nov 1955 20:04:00 GMT');
|
||||
|
||||
return $r;
|
@ -0,0 +1,11 @@
|
||||
|
||||
Warning: Expiry date cannot have a year greater than 9999 in %scookie_max_age.php on line 10
|
||||
|
||||
Array
|
||||
(
|
||||
[0] => Content-Type: text/plain; charset=utf-8
|
||||
[1] => Cache-Control: no-cache, private
|
||||
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
|
||||
[3] => Set-Cookie: foo=bar; expires=Sat, 01-Jan-10000 02:46:40 GMT; Max-Age=%d; path=/
|
||||
)
|
||||
shutdown
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
$r = require __DIR__.'/common.inc';
|
||||
|
||||
$r->headers->setCookie(new Cookie('foo', 'bar', 253402310800, '', null, false, false));
|
||||
$r->sendHeaders();
|
||||
|
||||
setcookie('foo2', 'bar', 253402310800, '/');
|
@ -0,0 +1,10 @@
|
||||
|
||||
Array
|
||||
(
|
||||
[0] => Content-Type: text/plain; charset=utf-8
|
||||
[1] => Cache-Control: no-cache, private
|
||||
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
|
||||
[3] => Set-Cookie: ?*():@&+$/%#[]=?*():@&+$/%#[]; path=/
|
||||
[4] => Set-Cookie: ?*():@&+$/%#[]=?*():@&+$/%#[]; path=/
|
||||
)
|
||||
shutdown
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
$r = require __DIR__.'/common.inc';
|
||||
|
||||
$str = '?*():@&+$/%#[]';
|
||||
|
||||
$r->headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true));
|
||||
$r->sendHeaders();
|
||||
|
||||
setrawcookie($str, $str, 0, '/', null, false, false);
|
@ -0,0 +1,9 @@
|
||||
|
||||
Array
|
||||
(
|
||||
[0] => Content-Type: text/plain; charset=utf-8
|
||||
[1] => Cache-Control: no-cache, private
|
||||
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
|
||||
[3] => Set-Cookie: CookieSamesiteLaxTest=LaxValue; path=/; httponly; samesite=lax
|
||||
)
|
||||
shutdown
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
$r = require __DIR__.'/common.inc';
|
||||
|
||||
$r->headers->setCookie(new Cookie('CookieSamesiteLaxTest', 'LaxValue', 0, '/', null, false, true, false, Cookie::SAMESITE_LAX));
|
||||
$r->sendHeaders();
|
@ -0,0 +1,9 @@
|
||||
|
||||
Array
|
||||
(
|
||||
[0] => Content-Type: text/plain; charset=utf-8
|
||||
[1] => Cache-Control: no-cache, private
|
||||
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
|
||||
[3] => Set-Cookie: CookieSamesiteStrictTest=StrictValue; path=/; httponly; samesite=strict
|
||||
)
|
||||
shutdown
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
$r = require __DIR__.'/common.inc';
|
||||
|
||||
$r->headers->setCookie(new Cookie('CookieSamesiteStrictTest', 'StrictValue', 0, '/', null, false, true, false, Cookie::SAMESITE_STRICT));
|
||||
$r->sendHeaders();
|
@ -0,0 +1,10 @@
|
||||
|
||||
Array
|
||||
(
|
||||
[0] => Content-Type: text/plain; charset=utf-8
|
||||
[1] => Cache-Control: no-cache, private
|
||||
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
|
||||
[3] => Set-Cookie: %3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
|
||||
[4] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
|
||||
)
|
||||
shutdown
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
$r = require __DIR__.'/common.inc';
|
||||
|
||||
$str = '?*():@&+$/%#[]';
|
||||
|
||||
$r->headers->setCookie(new Cookie($str, $str, 0, '', null, false, false));
|
||||
$r->sendHeaders();
|
||||
|
||||
setcookie($str, $str, 0, '/');
|
@ -0,0 +1,6 @@
|
||||
The cookie name "Hello + world" contains invalid characters.
|
||||
Array
|
||||
(
|
||||
[0] => Content-Type: text/plain; charset=utf-8
|
||||
)
|
||||
shutdown
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
$r = require __DIR__.'/common.inc';
|
||||
|
||||
try {
|
||||
$r->headers->setCookie(new Cookie('Hello + world', 'hodor'));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
<?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\HttpFoundation\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @requires PHP 7.0
|
||||
*/
|
||||
class ResponseFunctionalTest extends TestCase
|
||||
{
|
||||
private static $server;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$spec = array(
|
||||
1 => array('file', '/dev/null', 'w'),
|
||||
2 => array('file', '/dev/null', 'w'),
|
||||
);
|
||||
if (!self::$server = @proc_open('exec php -S localhost:8054', $spec, $pipes, __DIR__.'/Fixtures/response-functional')) {
|
||||
self::markTestSkipped('PHP server unable to start.');
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass()
|
||||
{
|
||||
if (self::$server) {
|
||||
proc_terminate(self::$server);
|
||||
proc_close(self::$server);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideCookie
|
||||
*/
|
||||
public function testCookie($fixture)
|
||||
{
|
||||
$result = file_get_contents(sprintf('http://localhost:8054/%s.php', $fixture));
|
||||
$this->assertStringMatchesFormatFile(__DIR__.sprintf('/Fixtures/response-functional/%s.expected', $fixture), $result);
|
||||
}
|
||||
|
||||
public function provideCookie()
|
||||
{
|
||||
foreach (glob(__DIR__.'/Fixtures/response-functional/*.php') as $file) {
|
||||
yield array(pathinfo($file, PATHINFO_FILENAME));
|
||||
}
|
||||
}
|
||||
}
|
@ -116,7 +116,7 @@ class ResponseHeaderBagTest extends TestCase
|
||||
|
||||
$bag->clearCookie('foo');
|
||||
|
||||
$this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; max-age=-31536001; path=/; httponly', $bag);
|
||||
$this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; httponly', $bag);
|
||||
}
|
||||
|
||||
public function testClearCookieSecureNotHttpOnly()
|
||||
@ -125,7 +125,7 @@ class ResponseHeaderBagTest extends TestCase
|
||||
|
||||
$bag->clearCookie('foo', '/', null, true, false);
|
||||
|
||||
$this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; max-age=-31536001; path=/; secure', $bag);
|
||||
$this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure', $bag);
|
||||
}
|
||||
|
||||
public function testReplace()
|
||||
|
@ -540,9 +540,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
// Because concurrent requests might still be using them,
|
||||
// old container files are not removed immediately,
|
||||
// but on a next dump of the container.
|
||||
static $legacyContainers = array();
|
||||
$oldContainerDir = dirname($oldContainer->getFileName());
|
||||
foreach (glob(dirname($oldContainerDir).'/*.legacy') as $legacyContainer) {
|
||||
if ($oldContainerDir.'.legacy' !== $legacyContainer && @unlink($legacyContainer)) {
|
||||
$legacyContainers[$oldContainerDir.'.legacy'] = true;
|
||||
foreach (glob(dirname($oldContainerDir).DIRECTORY_SEPARATOR.'*.legacy') as $legacyContainer) {
|
||||
if (!isset($legacyContainers[$legacyContainer]) && @unlink($legacyContainer)) {
|
||||
(new Filesystem())->remove(substr($legacyContainer, 0, -7));
|
||||
}
|
||||
}
|
||||
|
@ -60,22 +60,17 @@ class ClientTest extends TestCase
|
||||
$m = $r->getMethod('filterResponse');
|
||||
$m->setAccessible(true);
|
||||
|
||||
$expected = array(
|
||||
'foo=bar; expires=Sun, 15-Feb-2009 20:00:00 GMT; max-age='.(strtotime('Sun, 15-Feb-2009 20:00:00 GMT') - time()).'; path=/foo; domain=http://example.com; secure; httponly',
|
||||
'foo1=bar1; expires=Sun, 15-Feb-2009 20:00:00 GMT; max-age='.(strtotime('Sun, 15-Feb-2009 20:00:00 GMT') - time()).'; path=/foo; domain=http://example.com; secure; httponly',
|
||||
);
|
||||
$response = new Response();
|
||||
$response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true));
|
||||
$domResponse = $m->invoke($client, $response);
|
||||
$this->assertSame((string) $cookie1, $domResponse->getHeader('Set-Cookie'));
|
||||
|
||||
$response = new Response();
|
||||
$response->headers->setCookie(new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true));
|
||||
$response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true));
|
||||
$response->headers->setCookie($cookie2 = new Cookie('foo1', 'bar1', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true));
|
||||
$domResponse = $m->invoke($client, $response);
|
||||
$this->assertEquals($expected[0], $domResponse->getHeader('Set-Cookie'));
|
||||
|
||||
$response = new Response();
|
||||
$response->headers->setCookie(new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true));
|
||||
$response->headers->setCookie(new Cookie('foo1', 'bar1', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true));
|
||||
$domResponse = $m->invoke($client, $response);
|
||||
$this->assertEquals($expected[0], $domResponse->getHeader('Set-Cookie'));
|
||||
$this->assertEquals($expected, $domResponse->getHeader('Set-Cookie', false));
|
||||
$this->assertSame((string) $cookie1, $domResponse->getHeader('Set-Cookie'));
|
||||
$this->assertSame(array((string) $cookie1, (string) $cookie2), $domResponse->getHeader('Set-Cookie', false));
|
||||
}
|
||||
|
||||
public function testFilterResponseSupportsStreamedResponses()
|
||||
|
@ -86,7 +86,7 @@ class DumpDataCollectorTest extends TestCase
|
||||
|
||||
ob_start();
|
||||
$collector->collect(new Request(), new Response());
|
||||
$output = ob_get_clean();
|
||||
$output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
|
||||
|
||||
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n123\n", $output);
|
||||
$this->assertSame(1, $collector->getDumpsCount());
|
||||
@ -130,7 +130,8 @@ EOTXT;
|
||||
|
||||
ob_start();
|
||||
$collector->__destruct();
|
||||
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", ob_get_clean());
|
||||
$output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
|
||||
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", $output);
|
||||
}
|
||||
|
||||
public function testFlushNothingWhenDataDumperIsProvided()
|
||||
@ -142,10 +143,11 @@ EOTXT;
|
||||
ob_start();
|
||||
$collector->dump($data);
|
||||
$line = __LINE__ - 1;
|
||||
$output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
|
||||
if (\PHP_VERSION_ID >= 50400) {
|
||||
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", ob_get_clean());
|
||||
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", $output);
|
||||
} else {
|
||||
$this->assertSame("\"DumpDataCollectorTest.php on line {$line}:\"\n456\n", ob_get_clean());
|
||||
$this->assertSame("\"DumpDataCollectorTest.php on line {$line}:\"\n456\n", $output);
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
@ -144,7 +144,7 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
if (!\in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
return $types;
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
}
|
||||
$type = $this->extractFromReflectionType($reflectionType);
|
||||
|
||||
if (in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
if (\in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
$type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type);
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
return array($this->extractFromReflectionType($reflectionType));
|
||||
}
|
||||
|
||||
if (in_array($prefix, array('is', 'can', 'has'))) {
|
||||
if (\in_array($prefix, array('is', 'can', 'has'))) {
|
||||
return array(new Type(Type::BUILTIN_TYPE_BOOL));
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace Symfony\Component\PropertyInfo;
|
||||
|
||||
/**
|
||||
* Description extractor Interface.
|
||||
* Guesses the property's human readable description.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
|
@ -95,7 +95,7 @@ class PropertyInfoExtractor implements PropertyInfoExtractorInterface
|
||||
private function extract(iterable $extractors, string $method, array $arguments)
|
||||
{
|
||||
foreach ($extractors as $extractor) {
|
||||
$value = call_user_func_array(array($extractor, $method), $arguments);
|
||||
$value = \call_user_func_array(array($extractor, $method), $arguments);
|
||||
if (null !== $value) {
|
||||
return $value;
|
||||
}
|
||||
|
@ -11,8 +11,6 @@
|
||||
|
||||
namespace Symfony\Component\Security\Core\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserChecker;
|
||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
@ -50,20 +48,7 @@ class SimpleAuthenticationProvider implements AuthenticationProviderInterface
|
||||
$user = $authToken->getUser();
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
try {
|
||||
$user = $this->userProvider->loadUserByUsername($user);
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new AuthenticationServiceException('The user provider must return a UserInterface object.');
|
||||
}
|
||||
} catch (UsernameNotFoundException $e) {
|
||||
$e->setUsername($user);
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
$e = new AuthenticationServiceException($e->getMessage(), 0, $e);
|
||||
$e->setToken($token);
|
||||
throw $e;
|
||||
}
|
||||
return $authToken;
|
||||
}
|
||||
|
||||
$this->userChecker->checkPreAuth($user);
|
||||
|
@ -12,10 +12,10 @@
|
||||
namespace Symfony\Component\Security\Core\Tests\Authentication\Provider;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Security\Core\Exception\DisabledException;
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\SimpleAuthenticationProvider;
|
||||
use Symfony\Component\Security\Core\Exception\DisabledException;
|
||||
use Symfony\Component\Security\Core\Exception\LockedException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\UserChecker;
|
||||
|
||||
class SimpleAuthenticationProviderTest extends TestCase
|
||||
{
|
||||
@ -73,52 +73,18 @@ class SimpleAuthenticationProviderTest extends TestCase
|
||||
$provider->authenticate($token);
|
||||
}
|
||||
|
||||
public function testAuthenticateFromString()
|
||||
public function testAuthenticateSkipsUserChecksForNonUserInterfaceObjects()
|
||||
{
|
||||
$user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
|
||||
|
||||
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
||||
$token->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue('foo'));
|
||||
|
||||
->will($this->returnValue('string-user'));
|
||||
$authenticator = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface')->getMock();
|
||||
$authenticator->expects($this->once())
|
||||
->method('authenticateToken')
|
||||
->will($this->returnValue($token));
|
||||
|
||||
$userProvider = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserProviderInterface')->getMock();
|
||||
$userProvider->expects($this->once())
|
||||
->method('loadUserByUsername')
|
||||
->willReturn($this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock());
|
||||
$provider = $this->getProvider($authenticator, $userProvider);
|
||||
|
||||
$this->assertSame($token, $provider->authenticate($token));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\UsernameNotFoundException
|
||||
*/
|
||||
public function testUsernameNotFound()
|
||||
{
|
||||
$user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
|
||||
|
||||
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
||||
$token->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue('foo'));
|
||||
|
||||
$authenticator = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface')->getMock();
|
||||
$authenticator->expects($this->once())
|
||||
->method('authenticateToken')
|
||||
->will($this->returnValue($token));
|
||||
|
||||
$userProvider = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserProviderInterface')->getMock();
|
||||
$userProvider->expects($this->once())
|
||||
->method('loadUserByUsername')
|
||||
->willThrowException(new UsernameNotFoundException());
|
||||
|
||||
$this->getProvider($authenticator, $userProvider)->authenticate($token);
|
||||
$this->assertSame($token, $this->getProvider($authenticator, null, new UserChecker())->authenticate($token));
|
||||
}
|
||||
|
||||
protected function getProvider($simpleAuthenticator = null, $userProvider = null, $userChecker = null, $key = 'test')
|
||||
|
@ -18,7 +18,6 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInt
|
||||
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\Guard\Token\PostAuthenticationGuardToken;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
|
||||
@ -97,11 +96,6 @@ class GuardAuthenticatorHandler
|
||||
*/
|
||||
public function handleAuthenticationFailure(AuthenticationException $authenticationException, Request $request, AuthenticatorInterface $guardAuthenticator, string $providerKey): ?Response
|
||||
{
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if ($token instanceof PostAuthenticationGuardToken && $providerKey === $token->getProviderKey()) {
|
||||
$this->tokenStorage->setToken(null);
|
||||
}
|
||||
|
||||
$response = $guardAuthenticator->onAuthenticationFailure($request, $authenticationException);
|
||||
if ($response instanceof Response || null === $response) {
|
||||
// returning null is ok, it means they want the request to continue
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Security\Guard\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
@ -62,7 +63,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
||||
*/
|
||||
public function authenticate(TokenInterface $token)
|
||||
{
|
||||
if (!$this->supports($token)) {
|
||||
if (!$token instanceof GuardTokenInterface) {
|
||||
throw new \InvalidArgumentException('GuardAuthenticationProvider only supports GuardTokenInterface.');
|
||||
}
|
||||
|
||||
@ -86,19 +87,13 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
||||
throw new AuthenticationExpiredException();
|
||||
}
|
||||
|
||||
// find the *one* GuardAuthenticator that this token originated from
|
||||
foreach ($this->guardAuthenticators as $key => $guardAuthenticator) {
|
||||
// get a key that's unique to *this* guard authenticator
|
||||
// this MUST be the same as GuardAuthenticationListener
|
||||
$uniqueGuardKey = $this->providerKey.'_'.$key;
|
||||
$guardAuthenticator = $this->findOriginatingAuthenticator($token);
|
||||
|
||||
if ($uniqueGuardKey == $token->getGuardProviderKey()) {
|
||||
return $this->authenticateViaGuard($guardAuthenticator, $token);
|
||||
}
|
||||
if (null === $guardAuthenticator) {
|
||||
throw new AuthenticationException(sprintf('Token with provider key "%s" did not originate from any of the guard authenticators of provider "%s".', $token->getGuardProviderKey(), $this->providerKey));
|
||||
}
|
||||
|
||||
// no matching authenticator found - but there will be multiple GuardAuthenticationProvider
|
||||
// instances that will be checked if you have multiple firewalls.
|
||||
return $this->authenticateViaGuard($guardAuthenticator, $token);
|
||||
}
|
||||
|
||||
private function authenticateViaGuard($guardAuthenticator, PreAuthenticationGuardToken $token)
|
||||
@ -107,18 +102,11 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
||||
$user = $guardAuthenticator->getUser($token->getCredentials(), $this->userProvider);
|
||||
|
||||
if (null === $user) {
|
||||
throw new UsernameNotFoundException(sprintf(
|
||||
'Null returned from %s::getUser()',
|
||||
get_class($guardAuthenticator)
|
||||
));
|
||||
throw new UsernameNotFoundException(sprintf('Null returned from %s::getUser()', get_class($guardAuthenticator)));
|
||||
}
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new \UnexpectedValueException(sprintf(
|
||||
'The %s::getUser() method must return a UserInterface. You returned %s.',
|
||||
get_class($guardAuthenticator),
|
||||
is_object($user) ? get_class($user) : gettype($user)
|
||||
));
|
||||
throw new \UnexpectedValueException(sprintf('The %s::getUser() method must return a UserInterface. You returned %s.', get_class($guardAuthenticator), is_object($user) ? get_class($user) : gettype($user)));
|
||||
}
|
||||
|
||||
$this->userChecker->checkPreAuth($user);
|
||||
@ -130,18 +118,37 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
||||
// turn the UserInterface into a TokenInterface
|
||||
$authenticatedToken = $guardAuthenticator->createAuthenticatedToken($user, $this->providerKey);
|
||||
if (!$authenticatedToken instanceof TokenInterface) {
|
||||
throw new \UnexpectedValueException(sprintf(
|
||||
'The %s::createAuthenticatedToken() method must return a TokenInterface. You returned %s.',
|
||||
get_class($guardAuthenticator),
|
||||
is_object($authenticatedToken) ? get_class($authenticatedToken) : gettype($authenticatedToken)
|
||||
));
|
||||
throw new \UnexpectedValueException(sprintf('The %s::createAuthenticatedToken() method must return a TokenInterface. You returned %s.', get_class($guardAuthenticator), is_object($authenticatedToken) ? get_class($authenticatedToken) : gettype($authenticatedToken)));
|
||||
}
|
||||
|
||||
return $authenticatedToken;
|
||||
}
|
||||
|
||||
private function findOriginatingAuthenticator(PreAuthenticationGuardToken $token)
|
||||
{
|
||||
// find the *one* GuardAuthenticator that this token originated from
|
||||
foreach ($this->guardAuthenticators as $key => $guardAuthenticator) {
|
||||
// get a key that's unique to *this* guard authenticator
|
||||
// this MUST be the same as GuardAuthenticationListener
|
||||
$uniqueGuardKey = $this->providerKey.'_'.$key;
|
||||
|
||||
if ($uniqueGuardKey === $token->getGuardProviderKey()) {
|
||||
return $guardAuthenticator;
|
||||
}
|
||||
}
|
||||
|
||||
// no matching authenticator found - but there will be multiple GuardAuthenticationProvider
|
||||
// instances that will be checked if you have multiple firewalls.
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function supports(TokenInterface $token)
|
||||
{
|
||||
if ($token instanceof PreAuthenticationGuardToken) {
|
||||
return null !== $this->findOriginatingAuthenticator($token);
|
||||
}
|
||||
|
||||
return $token instanceof GuardTokenInterface;
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ class GuardAuthenticatorHandlerTest extends TestCase
|
||||
/**
|
||||
* @dataProvider getTokenClearingTests
|
||||
*/
|
||||
public function testHandleAuthenticationClearsToken($tokenClass, $tokenProviderKey, $actualProviderKey, $shouldTokenBeCleared)
|
||||
public function testHandleAuthenticationClearsToken($tokenClass, $tokenProviderKey, $actualProviderKey)
|
||||
{
|
||||
$token = $this->getMockBuilder($tokenClass)
|
||||
->disableOriginalConstructor()
|
||||
@ -91,12 +91,7 @@ class GuardAuthenticatorHandlerTest extends TestCase
|
||||
->method('getProviderKey')
|
||||
->will($this->returnValue($tokenProviderKey));
|
||||
|
||||
// make the $token be the current token
|
||||
$this->tokenStorage->expects($this->once())
|
||||
->method('getToken')
|
||||
->will($this->returnValue($token));
|
||||
|
||||
$this->tokenStorage->expects($shouldTokenBeCleared ? $this->once() : $this->never())
|
||||
$this->tokenStorage->expects($this->never())
|
||||
->method('setToken')
|
||||
->with(null);
|
||||
$authException = new AuthenticationException('Bad password!');
|
||||
@ -116,9 +111,9 @@ class GuardAuthenticatorHandlerTest extends TestCase
|
||||
{
|
||||
$tests = array();
|
||||
// correct token class and matching firewall => clear the token
|
||||
$tests[] = array('Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken', 'the_firewall_key', 'the_firewall_key', true);
|
||||
$tests[] = array('Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken', 'the_firewall_key', 'different_key', false);
|
||||
$tests[] = array('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', 'the_firewall_key', 'the_firewall_key', false);
|
||||
$tests[] = array('Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken', 'the_firewall_key', 'the_firewall_key');
|
||||
$tests[] = array('Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken', 'the_firewall_key', 'different_key');
|
||||
$tests[] = array('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', 'the_firewall_key', 'the_firewall_key');
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Guard\Provider\GuardAuthenticationProvider;
|
||||
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
|
||||
use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken;
|
||||
|
||||
/**
|
||||
* @author Ryan Weaver <weaverryan@gmail.com>
|
||||
@ -136,6 +137,40 @@ class GuardAuthenticationProviderTest extends TestCase
|
||||
$actualToken = $provider->authenticate($token);
|
||||
}
|
||||
|
||||
public function testSupportsChecksGuardAuthenticatorsTokenOrigin()
|
||||
{
|
||||
$authenticatorA = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||
$authenticatorB = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||
$authenticators = array($authenticatorA, $authenticatorB);
|
||||
|
||||
$mockedUser = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
|
||||
$provider = new GuardAuthenticationProvider($authenticators, $this->userProvider, 'first_firewall', $this->userChecker);
|
||||
|
||||
$token = new PreAuthenticationGuardToken($mockedUser, 'first_firewall_1');
|
||||
$supports = $provider->supports($token);
|
||||
$this->assertTrue($supports);
|
||||
|
||||
$token = new PreAuthenticationGuardToken($mockedUser, 'second_firewall_0');
|
||||
$supports = $provider->supports($token);
|
||||
$this->assertFalse($supports);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationException
|
||||
* @expectedExceptionMessageRegExp /second_firewall_0/
|
||||
*/
|
||||
public function testAuthenticateFailsOnNonOriginatingToken()
|
||||
{
|
||||
$authenticatorA = $this->getMockBuilder(AuthenticatorInterface::class)->getMock();
|
||||
$authenticators = array($authenticatorA);
|
||||
|
||||
$mockedUser = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
|
||||
$provider = new GuardAuthenticationProvider($authenticators, $this->userProvider, 'first_firewall', $this->userChecker);
|
||||
|
||||
$token = new PreAuthenticationGuardToken($mockedUser, 'second_firewall_0');
|
||||
$provider->authenticate($token);
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->userProvider = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserProviderInterface')->getMock();
|
||||
|
@ -184,10 +184,11 @@ class SplCaster
|
||||
$storage = array();
|
||||
unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
|
||||
|
||||
foreach (clone $c as $obj) {
|
||||
$clone = clone $c;
|
||||
foreach ($clone as $obj) {
|
||||
$storage[spl_object_hash($obj)] = array(
|
||||
'object' => $obj,
|
||||
'info' => $c->getInfo(),
|
||||
'info' => $clone->getInfo(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ class CliDumper extends AbstractDumper
|
||||
{
|
||||
parent::__construct($output, $charset, $flags);
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR && 'ON' !== @getenv('ConEmuANSI') && 'xterm' !== @getenv('TERM')) {
|
||||
if ('\\' === DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) {
|
||||
// Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI
|
||||
$this->setStyles(array(
|
||||
'default' => '31',
|
||||
@ -467,7 +467,7 @@ class CliDumper extends AbstractDumper
|
||||
protected function supportsColors()
|
||||
{
|
||||
if ($this->outputStream !== static::$defaultOutput) {
|
||||
return @(is_resource($this->outputStream) && function_exists('posix_isatty') && posix_isatty($this->outputStream));
|
||||
return $this->hasColorSupport($this->outputStream);
|
||||
}
|
||||
if (null !== static::$defaultColors) {
|
||||
return static::$defaultColors;
|
||||
@ -495,23 +495,10 @@ class CliDumper extends AbstractDumper
|
||||
}
|
||||
}
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
static::$defaultColors = @(
|
||||
function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support($this->outputStream)
|
||||
|| '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM')
|
||||
);
|
||||
} elseif (function_exists('posix_isatty')) {
|
||||
$h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null);
|
||||
$h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream;
|
||||
static::$defaultColors = @posix_isatty($h);
|
||||
} else {
|
||||
static::$defaultColors = false;
|
||||
}
|
||||
$h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null);
|
||||
$h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream;
|
||||
|
||||
return static::$defaultColors;
|
||||
return static::$defaultColors = $this->hasColorSupport($h);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -537,4 +524,69 @@ class CliDumper extends AbstractDumper
|
||||
|
||||
$this->dumpLine($cursor->depth, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the stream supports colorization.
|
||||
*
|
||||
* Reference: Composer\XdebugHandler\Process::supportsColor
|
||||
* https://github.com/composer/xdebug-handler
|
||||
*
|
||||
* @param mixed $stream A CLI output stream
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasColorSupport($stream)
|
||||
{
|
||||
if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
return (function_exists('sapi_windows_vt100_support')
|
||||
&& @sapi_windows_vt100_support($stream))
|
||||
|| false !== getenv('ANSICON')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
}
|
||||
|
||||
if (function_exists('stream_isatty')) {
|
||||
return @stream_isatty($stream);
|
||||
}
|
||||
|
||||
if (function_exists('posix_isatty')) {
|
||||
return @posix_isatty($stream);
|
||||
}
|
||||
|
||||
$stat = @fstat($stream);
|
||||
// Check if formatted mode is S_IFCHR
|
||||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Windows terminal supports true color.
|
||||
*
|
||||
* Note that this does not check an output stream, but relies on environment
|
||||
* variables from known implementations, or a PHP and Windows version that
|
||||
* supports true color.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isWindowsTrueColor()
|
||||
{
|
||||
$result = 183 <= getenv('ANSICON_VER')
|
||||
|| 'ON' === getenv('ConEmuANSI')
|
||||
|| 'xterm' === getenv('TERM');
|
||||
|
||||
if (!$result && PHP_VERSION_ID >= 70200) {
|
||||
$version = sprintf(
|
||||
'%s.%s.%s',
|
||||
PHP_WINDOWS_VERSION_MAJOR,
|
||||
PHP_WINDOWS_VERSION_MINOR,
|
||||
PHP_WINDOWS_VERSION_BUILD
|
||||
);
|
||||
$result = $version >= '10.0.15063';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -310,6 +310,9 @@ return function (root, x) {
|
||||
|
||||
return "concat(" + parts.join(",") + ", '')";
|
||||
}
|
||||
function xpathHasClass(className) {
|
||||
return "contains(concat(' ', normalize-space(@class), ' '), ' " + className +" ')";
|
||||
}
|
||||
addEventListener(root, 'mouseover', function (e) {
|
||||
if ('' != refStyle.innerHTML) {
|
||||
refStyle.innerHTML = '';
|
||||
@ -516,7 +519,15 @@ return function (root, x) {
|
||||
return;
|
||||
}
|
||||
|
||||
var xpathResult = doc.evaluate('//pre[@id="' + root.id + '"]//span[@class="sf-dump-str" or @class="sf-dump-key" or @class="sf-dump-public" or @class="sf-dump-protected" or @class="sf-dump-private"][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
|
||||
var classMatches = [
|
||||
"sf-dump-str",
|
||||
"sf-dump-key",
|
||||
"sf-dump-public",
|
||||
"sf-dump-protected",
|
||||
"sf-dump-private",
|
||||
].map(xpathHasClass).join(' or ');
|
||||
|
||||
var xpathResult = doc.evaluate('.//span[' + classMatches + '][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
|
||||
|
||||
while (node = xpathResult.iterateNext()) state.nodes.push(node);
|
||||
|
||||
|
@ -144,4 +144,23 @@ EOTXT;
|
||||
array(\SplDoublyLinkedList::IT_MODE_LIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_LIFO | IT_MODE_DELETE'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testCastObjectStorageIsntModified()
|
||||
{
|
||||
$var = new \SplObjectStorage();
|
||||
$var->attach(new \stdClass());
|
||||
$var->rewind();
|
||||
$current = $var->current();
|
||||
|
||||
$this->assertDumpMatchesFormat('%A', $var);
|
||||
$this->assertSame($current, $var->current());
|
||||
}
|
||||
|
||||
public function testCastObjectStorageDumpsInfo()
|
||||
{
|
||||
$var = new \SplObjectStorage();
|
||||
$var->attach(new \stdClass(), new \DateTime());
|
||||
|
||||
$this->assertDumpMatchesFormat('%ADateTime%A', $var);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user