8000 Added FormLogin and Anonymous authenticators · symfony/symfony@a172bac · GitHub
[go: up one dir, main page]

Skip to content

Commit a172bac

Browse files
committed
Added FormLogin and Anonymous authenticators
1 parent 9b7fddd commit a172bac

File tree

9 files changed

+262
-6
lines changed

9 files changed

+262
-6
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
/**
2020
* @author Wouter de Jong <wouter@wouterj.nl>
2121
*/
22-
class AnonymousFactory implements SecurityFactoryInterface
22+
class AnonymousFactory implements SecurityFactoryInterface, GuardFactoryInterface
2323
{
2424
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
2525
{
@@ -42,6 +42,20 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider,
4242
return [$providerId, $listenerId, $defaultEntryPoint];
4343
}
4444

45+
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
46+
{
47+
if (null === $config['secret']) {
48+
$config['secret'] = new Parameter('container.build_hash');
49+
}
50+
51+
$authenticatorId = 'security.authenticator.anonymous.'.$id;
52+
$container
53+
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.anonymous'))
54+
->replaceArgument(0, $config['secret']);
55+
56+
return $authenticatorId;
57+
}
58+
4559
public function getPosition()
4660
{
4761
return 'anonymous';

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* @author Fabien Potencier <fabien@symfony.com>
2323
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
2424
*/
25-
class FormLoginFactory extends AbstractFactory
25+
class FormLoginFactory extends AbstractFactory implements GuardFactoryInterface
2626
{
2727
public function __construct()
2828
{
@@ -96,4 +96,17 @@ protected function createEntryPoint(ContainerBuilder $container, string $id, arr
9696

9797
return $entryPointId;
9898
}
99+
100+
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
101+
{
102+
$authenticatorId = 'security.authenticator.form_login.'.$id;
103+
$defaultOptions = array_merge($this->defaultSuccessHandlerOptions, $this->options);
104+
$options = array_merge($defaultOptions, array_intersect_key($config, $defaultOptions));
105+
$container
106+
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.form_login'))
107+
->replaceArgument(1, isset($config['csrf_token_generator']) ? new Reference($config['csrf_token_generator']) : null)
108+
->replaceArgument(3, $options);
109+
110+
return $authenticatorId;
111+
}
99112
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ interface GuardFactoryInterface
2323
*
2424
* @return string|string[] The Guard service ID(s) to be used by the firewall
2525
*/
26-
public function createGuard(ContainerBuilder $container, string $id, array $config, string $userProviderId);
26+
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId);
2727
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function create(ContainerBuilder $container, string $id, array $config, s
4646
return [$provider, $listenerId, $entryPointId];
4747
}
4848

49-
public function createGuard(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
49+
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
5050
{
5151
$authenticatorId = 'security.authenticator.http_basic.'.$id;
5252
$container

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

Lines changed: 3 additions & 1 deletion
10000
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ public function load(array $configs, ContainerBuilder $container)
138138
$container->setParameter('security.access.always_authenticate_before_granting', $config['always_authenticate_before_granting']);
139139
$container->setParameter('security.authentication.hide_user_not_found', $config['hide_user_not_found']);
140140

141-
$this->guardAuthenticationManagerEnabled = $config['guard_authentication_manager'];
141+
if ($this->guardAuthenticationManagerEnabled = $config['guard_authentication_manager']) {
142+
$loader->load('authenticators.xml');
143+
}
142144

143145
$this->createFirewalls($config, $container);
144146
$this->createAuthorization($config, $container);

src/Symfony/Bundle/SecurityBundle/Resources/config/authenticators.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,20 @@
1212
<argument type="service" id="security.encoder_factory" />
1313
<argument type="service" id="logger" on-invalid="null" />
1414
</service>
15+
16+
<service id="security.authenticator.form_login"
17+
class="Symfony\Component\Security\Core\Authentication\Authenticator\FormLoginAuthenticator"
18+
abstract="true">
19+
<argument type="service" id="security.http_utils" />
20+
<argument /> <!-- csrf token generator -->
21+
<argument type="service" id="security.encoder_factory" />
22+
<argument type="abstract">options</argument>
23+
</service>
24+
25+
<service id="security.authenticator.anonymous"
26+
class="Symfony\Component\Security\Core\Authentication\Authenticator\AnonymousAuthenticator"
27+
abstract="true">
28+
<argument /> <!-- secret -->
29+
</service>
1530
</services>
1631
</container>

src/S 106D2 ymfony/Bundle/SecurityBundle/Resources/config/security.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
</service>
5555
<service id="security.authentication.manager.guard" class="Symfony\Component\Security\Core\Authentication\GuardAuthenticationManager">
5656
<argument /> <!-- guard authenticators -->
57-
<argument /> <!-- User Checker -->
57+
<argument type="service" id="Symfony\Component\Security\Core\User\UserCheckerInterface" /> <!-- User Checker -->
5858
<argument>%security.authentication.manager.erase_credentials%</argument>
5959
<call method="setEventDispatcher">
6060
<argument type="service" id="event_dispatcher" />
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
4+
5+
use Symfony\Component\HttpFoundation\Request;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
8+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
9+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
10+
use Symfony\Component\Security\Core\User\User;
11+
use Symfony\Component\Security\Core\User\UserInterface;
12+
use Symfony\Component\Security\Core\User\UserProviderInterface;
13+
use Symfony\Component\Security\Guard\AuthenticatorInterface;
14+
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
15+
16+
/**
17+
* @author Wouter de Jong <wouter@wouterj.nl>
18+
*/
19+
class AnonymousAuthenticator implements AuthenticatorInterface
20+
{
21+
private $secret;
22+
23+
public function __construct(string $secret)
24+
{
25+
$this->secret = $secret;
26+
}
27+
28+
public function start(Request $request, AuthenticationException $authException = null)
29+
{
30+
return new Response(null, Response::HTTP_UNAUTHORIZED);
31+
}
32+
33+
public function supports(Request $request): ?bool
34+
{
35+
return true;
36+
}
37+
38+
public function getCredentials(Request $request)
39+
{
40+
return [];
41+
}
42+
43+
public function getUser($credentials, UserProviderInterface $userProvider)
44+
{
45+
return new User('anon.', null);
46+
}
47+
48+
public function checkCredentials($credentials, UserInterface $user)
49+
{
50+
return true;
51+
}
52+
53+
public function createAuthenticatedToken(UserInterface $user, string $providerKey)
54+
{
55+
return new AnonymousToken($this->secret, 'anon.', []);
56+
}
57+
58+
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
59+
{
60+
}
61+
62+
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
63+
{
64+
}
65+
66+
public function supportsRememberMe(): bool
67+
{
68+
return false;
69+
}
70+
}
Lines changed: 142 additions & 0 deletions
E377
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
4+
5+
use Symfony\Component\HttpFoundation\Request;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
8+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
9+
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
10+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
11+
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
12+
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
13+
use Symfony\Component\Security\Core\Security;
14+
use Symfony\Component\Security\Core\User\UserInterface;
15+
use Symfony\Component\Security\Core\User\UserProviderInterface;
16+
use Symfony\Component\Security\Csrf\CsrfToken;
17+
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
18+
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
19+
use Symfony\Component\Security\Http\HttpUtils;
20+
use Symfony\Component\Security\Http\ParameterBagUtils;
21+
use Symfony\Component\Security\Http\Util\TargetPathTrait;
22+
23+
/**
24+
* @author Wouter de Jong <wouter@wouterj.nl>
25+
*/
26+
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
27+
{
28+
use TargetPathTrait, UsernamePasswordTrait, UserProviderTrait {
29+
UsernamePasswordTrait::checkCredentials as checkPassword;
30+
}
31+
32+
private $options;
33+
private $httpUtils;
34+
private $csrfTokenManager;
35+
private $encoderFactory;
36+
37+
public function __construct(HttpUtils $httpUtils, ?CsrfTokenManagerInterface $csrfTokenManager, EncoderFactoryInterface $encoderFactory, array $options)
38+
{
39+
$this->httpUtils = $httpUtils;
40+
$this->csrfTokenManager = $csrfTokenManager;
41+
$this->encoderFactory = $encoderFactory;
42+
$this->options = array_merge([
43+
'username_parameter' => '_username',
44+
'password_parameter' => '_password',
45+
'csrf_parameter' => '_csrf_token',
46+
'csrf_token_id' => 'authenticate',
47+
'post_only' => true,
48+
49+
'always_use_default_target_path' => false,
50+
'default_target_path' => '/',
51+
'login_path' => '/login',
52+
'target_path_parameter' => '_target_path',
53+
'use_referer' => false,
54+
], $options);
55+
}
56+
57+
protected function getLoginUrl(): string
58+
{
59+
return $this->options['login_path'];
60+
}
61+
62+
public function supports(Request $request): bool
63+
{
64+
return ($this->options['post_only'] ? $request->isMethod('POST') : true)
65+
&& $this->httpUtils->checkRequestPath($request, $this->options['check_path']);
66+
}
67+
68+
public function getCredentials(Request $request): array
69+
{
70+
$credentials = [];
71+
72+
if (null !== $this->csrfTokenManager) {
73+
$credentials['csrf_token'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);
74+
}
75+
76+
if ($this->options['post_only']) {
77+
$credentials['username'] = ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter']);
78+
$credentials['password'] = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']);
79+
} else {
80+
$credentials['username'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter']);
81+
$credentials['password'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
82+
}
83+
84+
if (!\is_string($credentials['username']) && (!\is_object($credentials['username']) || !method_exists($credentials['username'], '__toString'))) {
85+
throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($credentials['username'])));
86+
}
87+
88+
$credentials['username'] = trim($credentials['username']);
89+
90+
if (\strlen($credentials['username']) > Security::MAX_USERNAME_LENGTH) {
91+
throw new BadCredentialsException('Invalid username.');
92+
}
93+
94+
$request->getSession()->set(Security::LAST_USERNAME, $username);
95+
96+
return $credentials;
97+
}
98+
99+
public function checkCredentials($credentials, UserInterface $user): bool
100+
{
101+
if (null !== $this->csrfTokenManager) {
102+
if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $credentials['csrf_token']))) {
103+
throw new InvalidCsrfTokenException('Invalid CSRF token.');
104+
}
105+
}
106+
107+
return $this->checkPassword($credentials, $user);
108+
}
109+
110+
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
111+
{
112+
return $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request, $providerKey));
113+
}
114+
115+
private function determineTargetUrl(Request $request, string $providerKey)
116+
{
117+
if ($this->options['always_use_default_target_path']) {
118+
return $this->options['default_target_path'];
119+
}
120+
121+
if ($targetUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['target_path_parameter'])) {
122+
return $targetUrl;
123+
}
124+
125+
if ($targetUrl = $this->getTargetPath($request->getSession(), $providerKey)) {
126+
$this->removeTargetPath($request->getSession(), $providerKey);
127+
128+
return $targetUrl;
129+
}
130+
131+
if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) {
132+
if (false !== $pos = strpos($targetUrl, '?')) {
133+
$targetUrl = substr($targetUrl, 0, $pos);
134+
}
135+
if ($targetUrl && $targetUrl !== $this->httpUtils->generateUri($request, $this->options['login_path'])) {
136+
return $targetUrl;
137+
}
138+
}
139+
140+
return $this->options['default_target_path'];
141+
}
142+
}

0 commit comments

Comments
 (0)
0