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>
|
* @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)
|
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||||
{
|
{
|
||||||
@ -42,6 +42,20 @@ class AnonymousFactory implements SecurityFactoryInterface
|
|||||||
return [$providerId, $listenerId, $defaultEntryPoint];
|
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()
|
public function getPosition()
|
||||||
{
|
{
|
||||||
return 'anonymous';
|
return 'anonymous';
|
||||||
|
@ -22,7 +22,7 @@ use Symfony\Component\DependencyInjection\Reference;
|
|||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||||
*/
|
*/
|
||||||
class FormLoginFactory extends AbstractFactory
|
class FormLoginFactory extends AbstractFactory implements GuardFactoryInterface
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@ -96,4 +96,17 @@ class FormLoginFactory extends AbstractFactory
|
|||||||
|
|
||||||
return $entryPointId;
|
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
|
* @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];
|
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;
|
$authenticatorId = 'security.authenticator.http_basic.'.$id;
|
||||||
$container
|
$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.access.always_authenticate_before_granting', $config['always_authenticate_before_granting']);
|
||||||
$container->setParameter('security.authentication.hide_user_not_found', $config['hide_user_not_found']);
|
$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->createFirewalls($config, $container);
|
||||||
$this->createAuthorization($config, $container);
|
$this->createAuthorization($config, $container);
|
||||||
|
@ -12,5 +12,20 @@
|
|||||||
<argument type="service" id="security.encoder_factory" />
|
<argument type="service" id="security.encoder_factory" />
|
||||||
<argument type="service" id="logger" on-invalid="null" />
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
</service>
|
</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>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
</service>
|
</service>
|
||||||
<service id="security.authentication.manager.guard" class="Symfony\Component\Security\Core\Authentication\GuardAuthenticationManager">
|
<service id="security.authentication.manager.guard" class="Symfony\Component\Security\Core\Authentication\GuardAuthenticationManager">
|
||||||
<argument /> <!-- guard authenticators -->
|
<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>
|
<argument>%security.authentication.manager.erase_credentials%</argument>
|
||||||
<call method="setEventDispatcher">
|
<call method="setEventDispatcher">
|
||||||
<argument type="service" id="event_dispatcher" />
|
<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