Merge branch '4.4'

* 4.4: (23 commits)
  [HttpFoundation] fix docblock
  [HttpKernel] Flatten "exception" controller argument if not typed
  Fix MySQL column type definition.
  Link the right file depending on the new version
  [Cache] Redis Tag Aware warn on wrong eviction policy
  [HttpClient] fix HttpClientDataCollector
  [HttpKernel] collect bundle classes, not paths
  [Config] fix id-generation for GlobResource
  [HttpKernel] dont check cache freshness more than once per process
  [Finder] Allow ssh2 stream wrapper for sftp
  [FrameworkBundle] fix wiring of httplug client
  add FrameworkBundle requirement
  [SecurityBundle] add tests with empty authenticator
  [Security] always check the token on non-lazy firewalls
  [DI] Use reproducible entropy to generate env placeholders
  [WebProfilerBundle] Require symfony/twig-bundle
  [Mailer] Add UPGRADE entry about the null transport DSN
  bumped Symfony version to 4.3.9
  updated VERSION for 4.3.8
  updated CHANGELOG for 4.3.8
  ...
This commit is contained in:
Nicolas Grekas 2019-11-16 16:24:47 +01:00
commit df63cc59f1
25 changed files with 230 additions and 29 deletions

View File

@ -7,6 +7,16 @@ in 4.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1 To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1
* 4.3.8 (2019-11-13)
* bug #34344 [Console] Constant STDOUT might be undefined (nicolas-grekas)
* security #cve-2019-18886 [Security\Core] throw AccessDeniedException when switch user fails (nicolas-grekas)
* security #cve-2019-18888 [Mime] fix guessing mime-types of files with leading dash (nicolas-grekas)
* security #cve-2019-11325 [VarExporter] fix exporting some strings (nicolas-grekas)
* security #cve-2019-18889 [Cache] forbid serializing AbstractAdapter and TagAwareAdapter instances (nicolas-grekas)
* security #cve-2019-18888 [HttpFoundation] fix guessing mime-types of files with leading dash (nicolas-grekas)
* security #cve-2019-18887 [HttpKernel] Use constant time comparison in UriSigner (stof)
* 4.3.7 (2019-11-11) * 4.3.7 (2019-11-11)
* bug #34294 [Workflow] Fix error when we use ValueObject for the marking property (FabienSalles) * bug #34294 [Workflow] Fix error when we use ValueObject for the marking property (FabienSalles)

View File

@ -26,8 +26,8 @@ file and directory structure of your application:
Then, upgrade the contents of your console script and your front controller: Then, upgrade the contents of your console script and your front controller:
* `bin/console`: https://github.com/symfony/recipes/blob/master/symfony/console/3.3/bin/console * `bin/console`: https://github.com/symfony/recipes/blob/master/symfony/console/4.4/bin/console
* `public/index.php`: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/3.3/public/index.php * `public/index.php`: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/4.4/public/index.php
Lastly, read the following article to add Symfony Flex to your application and Lastly, read the following article to add Symfony Flex to your application and
upgrade the configuration files: https://symfony.com/doc/current/setup/flex.html upgrade the configuration files: https://symfony.com/doc/current/setup/flex.html

View File

@ -164,6 +164,11 @@ Lock
* Deprecated services `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract`, * Deprecated services `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract`,
use `StoreFactory::createStore` instead. use `StoreFactory::createStore` instead.
Mailer
------
* [BC BREAK] Changed the DSN to use for disabling delivery (using the `NullTransport`) from `smtp://null` to `null://null` (host doesn't matter).
Messenger Messenger
--------- ---------

View File

@ -26,8 +26,8 @@
<service id="Http\Client\HttpClient" class="Symfony\Component\HttpClient\HttplugClient"> <service id="Http\Client\HttpClient" class="Symfony\Component\HttpClient\HttplugClient">
<argument type="service" id="http_client" /> <argument type="service" id="http_client" />
<argument type="service" id="Http\Message\ResponseFactory" on-invalid="ignore" /> <argument type="service" id="Psr\Http\Message\ResponseFactoryInterface" on-invalid="ignore" />
<argument type="service" id="Http\Message\StreamFactory" on-invalid="ignore" /> <argument type="service" id="Psr\Http\Message\StreamFactoryInterface" on-invalid="ignore" />
</service> </service>
</services> </services>
</container> </container>

View File

@ -0,0 +1,24 @@
<?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\Bundle\SecurityBundle\Tests\Functional;
class AnonymousTest extends AbstractWebTestCase
{
public function testAnonymous()
{
$client = $this->createClient(['test_case' => 'Anonymous', 'root_config' => 'config.yml']);
$client->request('GET', '/');
$this->assertSame(401, $client->getResponse()->getStatusCode());
}
}

View File

@ -0,0 +1,57 @@
<?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\Bundle\SecurityBundle\Tests\Functional\Bundle\AnonymousBundle;
use Symfony\Component\HttpFoundation\Request;
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\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
class AppCustomAuthenticator extends AbstractGuardAuthenticator
{
public function supports(Request $request)
{
return false;
}
public function getCredentials(Request $request)
{
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
}
public function checkCredentials($credentials, UserInterface $user)
{
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
}
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response($authException->getMessage(), Response::HTTP_UNAUTHORIZED);
}
public function supportsRememberMe()
{
}
}

View File

@ -0,0 +1,15 @@
<?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.
*/
return [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
];

View File

@ -0,0 +1,24 @@
framework:
secret: test
router: { resource: "%kernel.project_dir%/%kernel.test_case%/routing.yml" }
validation: { enabled: true, enable_annotations: true }
csrf_protection: true
form: true
test: ~
default_locale: en
session:
storage_id: session.storage.mock_file
profiler: { only_exceptions: false }
services:
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AnonymousBundle\AppCustomAuthenticator: ~
security:
firewalls:
secure:
pattern: ^/
anonymous: false
stateless: true
guard:
authenticators:
- Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AnonymousBundle\AppCustomAuthenticator

View File

@ -0,0 +1,5 @@
main:
path: /
defaults:
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction
path: /app

View File

@ -210,7 +210,7 @@
<thead> <thead>
<tr> <tr>
<th class="key">Name</th> <th class="key">Name</th>
<th>Path</th> <th>Class</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@ -18,6 +18,7 @@
"require": { "require": {
"php": "^7.2.9", "php": "^7.2.9",
"symfony/config": "^4.4|^5.0", "symfony/config": "^4.4|^5.0",
"symfony/framework-bundle": "^4.4|^5.0",
"symfony/http-kernel": "^4.4|^5.0", "symfony/http-kernel": "^4.4|^5.0",
"symfony/routing": "^4.4|^5.0", "symfony/routing": "^4.4|^5.0",
"symfony/twig-bundle": "^4.4|^5.0", "symfony/twig-bundle": "^4.4|^5.0",

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\Adapter;
use Predis\Connection\Aggregate\ClusterInterface; use Predis\Connection\Aggregate\ClusterInterface;
use Predis\Connection\Aggregate\PredisCluster; use Predis\Connection\Aggregate\PredisCluster;
use Predis\Response\Status; use Predis\Response\Status;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Marshaller\DeflateMarshaller; use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Marshaller\MarshallerInterface;
@ -58,6 +59,11 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter
*/ */
private const DEFAULT_CACHE_TTL = 8640000; private const DEFAULT_CACHE_TTL = 8640000;
/**
* @var string|null detected eviction policy used on Redis server
*/
private $redisEvictionPolicy;
/** /**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redisClient The redis client * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redisClient The redis client
* @param string $namespace The default namespace * @param string $namespace The default namespace
@ -87,6 +93,13 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter
*/ */
protected function doSave(array $values, int $lifetime, array $addTagData = [], array $delTagData = []): array protected function doSave(array $values, int $lifetime, array $addTagData = [], array $delTagData = []): array
{ {
$eviction = $this->getRedisEvictionPolicy();
if ('noeviction' !== $eviction && 0 !== strpos($eviction, 'volatile-')) {
CacheItem::log($this->logger, sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies', $eviction));
return false;
}
// serialize values // serialize values
if (!$serialized = $this->marshaller->marshall($values, $failed)) { if (!$serialized = $this->marshaller->marshall($values, $failed)) {
return $failed; return $failed;
@ -260,4 +273,20 @@ EOLUA;
return $newIds; return $newIds;
} }
private function getRedisEvictionPolicy(): string
{
if (null !== $this->redisEvictionPolicy) {
return $this->redisEvictionPolicy;
}
foreach ($this->getHosts() as $host) {
$info = $host->info('Memory');
$info = isset($info['Memory']) ? $info['Memory'] : $info;
return $this->redisEvictionPolicy = $info['maxmemory_policy'];
}
return $this->redisEvictionPolicy = '';
}
} }

View File

@ -41,6 +41,7 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface
*/ */
public function __construct(string $prefix, string $pattern, bool $recursive, bool $forExclusion = false, array $excludedPrefixes = []) public function __construct(string $prefix, string $pattern, bool $recursive, bool $forExclusion = false, array $excludedPrefixes = [])
{ {
ksort($excludedPrefixes);
$this->prefix = realpath($prefix) ?: (file_exists($prefix) ? $prefix : false); $this->prefix = realpath($prefix) ?: (file_exists($prefix) ? $prefix : false);
$this->pattern = $pattern; $this->pattern = $pattern;
$this->recursive = $recursive; $this->recursive = $recursive;
@ -62,7 +63,7 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface
*/ */
public function __toString(): string public function __toString(): string
{ {
return 'glob.'.$this->prefix.$this->pattern.(int) $this->recursive; return 'glob.'.$this->prefix.(int) $this->recursive.$this->pattern.(int) $this->forExclusion.implode("\0", $this->excludedPrefixes);
} }
/** /**

View File

@ -24,6 +24,8 @@ class EnvPlaceholderParameterBag extends ParameterBag
private $unusedEnvPlaceholders = []; private $unusedEnvPlaceholders = [];
private $providedTypes = []; private $providedTypes = [];
private static $counter = 0;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -49,7 +51,7 @@ class EnvPlaceholderParameterBag extends ParameterBag
throw new RuntimeException(sprintf('The default value of an env() parameter must be a string or null, but "%s" given to "%s".', \gettype($defaultValue), $name)); throw new RuntimeException(sprintf('The default value of an env() parameter must be a string or null, but "%s" given to "%s".', \gettype($defaultValue), $name));
} }
$uniqueName = md5($name.uniqid(mt_rand(), true)); $uniqueName = md5($name.'_'.self::$counter++);
$placeholder = sprintf('%s_%s_%s', $this->getEnvPlaceholderUniquePrefix(), str_replace(':', '_', $env), $uniqueName); $placeholder = sprintf('%s_%s_%s', $this->getEnvPlaceholderUniquePrefix(), str_replace(':', '_', $env), $uniqueName);
$this->envPlaceholders[$env][$placeholder] = $placeholder; $this->envPlaceholders[$env][$placeholder] = $placeholder;
@ -64,7 +66,13 @@ class EnvPlaceholderParameterBag extends ParameterBag
*/ */
public function getEnvPlaceholderUniquePrefix(): string public function getEnvPlaceholderUniquePrefix(): string
{ {
return $this->envPlaceholderUniquePrefix ?? $this->envPlaceholderUniquePrefix = 'env_'.bin2hex(random_bytes(8)); if (null === $this->envPlaceholderUniquePrefix) {
$reproducibleEntropy = unserialize(serialize($this->parameters));
array_walk_recursive($reproducibleEntropy, function (&$v) { $v = null; });
$this->envPlaceholderUniquePrefix = 'env_'.substr(md5(serialize($reproducibleEntropy)), -16);
}
return $this->envPlaceholderUniquePrefix;
} }
/** /**

View File

@ -784,7 +784,7 @@ class Finder implements \IteratorAggregate, \Countable
{ {
$dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR); $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
if (preg_match('#^s?ftp://#', $dir)) { if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
$dir .= '/'; $dir .= '/';
} }

View File

@ -133,6 +133,7 @@ final class HttpClientDataCollector extends DataCollector
$debugInfo = array_diff_key($info, $baseInfo); $debugInfo = array_diff_key($info, $baseInfo);
$info = array_diff_key($info, $debugInfo) + ['debug_info' => $debugInfo]; $info = array_diff_key($info, $debugInfo) + ['debug_info' => $debugInfo];
unset($traces[$i]['info']); // break PHP reference used by TraceableHttpClient
$traces[$i]['info'] = $this->cloneVar($info); $traces[$i]['info'] = $this->cloneVar($info);
$traces[$i]['options'] = $this->cloneVar($trace['options']); $traces[$i]['options'] = $this->cloneVar($trace['options']);
} }

View File

@ -219,7 +219,7 @@ class PdoSessionHandler extends AbstractSessionHandler
// - trailing space removal // - trailing space removal
// - case-insensitivity // - case-insensitivity
// - language processing like é == e // - language processing like é == e
$sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol MEDIUMINT NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8_bin, ENGINE = InnoDB"; $sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8_bin, ENGINE = InnoDB";
break; break;
case 'sqlite': case 'sqlite':
$sql = "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)"; $sql = "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)";

View File

@ -34,7 +34,7 @@ class RedisSessionHandler extends AbstractSessionHandler
* List of available options: * List of available options:
* * prefix: The prefix to use for the keys in order to avoid collision on the Redis server. * * prefix: The prefix to use for the keys in order to avoid collision on the Redis server.
* *
* @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy $redis * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis
* *
* @throws \InvalidArgumentException When unsupported client or options are passed * @throws \InvalidArgumentException When unsupported client or options are passed
*/ */

View File

@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\VarDumper\Caster\LinkStub; use Symfony\Component\VarDumper\Caster\ClassStub;
/** /**
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
@ -28,12 +28,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
* @var KernelInterface * @var KernelInterface
*/ */
private $kernel; private $kernel;
private $hasVarDumper;
public function __construct()
{
$this->hasVarDumper = class_exists(LinkStub::class);
}
/** /**
* Sets the Kernel associated with this Request. * Sets the Kernel associated with this Request.
@ -67,7 +61,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
if (isset($this->kernel)) { if (isset($this->kernel)) {
foreach ($this->kernel->getBundles() as $name => $bundle) { foreach ($this->kernel->getBundles() as $name => $bundle) {
$this->data['bundles'][$name] = $this->hasVarDumper ? new LinkStub($bundle->getPath()) : $bundle->getPath(); $this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
} }
$this->data['symfony_state'] = $this->determineSymfonyState(); $this->data['symfony_state'] = $this->determineSymfonyState();

View File

@ -99,7 +99,7 @@ class ErrorListener implements EventSubscriberInterface
$r = new \ReflectionFunction(\Closure::fromCallable($event->getController())); $r = new \ReflectionFunction(\Closure::fromCallable($event->getController()));
$r = $r->getParameters()[$k] ?? null; $r = $r->getParameters()[$k] ?? null;
if ($r && $r->hasType() && FlattenException::class === $r->getType()->getName()) { if ($r && (!$r->hasType() || FlattenException::class === $r->getType()->getName())) {
$arguments = $event->getArguments(); $arguments = $event->getArguments();
$arguments[$k] = FlattenException::createFromThrowable($e); $arguments[$k] = FlattenException::createFromThrowable($e);
$event->setArguments($arguments); $event->setArguments($arguments);

View File

@ -66,6 +66,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private $requestStackSize = 0; private $requestStackSize = 0;
private $resetServices = false; private $resetServices = false;
private static $freshCache = [];
const VERSION = '5.0.0-DEV'; const VERSION = '5.0.0-DEV';
const VERSION_ID = 50000; const VERSION_ID = 50000;
const MAJOR_VERSION = 5; const MAJOR_VERSION = 5;
@ -430,7 +432,9 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING); $errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
try { try {
if (file_exists($cachePath) && \is_object($this->container = include $cachePath) && (!$this->debug || $cache->isFresh())) { if (file_exists($cachePath) && \is_object($this->container = include $cachePath)
&& (!$this->debug || (self::$freshCache[$k = $cachePath.'.'.$this->environment] ?? self::$freshCache[$k] = $cache->isFresh()))
) {
$this->container->set('kernel', $this); $this->container->set('kernel', $this);
error_reporting($errorLevel); error_reporting($errorLevel);

View File

@ -13,8 +13,8 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
@ -158,12 +158,11 @@ class ErrorListenerTest extends TestCase
$this->assertFalse($dispatcher->hasListeners(KernelEvents::RESPONSE), 'CSP removal listener has been removed'); $this->assertFalse($dispatcher->hasListeners(KernelEvents::RESPONSE), 'CSP removal listener has been removed');
} }
public function testOnControllerArguments() /**
* @dataProvider controllerProvider
*/
public function testOnControllerArguments(callable $controller)
{ {
$controller = function (FlattenException $exception) {
return new Response('OK: '.$exception->getMessage());
};
$listener = new ErrorListener($controller, $this->createMock(LoggerInterface::class), true); $listener = new ErrorListener($controller, $this->createMock(LoggerInterface::class), true);
$kernel = $this->createMock(HttpKernelInterface::class); $kernel = $this->createMock(HttpKernelInterface::class);
@ -181,6 +180,23 @@ class ErrorListenerTest extends TestCase
$this->assertSame('OK: foo', $event->getResponse()->getContent()); $this->assertSame('OK: foo', $event->getResponse()->getContent());
} }
public function controllerProvider()
{
yield [function (FlattenException $exception) {
return new Response('OK: '.$exception->getMessage());
}];
yield [function ($exception) {
$this->assertInstanceOf(FlattenException::class, $exception);
return new Response('OK: '.$exception->getMessage());
}];
yield [function (\Throwable $exception) {
return new Response('OK: '.$exception->getMessage());
}];
}
} }
class TestLogger extends Logger implements DebugLoggerInterface class TestLogger extends Logger implements DebugLoggerInterface

View File

@ -4,6 +4,7 @@ CHANGELOG
4.4.0 4.4.0
----- -----
* [BC BREAK] changed the `NullTransport` DSN from `smtp://null` to `null://null`
* [BC BREAK] renamed `SmtpEnvelope` to `Envelope`, renamed `DelayedSmtpEnvelope` to * [BC BREAK] renamed `SmtpEnvelope` to `Envelope`, renamed `DelayedSmtpEnvelope` to
`DelayedEnvelope` `DelayedEnvelope`
* [BC BREAK] changed the syntax for failover and roundrobin DSNs * [BC BREAK] changed the syntax for failover and roundrobin DSNs

View File

@ -18,6 +18,7 @@ use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface
use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
/** /**
* AccessListener enforces access control rules. * AccessListener enforces access control rules.
@ -49,6 +50,10 @@ class AccessListener
*/ */
public function __invoke(RequestEvent $event) public function __invoke(RequestEvent $event)
{ {
if (!$event instanceof LazyResponseEvent && null === $token = $this->tokenStorage->getToken()) {
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
}
$request = $event->getRequest(); $request = $event->getRequest();
list($attributes) = $this->map->getPatterns($request); list($attributes) = $this->map->getPatterns($request);
@ -57,7 +62,7 @@ class AccessListener
return; return;
} }
if (null === $token = $this->tokenStorage->getToken()) { if ($event instanceof LazyResponseEvent && null === $token = $this->tokenStorage->getToken()) {
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.'); throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
} }

View File

@ -18,6 +18,7 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
use Symfony\Component\Security\Http\Firewall\AccessListener; use Symfony\Component\Security\Http\Firewall\AccessListener;
class AccessListenerTest extends TestCase class AccessListenerTest extends TestCase
@ -219,7 +220,7 @@ class AccessListenerTest extends TestCase
->willReturn($request) ->willReturn($request)
; ;
$listener($event); $listener(new LazyResponseEvent($event));
} }
public function testHandleWhenTheSecurityTokenStorageHasNoToken() public function testHandleWhenTheSecurityTokenStorageHasNoToken()