Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a114f8d

Browse files
committed
feature #36575 [Security] Require entry_point to be configured with multiple authenticators (wouterj)
This PR was squashed before being merged into the 5.1-dev branch. Discussion ---------- [Security] Require entry_point to be configured with multiple authenticators | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | tbd See @weaverryan's comment at #33558 (comment): > I have it on my list to look at the entrypoint stuff more closely. But my gut reaction is this: let's fix them (or try to... or maybe in a PR after this) :). What I mean is this: > > - It's always been confusing that your firewall may have multiple auth mechanisms that have their own "entry point"... and one is chosen seemingly at random :). I know it's not random, but why does the entrypoint from `form_login` "win" over `http_basic` if I have both defined under my firewall? > > - Since we're moving to a new system, why not throw an exception the _moment_ that a firewall has multiple entrypoints available to it. Then we _force_ the user to choose the _one_ entrypoint that should be used. --- **Before** (one authenticator) ```yaml security: enable_authenticator_manager: true firewalls: main: form_login: ... # form login is your entry point ``` **After** Same as before --- **Before** (multiple authenticators) ```yaml security: enable_authenticator_manager: true firewalls: main: http_basic: ... form_login: ... # for some reason, FormLogin is now your entry point! (config order doesn't matter) ``` **After** ```yaml security: enable_authenticator_manager: true firewalls: main: http_basic: ... form_login: ... entry_point: form_login ``` --- **Before** (custom entry point service) ```yaml security: enable_authenticator_manager: true firewalls: main: http_basic: ... form_login: ... entry_point: App\Security\CustomEntryPoint ``` **After** Same as before Commits ------- 7e86169 [Security] Require entry_point to be configured with multiple authenticators
2 parents 71b3912 + 7e86169 commit a114f8d

17 files changed

+81
-15
lines changed

UPGRADE-5.1.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ Routing
109109
* Added argument `$priority` to `RouteCollection::add()`
110110
* Deprecated the `RouteCompiler::REGEX_DELIMITER` constant
111111

112+
SecurityBundle
113+
--------------
114+
115+
* Marked the `AbstractFactory`, `AnonymousFactory`, `FormLoginFactory`, `FormLoginLdapFactory`, `GuardAuthenticationFactory`,
116+
`HttpBasicFactory`, `HttpBasicLdapFactory`, `JsonLoginFactory`, `JsonLoginLdapFactory`, `RememberMeFactory`, `RemoteUserFactory`
117+
and `X509Factory` as `@internal`. Instead of extending these classes, create your own implementation based on
118+
`SecurityFactoryInterface`.
119+
112120
Security
113121
--------
114122

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ CHANGELOG
66

77
* Added XSD for configuration
88
* Added security configuration for priority-based access decision strategy
9+
* Marked the `AbstractFactory`, `AnonymousFactory`, `FormLoginFactory`, `FormLoginLdapFactory`, `GuardAuthenticationFactory`, `HttpBasicFactory`, `HttpBasicLdapFactory`, `JsonLoginFactory`, `JsonLoginLdapFactory`, `RememberMeFactory`, `RemoteUserFactory` and `X509Factory` as `@internal`
10+
* Renamed method `AbstractFactory#createEntryPoint()` to `AbstractFactory#createDefaultEntryPoint()`
911

1012
5.0.0
1113
-----

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
* @author Fabien Potencier <[email protected]>
2424
* @author Lukas Kahwe Smith <[email protected]>
2525
* @author Johannes M. Schmitt <[email protected]>
26+
*
27+
* @internal
2628
*/
2729
abstract class AbstractFactory implements SecurityFactoryInterface
2830
{
@@ -65,7 +67,7 @@ public function create(ContainerBuilder $container, string $id, array $config, s
6567
}
6668

6769
// create entry point if applicable (optional)
68-
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPointId);
70+
$entryPointId = $this->createDefaultEntryPoint($container, $id, $config, $defaultEntryPointId);
6971

7072
return [$authProviderId, $listenerId, $entryPointId];
7173
}
@@ -126,7 +128,7 @@ abstract protected function getListenerId();
126128
*
127129
* @return string|null the entry point id
128130
*/
129-
protected function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId)
131+
protected function createDefaultEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId)
130132
{
131133
return $defaultEntryPointId;
132134
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AnonymousFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
/**
2020
* @author Wouter de Jong <[email protected]>
21+
*
22+
* @internal
2123
*/
2224
class AnonymousFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2325
{

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/CustomAuthenticatorFactory.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
1717

18+
/**
19+
* @author Wouter de Jong <[email protected]>
20+
*
21+
* @internal
22+
* @experimental in Symfony 5.1
23+
*/
1824
class CustomAuthenticatorFactory implements AuthenticatorFactoryInterface, SecurityFactoryInterface
1925
{
2026
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint)

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/EntryPointFactoryInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ interface EntryPointFactoryInterface
2323
/**
2424
* Creates the entry point and returns the service ID.
2525
*/
26-
public function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId): string;
26+
public function createEntryPoint(ContainerBuilder $container, string $id, array $config): ?string;
2727
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*
2323
* @author Fabien Potencier <[email protected]>
2424
* @author Johannes M. Schmitt <[email protected]>
25+
*
26+
* @internal
2527
*/
2628
class FormLoginFactory extends AbstractFactory implements AuthenticatorFactoryInterface, EntryPointFactoryInterface
2729
{
@@ -90,7 +92,12 @@ protected function createListener(ContainerBuilder $container, string $id, array
9092
return $listenerId;
9193
}
9294

93-
public function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPoint): string
95+
protected function createDefaultEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId)
96+
{
97+
return $this->createEntryPoint($container, $id, $config);
98+
}
99+
100+
public function createEntryPoint(ContainerBuilder $container, string $id, array $config): string
94101
{
95102
$entryPointId = 'security.authentication.form_entry_point.'.$id;
96103
$container

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginLdapFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
*
2323
* @author Grégoire Pineau <[email protected]>
2424
* @author Charles Sarrazin <[email protected]>
25+
*
26+
* @internal
2527
*/
2628
class FormLoginLdapFactory extends FormLoginFactory
2729
{

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/GuardAuthenticationFactory.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
* Configures the "guard" authentication provider key under a firewall.
2424
*
2525
* @author Ryan Weaver <[email protected]>
26+
*
27+
* @internal
2628
*/
2729
class GuardAuthenticationFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface, EntryPointFactoryInterface
2830
{
@@ -111,9 +113,15 @@ public function createAuthenticator(ContainerBuilder $container, string $firewal
111113
return $authenticatorIds;
112114
}
113115

114-
public function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPointId): string
116+
public function createEntryPoint(ContainerBuilder $container, string $id, array $config): ?string
115117
{
116-
return $this->determineEntryPoint($defaultEntryPointId, $config);
118+
try {
119+
return $this->determineEntryPoint(null, $config);
120+
} catch (\LogicException $e) {
121+
// ignore the exception, the new system prefers setting "entry_point" over "guard.entry_point"
122+
}
123+
124+
return null;
117125
}
118126

119127
private function determineEntryPoint(?string $defaultEntryPointId, array $config): string

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicFactory.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
* HttpBasicFactory creates services for HTTP basic authentication.
2121
*
2222
* @author Fabien Potencier <[email protected]>
23+
*
24+
* @internal
2325
*/
24-
class HttpBasicFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
26+
class HttpBasicFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface, EntryPointFactoryInterface
2527
{
2628
public function create(ContainerBuilder $container, string $id, array $config, string $userProvider, ?string $defaultEntryPoint)
2729
{
@@ -34,7 +36,10 @@ public function create(ContainerBuilder $container, string $id, array $config, s
3436
;
3537

3638
// entry point
37-
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
39+
$entryPointId = $defaultEntryPoint;
40+
if (null === $entryPointId) {
41+
$entryPointId = $this->createEntryPoint($container, $id, $config);
42+
}
3843

3944
// listener
4045
$listenerId = 'security.authentication.listener.basic.'.$id;
@@ -77,12 +82,8 @@ public function addConfiguration(NodeDefinition $node)
7782
;
7883
}
7984

80-
protected function createEntryPoint(ContainerBuilder $container, string $id, array $config, ?string $defaultEntryPoint)
85+
public function createEntryPoint(ContainerBuilder $container, string $id, array $config): string
8186
{
82-
if (null !== $defaultEntryPoint) {
83-
return $defaultEntryPoint;
84-
}
85-
8687
$entryPointId = 'security.authentication.basic_entry_point.'.$id;
8788
$container
8889
->setDefinition($entryPointId, new ChildDefinition('security.authentication.basic_entry_point'))

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/HttpBasicLdapFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
* @author Fabien Potencier <[email protected]>
2424
* @author Grégoire Pineau <[email protected]>
2525
* @author Charles Sarrazin <[email protected]>
26+
*
27+
* @internal
2628
*/
2729
class HttpBasicLdapFactory extends HttpBasicFactory
2830
{

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/JsonLoginFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
* JsonLoginFactory creates services for JSON login authentication.
2020
*
2121
* @author Kévin Dunglas <[email protected]>
22+
*
23+
* @internal
2224
*/
2325
class JsonLoginFactory extends AbstractFactory implements AuthenticatorFactoryInterface
2426
{

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/JsonLoginLdapFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
/**
2121
* JsonLoginLdapFactory creates services for json login ldap authentication.
22+
*
23+
* @internal
2224
*/
2325
class JsonLoginLdapFactory extends JsonLoginFactory
2426
{

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
use Symfony\Component\HttpFoundation\Cookie;
2121
use Symfony\Component\Security\Http\EventListener\RememberMeLogoutListener;
2222

23+
/**
24+
* @internal
25+
*/
2326
class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2427
{
2528
protected $options = [

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RemoteUserFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
*
2222
* @author Fabien Potencier <[email protected]>
2323
* @author Maxime Douailin <[email protected]>
24+
*
25+
* @internal
2426
*/
2527
class RemoteUserFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2628
{

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/X509Factory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* X509Factory creates services for X509 certificate authentication.
2121
*
2222
* @author Fabien Potencier <[email protected]>
23+
*
24+
* @internal
2325
*/
2426
class X509Factory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
2527
{

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use Symfony\Component\Security\Core\User\ChainUserProvider;
4040
use Symfony\Component\Security\Core\User\UserProviderInterface;
4141
use Symfony\Component\Security\Http\Controller\UserValueResolver;
42+
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
4243
use Twig\Extension\AbstractExtension;
4344

4445
/**
@@ -519,6 +520,7 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri
519520
{
520521
$listeners = [];
521522
$hasListeners = false;
523+
$entryPoints = [];
522524

523525
foreach ($this->listenerPositions as $position) {
524526
foreach ($this->factories[$position] as $factory) {
@@ -541,8 +543,8 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri
541543
$authenticationProviders[] = $authenticators;
542544
}
543545

544-
if ($factory instanceof EntryPointFactoryInterface) {
545-
$defaultEntryPoint = $factory->createEntryPoint($container, $id, $firewall[$key], $defaultEntryPoint);
546+
if ($factory instanceof EntryPointFactoryInterface && ($entryPoint = $factory->createEntryPoint($container, $id, $firewall[$key], null))) {
547+
$entryPoints[$key] = $entryPoint;
546548
}
547549
} else {
548550
list($provider, $listenerId, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
@@ -555,6 +557,19 @@ private function createAuthenticationListeners(ContainerBuilder $container, stri
555557
}
556558
}
557559

560+
if ($entryPoints) {
561+
// we can be sure the authenticator system is enabled
562+
if (null !== $defaultEntryPoint) {
563+
return $entryPoints[$defaultEntryPoint] ?? $defaultEntryPoint;
564+
}
565+
566+
if (1 === \count($entryPoints)) {
567+
return current($entryPoints);
568+
}
569+
570+
throw new InvalidConfigurationException(sprintf('Because you have multiple authenticators in firewall "%s", you need to set the "entry_point" key to one of your authenticators (%s) or a service ID implementing "%s". The "entry_point" determines what should happen (e.g. redirect to "/login") when an anonymous user tries to access a protected page.', $id, implode(', ', $entryPoints), AuthenticationEntryPointInterface::class));
571+
}
572+
558573
if (false === $hasListeners) {
559574
throw new InvalidConfigurationException(sprintf('No authentication listener registered for firewall "%s".', $id));
560575
}

0 commit comments

Comments
 (0)