bug #34358 [Security] always check the token on non-lazy firewalls (nicolas-grekas, lyrixx)

This PR was merged into the 4.4 branch.

Discussion
----------

 [Security] always check the token on non-lazy firewalls

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #34357
| License       | MIT
| Doc PR        |

Commits
-------

2c2632a04c [SecurityBundle] add tests with empty authenticator
797450d6b8 [Security] always check the token on non-lazy firewalls
This commit is contained in:
Nicolas Grekas 2019-11-15 12:06:35 +01:00
commit b8f8ac947e
7 changed files with 133 additions and 2 deletions

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

@ -18,6 +18,7 @@ use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
/**
* AccessListener enforces access control rules.
@ -51,6 +52,10 @@ class AccessListener implements ListenerInterface
*/
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();
list($attributes) = $this->map->getPatterns($request);
@ -59,7 +64,7 @@ class AccessListener implements ListenerInterface
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.');
}

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\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
use Symfony\Component\Security\Http\Firewall\AccessListener;
class AccessListenerTest extends TestCase
@ -219,7 +220,7 @@ class AccessListenerTest extends TestCase
->willReturn($request)
;
$listener($event);
$listener(new LazyResponseEvent($event));
}
public function testHandleWhenTheSecurityTokenStorageHasNoToken()