Added FormLogin and Anonymous authenticators
This commit is contained in:
parent
9b7fddd10c
commit
a172bacaa6
@ -19,7 +19,7 @@ use Symfony\Component\DependencyInjection\Parameter;
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class AnonymousFactory implements SecurityFactoryInterface
|
||||
class AnonymousFactory implements SecurityFactoryInterface, GuardFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||
{
|
||||
@ -42,6 +42,20 @@ class AnonymousFactory implements SecurityFactoryInterface
|
||||
return [$providerId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
|
||||
{
|
||||
if (null === $config['secret']) {
|
||||
$config['secret'] = new Parameter('container.build_hash');
|
||||
}
|
||||
|
||||
$authenticatorId = 'security.authenticator.anonymous.'.$id;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.anonymous'))
|
||||
->replaceArgument(0, $config['secret']);
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPosition()
|
||||
{
|
||||
return 'anonymous';
|
||||
|
@ -22,7 +22,7 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class FormLoginFactory extends AbstractFactory
|
||||
class FormLoginFactory extends AbstractFactory implements GuardFactoryInterface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
@ -96,4 +96,17 @@ class FormLoginFactory extends AbstractFactory
|
||||
|
||||
return $entryPointId;
|
||||
}
|
||||
|
||||
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.form_login.'.$id;
|
||||
$defaultOptions = array_merge($this->defaultSuccessHandlerOptions, $this->options);
|
||||
$options = array_merge($defaultOptions, array_intersect_key($config, $defaultOptions));
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.form_login'))
|
||||
->replaceArgument(1, isset($config['csrf_token_generator']) ? new Reference($config['csrf_token_generator']) : null)
|
||||
->replaceArgument(3, $options);
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
}
|
||||
|
@ -23,5 +23,5 @@ interface GuardFactoryInterface
|
||||
*
|
||||
* @return string|string[] The Guard service ID(s) to be used by the firewall
|
||||
*/
|
||||
public function createGuard(ContainerBuilder $container, string $id, array $config, string $userProviderId);
|
||||
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class HttpBasicFactory implements SecurityFactoryInterface, GuardFactoryInterfac
|
||||
return [$provider, $listenerId, $entryPointId];
|
||||
}
|
||||
|
||||
public function createGuard(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
public function createGuard(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.http_basic.'.$id;
|
||||
$container
|
||||
|
@ -138,7 +138,9 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
$container->setParameter('security.access.always_authenticate_before_granting', $config['always_authenticate_before_granting']);
|
||||
$container->setParameter('security.authentication.hide_user_not_found', $config['hide_user_not_found']);
|
||||
|
||||
$this->guardAuthenticationManagerEnabled = $config['guard_authentication_manager'];
|
||||
if ($this->guardAuthenticationManagerEnabled = $config['guard_authentication_manager']) {
|
||||
$loader->load('authenticators.xml');
|
||||
}
|
||||
|
||||
$this->createFirewalls($config, $container);
|
||||
$this->createAuthorization($config, $container);
|
||||
|
@ -12,5 +12,20 @@
|
||||
<argument type="service" id="security.encoder_factory" />
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
<service id="security.authenticator.form_login"
|
||||
class="Symfony\Component\Security\Core\Authentication\Authenticator\FormLoginAuthenticator"
|
||||
abstract="true">
|
||||
<argument type="service" id="security.http_utils" />
|
||||
<argument /> <!-- csrf token generator -->
|
||||
<argument type="service" id="security.encoder_factory" />
|
||||
<argument type="abstract">options</argument>
|
||||
</service>
|
||||
|
||||
<service id="security.authenticator.anonymous"
|
||||
class="Symfony\Component\Security\Core\Authentication\Authenticator\AnonymousAuthenticator"
|
||||
abstract="true">
|
||||
<argument /> <!-- secret -->
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -54,7 +54,7 @@
|
||||
</service>
|
||||
<service id="security.authentication.manager.guard" class="Symfony\Component\Security\Core\Authentication\GuardAuthenticationManager">
|
||||
<argument /> <!-- guard authenticators -->
|
||||
<argument /> <!-- User Checker -->
|
||||
<argument type="service" id="Symfony\Component\Security\Core\User\UserCheckerInterface" /> <!-- User Checker -->
|
||||
<argument>%security.authentication.manager.erase_credentials%</argument>
|
||||
<call method="setEventDispatcher">
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
|
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\User;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Guard\Token\GuardTokenInterface;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class AnonymousAuthenticator implements AuthenticatorInterface
|
||||
{
|
||||
private $secret;
|
||||
|
||||
public function __construct(string $secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
public function start(Request $request, AuthenticationException $authException = null)
|
||||
{
|
||||
return new Response(null, Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCredentials(Request $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getUser($credentials, UserProviderInterface $userProvider)
|
||||
{
|
||||
return new User('anon.', null);
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function createAuthenticatedToken(UserInterface $user, string $providerKey)
|
||||
{
|
||||
return new AnonymousToken($this->secret, 'anon.', []);
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
|
||||
{
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
|
||||
{
|
||||
}
|
||||
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Security\Core\Authentication\Authenticator;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Csrf\CsrfToken;
|
||||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
|
||||
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\ParameterBagUtils;
|
||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
|
||||
{
|
||||
use TargetPathTrait, UsernamePasswordTrait, UserProviderTrait {
|
||||
UsernamePasswordTrait::checkCredentials as checkPassword;
|
||||
}
|
||||
|
||||
private $options;
|
||||
private $httpUtils;
|
||||
private $csrfTokenManager;
|
||||
private $encoderFactory;
|
||||
|
||||
public function __construct(HttpUtils $httpUtils, ?CsrfTokenManagerInterface $csrfTokenManager, EncoderFactoryInterface $encoderFactory, array $options)
|
||||
{
|
||||
$this->httpUtils = $httpUtils;
|
||||
$this->csrfTokenManager = $csrfTokenManager;
|
||||
$this->encoderFactory = $encoderFactory;
|
||||
$this->options = array_merge([
|
||||
'username_parameter' => '_username',
|
||||
'password_parameter' => '_password',
|
||||
'csrf_parameter' => '_csrf_token',
|
||||
'csrf_token_id' => 'authenticate',
|
||||
'post_only' => true,
|
||||
|
||||
'always_use_default_target_path' => false,
|
||||
'default_target_path' => '/',
|
||||
'login_path' => '/login',
|
||||
'target_path_parameter' => '_target_path',
|
||||
'use_referer' => false,
|
||||
], $options);
|
||||
}
|
||||
|
||||
protected function getLoginUrl(): string
|
||||
{
|
||||
return $this->options['login_path'];
|
||||
}
|
||||
|
||||
public function supports(Request $request): bool
|
||||
{
|
||||
return ($this->options['post_only'] ? $request->isMethod('POST') : true)
|
||||
&& $this->httpUtils->checkRequestPath($request, $this->options['check_path']);
|
||||
}
|
||||
|
||||
public function getCredentials(Request $request): array
|
||||
{
|
||||
$credentials = [];
|
||||
|
||||
if (null !== $this->csrfTokenManager) {
|
||||
$credentials['csrf_token'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);
|
||||
}
|
||||
|
||||
if ($this->options['post_only']) {
|
||||
$credentials['username'] = ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter']);
|
||||
$credentials['password'] = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']);
|
||||
} else {
|
||||
$credentials['username'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter']);
|
||||
$credentials['password'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
|
||||
}
|
||||
|
||||
if (!\is_string($credentials['username']) && (!\is_object($credentials['username']) || !method_exists($credentials['username'], '__toString'))) {
|
||||
throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($credentials['username'])));
|
||||
}
|
||||
|
||||
$credentials['username'] = trim($credentials['username']);
|
||||
|
||||
if (\strlen($credentials['username']) > Security::MAX_USERNAME_LENGTH) {
|
||||
throw new BadCredentialsException('Invalid username.');
|
||||
}
|
||||
|
||||
$request->getSession()->set(Security::LAST_USERNAME, $username);
|
||||
|
||||
return $credentials;
|
||||
}
|
||||
|
||||
public function checkCredentials($credentials, UserInterface $user): bool
|
||||
{
|
||||
if (null !== $this->csrfTokenManager) {
|
||||
if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $credentials['csrf_token']))) {
|
||||
throw new InvalidCsrfTokenException('Invalid CSRF token.');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->checkPassword($credentials, $user);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
|
||||
{
|
||||
return $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request, $providerKey));
|
||||
}
|
||||
|
||||
private function determineTargetUrl(Request $request, string $providerKey)
|
||||
{
|
||||
if ($this->options['always_use_default_target_path']) {
|
||||
return $this->options['default_target_path'];
|
||||
}
|
||||
|
||||
if ($targetUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['target_path_parameter'])) {
|
||||
return $targetUrl;
|
||||
}
|
||||
|
||||
if ($targetUrl = $this->getTargetPath($request->getSession(), $providerKey)) {
|
||||
$this->removeTargetPath($request->getSession(), $providerKey);
|
||||
|
||||
return $targetUrl;
|
||||
}
|
||||
|
||||
if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) {
|
||||
if (false !== $pos = strpos($targetUrl, '?')) {
|
||||
$targetUrl = substr($targetUrl, 0, $pos);
|
||||
}
|
||||
if ($targetUrl && $targetUrl !== $this->httpUtils->generateUri($request, $this->options['login_path'])) {
|
||||
return $targetUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->options['default_target_path'];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user