diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/User/FilesystemUserProvider.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/User/FilesystemUserProvider.php new file mode 100644 index 0000000000000..c3fbc5173352e --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/User/FilesystemUserProvider.php @@ -0,0 +1,30 @@ + + * + * 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\FormLoginBundle\Security\User; + +use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Security\Core\User\InMemoryUserProvider; + +class FilesystemUserProvider extends InMemoryUserProvider +{ + public static function getFilename($testCase) + { + return sys_get_temp_dir().'/'.Kernel::VERSION.'/'. $testCase .'/user.txt'; + } + + public function __construct($testCase) + { + $users = json_decode(file_get_contents(self::getFilename($testCase)), true); + + parent::__construct($users); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php index 1b8415ad2ad59..94134ba80f343 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php @@ -11,6 +11,8 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional; +use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security\User\FilesystemUserProvider; + class FormLoginTest extends WebTestCase { /** @@ -76,6 +78,37 @@ public function testFormLoginRedirectsToProtectedResourceAfterLogin($config) $this->assertContains('You\'re browsing to path "/protected_resource".', $text); } + public function testFormLoginRedirectsToEntryPointWithAuthenticationExceptionMessage() + { + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'custom_provider.yml')); + $client->insulate(); + + // An user is added to the FilesystemUserProvider + file_put_contents(FilesystemUserProvider::getFilename('StandardFormLogin'), json_encode( + array('johannes' => array('password' => 'test', 'roles' => array('ROLE_USER'))) + )); + + $form = $client->request('GET', '/login')->selectButton('login')->form(); + + $form['_username'] = 'johannes'; + $form['_password'] = 'test'; + $client->submit($form); + + $client->followRedirect(); + + // The username is modified between two requests + file_put_contents(FilesystemUserProvider::getFilename('StandardFormLogin'), json_encode( + array('johannes_' => array('password' => 'test', 'roles' => array('ROLE_USER'))) + )); + + $client->request('GET', '/profile'); + + $crawler = $client->followRedirect(); + + // The message from the authentication exception thrown during the refreshUser is displayed + $this->assertContains('Username "johannes" does not exist.', $crawler->text()); + } + public function getConfigs() { return array( diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/custom_provider.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/custom_provider.yml new file mode 100644 index 0000000000000..189fe8fc08652 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/custom_provider.yml @@ -0,0 +1,27 @@ +imports: + - { resource: ./../config/default.yml } + +services: + filesystem_user_provider: + class: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security\User\FilesystemUserProvider + arguments: + - %kernel.test_case% + +security: + encoders: + Symfony\Component\Security\Core\User\User: plaintext + + providers: + filesystem: + id: filesystem_user_provider + + firewalls: + login_form: + pattern: ^/login$ + security: false + + default: + form_login: + check_path: /login_check + default_target_path: /profile + anonymous: ~ diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 43ad31d1a1629..334da578d9540 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -144,6 +144,7 @@ public function onKernelResponse(FilterResponseEvent $event) * * @return TokenInterface|null * + * @throws UsernameNotFoundException * @throws \RuntimeException */ private function refreshUser(TokenInterface $token) @@ -174,7 +175,7 @@ private function refreshUser(TokenInterface $token) $this->logger->warning(sprintf('Username "%s" could not be found.', $e->getUsername())); } - return; + throw $e; } } diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 8553c75b79d44..a74d477de1fba 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; use Symfony\Component\Security\Core\Exception\LogoutException; +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\HttpFoundation\Request; use Psr\Log\LoggerInterface; @@ -100,6 +101,15 @@ private function handleAuthenticationException(GetResponseForExceptionEvent $eve $this->logger->info(sprintf('Authentication exception occurred; redirecting to authentication entry point (%s)', $exception->getMessage())); } + if ($event->getRequest()->hasSession() && !$this->stateless) { + $session = $event->getRequest()->getSession(); + $session->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + + if ($exception instanceof UsernameNotFoundException) { + $session->set(SecurityContextInterface::LAST_USERNAME, $exception->getUsername()); + } + } + try { $event->setResponse($this->startAuthentication($event->getRequest(), $exception)); } catch (\Exception $e) {