Skip to content

Commit 46bdeb8

Browse files
committed
[SecurityBundle] Link UserProviderListener to correct firewall dispatcher
1 parent 0f4cbc0 commit 46bdeb8

File tree

7 files changed

+157
-2
lines changed

7 files changed

+157
-2
lines changed

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,8 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
339339

340340
$config->replaceArgument(4, $firewall['stateless']);
341341

342+
$firewallEventDispatcherId = 'security.event_dispatcher.'.$id;
343+
342344
// Provider id (must be configured explicitly per firewall/authenticator if more than one provider is set)
343345
$defaultProvider = null;
344346
if (isset($firewall['provider'])) {
@@ -349,7 +351,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
349351

350352
if ($this->authenticatorManagerEnabled) {
351353
$container->setDefinition('security.listener.'.$id.'.user_provider', new ChildDefinition('security.listener.user_provider.abstract'))
352-
->addTag('kernel.event_listener', ['event' => CheckPassportEvent::class, 'priority' => 2048, 'method' => 'checkPassport'])
354+
->addTag('kernel.event_listener', ['dispatcher' => $firewallEventDispatcherId, 'event' => CheckPassportEvent::class, 'priority' => 2048, 'method' => 'checkPassport'])
353355
->replaceArgument(0, new Reference($defaultProvider));
354356
}
355357
} elseif (1 === \count($providerIds)) {
@@ -359,7 +361,6 @@ private function createFirewall(ContainerBuilder $container, string $id, array $
359361
$config->replaceArgument(5, $defaultProvider);
360362

361363
// Register Firewall-specific event dispatcher
362-
$firewallEventDispatcherId = 'security.event_dispatcher.'.$id;
363364
$container->register($firewallEventDispatcherId, EventDispatcher::class);
364365

365366
// Register listeners

src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticatorTest.php

+24
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,28 @@ public function provideEmails()
6363
yield ['jane@example.org', true];
6464
yield ['john@example.org', false];
6565
}
66+
67+
/**
68+
* @dataProvider provideEmailsWithFirewalls
69+
*/
70+
public function testLoginUsersWithMultipleFirewalls(string $username, string $firewallContext)
71+
{
72+
$client = $this->createClient(['test_case' => 'Authenticator', 'root_config' => 'multiple_firewall_user_provider.yml']);
73+
$client->request('GET', '/main/login/check');
74+
75+
$client->request('POST', '/'.$firewallContext.'/login/check', [
76+
'_username' => $username,
77+
'_password' => 'test',
78+
]);
79+
$this->assertResponseRedirects('/'.$firewallContext.'/user_profile');
80+
81+
$client->request('GET', '/'.$firewallContext.'/user_profile');
82+
$this->assertEquals('Welcome '.$username.'!', $client->getResponse()->getContent());
83+
}
84+
85+
public function provideEmailsWithFirewalls()
86+
{
87+
yield ['jane@example.org', 'main'];
88+
yield ['john@example.org', 'custom'];
89+
}
6690
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle;
13+
14+
use Symfony\Component\HttpFoundation\RedirectResponse;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
18+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
19+
use Symfony\Component\Security\Core\Security;
20+
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
21+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
22+
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
23+
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
24+
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
25+
use Symfony\Component\Security\Http\Util\TargetPathTrait;
26+
27+
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
28+
{
29+
use TargetPathTrait;
30+
31+
/** @var UrlGeneratorInterface */
32+
private $urlGenerator;
33+
34+
public function __construct(UrlGeneratorInterface $urlGenerator)
35+
{
36+
$this->urlGenerator = $urlGenerator;
37+
}
38+
39+
public function authenticate(Request $request): PassportInterface
40+
{
41+
$username = $request->request->get('_username', '');
42+
43+
$request->getSession()->set(Security::LAST_USERNAME, $username);
44+
45+
return new Passport(
46+
new UserBadge($username),
47+
new PasswordCredentials($request->request->get('_password', '')),
48+
[]
49+
);
50+
}
51+
52+
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $firewallName): ?Response
53+
{
54+
return new RedirectResponse($this->urlGenerator->generate('security_'.$firewallName.'_profile'));
55+
}
56+
57+
protected function getLoginUrl(Request $request): string
58+
{
59+
return strpos($request->getUri(), 'main') ?
60+
$this->urlGenerator->generate('security_main_login') :
61+
$this->urlGenerator->generate('security_custom_login')
62+
;
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15+
use Symfony\Component\HttpFoundation\Response;
16+
17+
class SecurityController extends AbstractController
18+
{
19+
public function checkAction()
20+
{
21+
return new Response('OK');
22+
}
23+
24+
public function profileAction()
25+
{
26+
return new Response('Welcome '.$this->getUser()->getUsername().'!');
27+
}
28+
}

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/Authenticator/config.yml

+8
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,12 @@ services:
1414
calls:
1515
- ['setContainer', ['@Psr\Container\ContainerInterface']]
1616
tags: [container.service_subscriber]
17+
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\SecurityController:
18+
public: true
19+
calls:
20+
- ['setContainer', ['@Psr\Container\ContainerInterface']]
21+
tags: [container.service_subscriber]
1722
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\ApiAuthenticator: ~
23+
Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\LoginFormAuthenticator:
24+
public: true
25+
arguments: ['@router']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
imports:
2+
- { resource: ./config.yml }
3+
- { resource: ./security.yml }
4+
5+
security:
6+
firewalls:
7+
main:
8+
pattern: ^/main
9+
provider: in_memory
10+
custom_authenticator: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\LoginFormAuthenticator
11+
custom:
12+
pattern: ^/custom
13+
provider: in_memory2
14+
custom_authenticator: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\LoginFormAuthenticator

src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/Authenticator/routing.yml

+16
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,19 @@ profile:
22
path: /profile
33
defaults:
44
_controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\ProfileController
5+
6+
security_main_login:
7+
path: /main/login/check
8+
defaults: { _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\SecurityController::checkAction }
9+
10+
security_custom_login:
11+
path: /custom/login/check
12+
defaults: { _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\SecurityController::checkAction }
13+
14+
security_main_profile:
15+
path: /main/user_profile
16+
defaults: { _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\SecurityController::profileAction }
17+
18+
security_custom_profile:
19+
path: /custom/user_profile
20+
defaults: { _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\SecurityController::profileAction }

0 commit comments

Comments
 (0)