login consent app sql
This commit is contained in:
229
vendor/symfony/security-http/Firewall/AbstractAuthenticationListener.php
vendored
Normal file
229
vendor/symfony/security-http/Firewall/AbstractAuthenticationListener.php
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\SessionUnavailableException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', AbstractAuthenticationListener::class);
|
||||
|
||||
/**
|
||||
* The AbstractAuthenticationListener is the preferred base class for all
|
||||
* browser-/HTTP-based authentication requests.
|
||||
*
|
||||
* Subclasses likely have to implement the following:
|
||||
* - an TokenInterface to hold authentication related data
|
||||
* - an AuthenticationProvider to perform the actual authentication of the
|
||||
* token, retrieve the UserInterface implementation from a database, and
|
||||
* perform the specific account checks using the UserChecker
|
||||
*
|
||||
* By default, this listener only is active for a specific path, e.g.
|
||||
* /login_check. If you want to change this behavior, you can overwrite the
|
||||
* requiresAuthentication() method.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
abstract class AbstractAuthenticationListener extends AbstractListener
|
||||
{
|
||||
protected $options;
|
||||
protected $logger;
|
||||
protected $authenticationManager;
|
||||
protected $providerKey;
|
||||
protected $httpUtils;
|
||||
|
||||
private $tokenStorage;
|
||||
private $sessionStrategy;
|
||||
private $dispatcher;
|
||||
private $successHandler;
|
||||
private $failureHandler;
|
||||
private $rememberMeServices;
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, string $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = [], LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
if (empty($providerKey)) {
|
||||
throw new \InvalidArgumentException('$providerKey must not be empty.');
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->sessionStrategy = $sessionStrategy;
|
||||
$this->providerKey = $providerKey;
|
||||
$this->successHandler = $successHandler;
|
||||
$this->failureHandler = $failureHandler;
|
||||
$this->options = array_merge([
|
||||
'check_path' => '/login_check',
|
||||
'login_path' => '/login',
|
||||
'always_use_default_target_path' => false,
|
||||
'default_target_path' => '/',
|
||||
'target_path_parameter' => '_target_path',
|
||||
'use_referer' => false,
|
||||
'failure_path' => null,
|
||||
'failure_forward' => false,
|
||||
'require_previous_session' => true,
|
||||
], $options);
|
||||
$this->logger = $logger;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->httpUtils = $httpUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RememberMeServices implementation to use.
|
||||
*/
|
||||
public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices)
|
||||
{
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $this->requiresAuthentication($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles form based authentication.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @throws SessionUnavailableException
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$request->hasSession()) {
|
||||
throw new \RuntimeException('This authentication method requires a session.');
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->options['require_previous_session'] && !$request->hasPreviousSession()) {
|
||||
throw new SessionUnavailableException('Your session has timed out, or you have disabled cookies.');
|
||||
}
|
||||
|
||||
if (null === $returnValue = $this->attemptAuthentication($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($returnValue instanceof TokenInterface) {
|
||||
$this->sessionStrategy->onAuthentication($request, $returnValue);
|
||||
|
||||
$response = $this->onSuccess($request, $returnValue);
|
||||
} elseif ($returnValue instanceof Response) {
|
||||
$response = $returnValue;
|
||||
} else {
|
||||
throw new \RuntimeException('attemptAuthentication() must either return a Response, an implementation of TokenInterface, or null.');
|
||||
}
|
||||
} catch (AuthenticationException $e) {
|
||||
$response = $this->onFailure($request, $e);
|
||||
}
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this request requires authentication.
|
||||
*
|
||||
* The default implementation only processes requests to a specific path,
|
||||
* but a subclass could change this to only authenticate requests where a
|
||||
* certain parameters is present.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function requiresAuthentication(Request $request)
|
||||
{
|
||||
return $this->httpUtils->checkRequestPath($request, $this->options['check_path']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs authentication.
|
||||
*
|
||||
* @return TokenInterface|Response|null The authenticated token, null if full authentication is not possible, or a Response
|
||||
*
|
||||
* @throws AuthenticationException if the authentication fails
|
||||
*/
|
||||
abstract protected function attemptAuthentication(Request $request);
|
||||
|
||||
private function onFailure(Request $request, AuthenticationException $failed): Response
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Authentication request failed.', ['exception' => $failed]);
|
||||
}
|
||||
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getFirewallName()) {
|
||||
$this->tokenStorage->setToken(null);
|
||||
}
|
||||
|
||||
$response = $this->failureHandler->onAuthenticationFailure($request, $failed);
|
||||
|
||||
if (!$response instanceof Response) {
|
||||
throw new \RuntimeException('Authentication Failure Handler did not return a Response.');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function onSuccess(Request $request, TokenInterface $token): Response
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
// @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
|
||||
$this->logger->info('User has been authenticated successfully.', ['username' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()]);
|
||||
}
|
||||
|
||||
$this->tokenStorage->setToken($token);
|
||||
|
||||
$session = $request->getSession();
|
||||
$session->remove(Security::AUTHENTICATION_ERROR);
|
||||
$session->remove(Security::LAST_USERNAME);
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$loginEvent = new InteractiveLoginEvent($request, $token);
|
||||
$this->dispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
|
||||
}
|
||||
|
||||
$response = $this->successHandler->onAuthenticationSuccess($request, $token);
|
||||
|
||||
if (!$response instanceof Response) {
|
||||
throw new \RuntimeException('Authentication Success Handler did not return a Response.');
|
||||
}
|
||||
|
||||
if (null !== $this->rememberMeServices) {
|
||||
$this->rememberMeServices->loginSuccess($request, $response, $token);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
34
vendor/symfony/security-http/Firewall/AbstractListener.php
vendored
Normal file
34
vendor/symfony/security-http/Firewall/AbstractListener.php
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
|
||||
/**
|
||||
* A base class for listeners that can tell whether they should authenticate incoming requests.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
abstract class AbstractListener implements FirewallListenerInterface
|
||||
{
|
||||
final public function __invoke(RequestEvent $event)
|
||||
{
|
||||
if (false !== $this->supports($event->getRequest())) {
|
||||
$this->authenticate($event);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getPriority(): int
|
||||
{
|
||||
return 0; // Default
|
||||
}
|
||||
}
|
160
vendor/symfony/security-http/Firewall/AbstractPreAuthenticatedListener.php
vendored
Normal file
160
vendor/symfony/security-http/Firewall/AbstractPreAuthenticatedListener.php
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', AbstractPreAuthenticatedListener::class);
|
||||
|
||||
/**
|
||||
* AbstractPreAuthenticatedListener is the base class for all listener that
|
||||
* authenticates users based on a pre-authenticated request (like a certificate
|
||||
* for instance).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
abstract class AbstractPreAuthenticatedListener extends AbstractListener
|
||||
{
|
||||
protected $logger;
|
||||
private $tokenStorage;
|
||||
private $authenticationManager;
|
||||
private $providerKey;
|
||||
private $dispatcher;
|
||||
private $sessionStrategy;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, string $providerKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->providerKey = $providerKey;
|
||||
$this->logger = $logger;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
try {
|
||||
$request->attributes->set('_pre_authenticated_data', $this->getPreAuthenticatedData($request));
|
||||
} catch (BadCredentialsException $e) {
|
||||
$this->clearToken($e);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles pre-authentication.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
[$user, $credentials] = $request->attributes->get('_pre_authenticated_data');
|
||||
$request->attributes->remove('_pre_authenticated_data');
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Checking current security token.', ['token' => (string) $this->tokenStorage->getToken()]);
|
||||
}
|
||||
|
||||
if (null !== $token = $this->tokenStorage->getToken()) {
|
||||
// @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
|
||||
if ($token instanceof PreAuthenticatedToken && $this->providerKey == $token->getFirewallName() && $token->isAuthenticated() && (method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()) === $user) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Trying to pre-authenticate user.', ['username' => (string) $user]);
|
||||
}
|
||||
|
||||
try {
|
||||
$token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials, $this->providerKey));
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Pre-authentication successful.', ['token' => (string) $token]);
|
||||
}
|
||||
|
||||
$this->migrateSession($request, $token);
|
||||
|
||||
$this->tokenStorage->setToken($token);
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$loginEvent = new InteractiveLoginEvent($request, $token);
|
||||
$this->dispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
|
||||
}
|
||||
} catch (AuthenticationException $e) {
|
||||
$this->clearToken($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method if your authentication token is stored to a session.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy)
|
||||
{
|
||||
$this->sessionStrategy = $sessionStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a PreAuthenticatedToken for this provider (if present).
|
||||
*/
|
||||
private function clearToken(AuthenticationException $exception)
|
||||
{
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if ($token instanceof PreAuthenticatedToken && $this->providerKey === $token->getFirewallName()) {
|
||||
$this->tokenStorage->setToken(null);
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Cleared security token due to an exception.', ['exception' => $exception]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user and credentials from the Request.
|
||||
*
|
||||
* @return array An array composed of the user and the credentials
|
||||
*/
|
||||
abstract protected function getPreAuthenticatedData(Request $request);
|
||||
|
||||
private function migrateSession(Request $request, TokenInterface $token)
|
||||
{
|
||||
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sessionStrategy->onAuthentication($request, $token);
|
||||
}
|
||||
}
|
143
vendor/symfony/security-http/Firewall/AccessListener.php
vendored
Normal file
143
vendor/symfony/security-http/Firewall/AccessListener.php
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
|
||||
use Symfony\Component\Security\Http\AccessMapInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\NoopAuthenticationManager;
|
||||
use Symfony\Component\Security\Http\Event\LazyResponseEvent;
|
||||
|
||||
/**
|
||||
* AccessListener enforces access control rules.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class AccessListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $accessDecisionManager;
|
||||
private $map;
|
||||
private $authManager;
|
||||
private $exceptionOnNoToken;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, /*bool*/ $exceptionOnNoToken = true)
|
||||
{
|
||||
if ($exceptionOnNoToken instanceof AuthenticationManagerInterface) {
|
||||
trigger_deprecation('symfony/security-http', '5.4', 'The $authManager argument of "%s" is deprecated.', __METHOD__);
|
||||
$authManager = $exceptionOnNoToken;
|
||||
$exceptionOnNoToken = \func_num_args() > 4 ? func_get_arg(4) : true;
|
||||
}
|
||||
|
||||
if (false !== $exceptionOnNoToken) {
|
||||
trigger_deprecation('symfony/security-http', '5.4', 'Not setting the $exceptionOnNoToken argument of "%s" to "false" is deprecated.', __METHOD__);
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->accessDecisionManager = $accessDecisionManager;
|
||||
$this->map = $map;
|
||||
$this->authManager = $authManager ?? (class_exists(AuthenticationManagerInterface::class) ? new NoopAuthenticationManager() : null);
|
||||
$this->exceptionOnNoToken = $exceptionOnNoToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
[$attributes] = $this->map->getPatterns($request);
|
||||
$request->attributes->set('_access_control_attributes', $attributes);
|
||||
|
||||
if ($attributes && (
|
||||
(\defined(AuthenticatedVoter::class.'::IS_AUTHENTICATED_ANONYMOUSLY') ? [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] !== $attributes : true)
|
||||
&& [AuthenticatedVoter::PUBLIC_ACCESS] !== $attributes
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles access authorization.
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
* @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token and $exceptionOnNoToken is set to true
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (!$event instanceof LazyResponseEvent && null === ($token = $this->tokenStorage->getToken()) && $this->exceptionOnNoToken) {
|
||||
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
$attributes = $request->attributes->get('_access_control_attributes');
|
||||
$request->attributes->remove('_access_control_attributes');
|
||||
|
||||
if (!$attributes || ((
|
||||
(\defined(AuthenticatedVoter::class.'::IS_AUTHENTICATED_ANONYMOUSLY') ? [AuthenticatedVoter::IS_AUTHENTICATED_ANONYMOUSLY] === $attributes : false)
|
||||
|| [AuthenticatedVoter::PUBLIC_ACCESS] === $attributes
|
||||
) && $event instanceof LazyResponseEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event instanceof LazyResponseEvent) {
|
||||
$token = $this->tokenStorage->getToken();
|
||||
}
|
||||
|
||||
if (null === $token) {
|
||||
if ($this->exceptionOnNoToken) {
|
||||
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
|
||||
}
|
||||
|
||||
$token = new NullToken();
|
||||
}
|
||||
|
||||
// @deprecated since Symfony 5.4
|
||||
if (method_exists($token, 'isAuthenticated') && !$token->isAuthenticated(false)) {
|
||||
trigger_deprecation('symfony/core', '5.4', 'Returning false from "%s()" is deprecated, return null from "getUser()" instead.');
|
||||
|
||||
if ($this->authManager) {
|
||||
$token = $this->authManager->authenticate($token);
|
||||
$this->tokenStorage->setToken($token);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->accessDecisionManager->decide($token, $attributes, $request, true)) {
|
||||
throw $this->createAccessDeniedException($request, $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
private function createAccessDeniedException(Request $request, array $attributes)
|
||||
{
|
||||
$exception = new AccessDeniedException();
|
||||
$exception->setAttributes($attributes);
|
||||
$exception->setSubject($request);
|
||||
|
||||
return $exception;
|
||||
}
|
||||
|
||||
public static function getPriority(): int
|
||||
{
|
||||
return -255;
|
||||
}
|
||||
}
|
84
vendor/symfony/security-http/Firewall/AnonymousAuthenticationListener.php
vendored
Normal file
84
vendor/symfony/security-http/Firewall/AnonymousAuthenticationListener.php
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', AnonymousAuthenticationListener::class);
|
||||
|
||||
// Help opcache.preload discover always-needed symbols
|
||||
class_exists(AnonymousToken::class);
|
||||
|
||||
/**
|
||||
* AnonymousAuthenticationListener automatically adds a Token if none is
|
||||
* already present.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class AnonymousAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $secret;
|
||||
private $authenticationManager;
|
||||
private $logger;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, string $secret, LoggerInterface $logger = null, AuthenticationManagerInterface $authenticationManager = null)
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->secret = $secret;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null; // always run authenticate() lazily with lazy firewalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles anonymous authentication.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (null !== $this->tokenStorage->getToken()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$token = new AnonymousToken($this->secret, 'anon.', []);
|
||||
if (null !== $this->authenticationManager) {
|
||||
$token = $this->authenticationManager->authenticate($token);
|
||||
}
|
||||
|
||||
$this->tokenStorage->setToken($token);
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Populated the TokenStorage with an anonymous Token.');
|
||||
}
|
||||
} catch (AuthenticationException $failed) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Anonymous authentication failed.', ['exception' => $failed]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
vendor/symfony/security-http/Firewall/AuthenticatorManagerListener.php
vendored
Normal file
47
vendor/symfony/security-http/Firewall/AuthenticatorManagerListener.php
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticatorManagerInterface;
|
||||
|
||||
/**
|
||||
* Firewall authentication listener that delegates to the authenticator system.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
class AuthenticatorManagerListener extends AbstractListener
|
||||
{
|
||||
private $authenticatorManager;
|
||||
|
||||
public function __construct(AuthenticatorManagerInterface $authenticationManager)
|
||||
{
|
||||
$this->authenticatorManager = $authenticationManager;
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $this->authenticatorManager->supports($request);
|
||||
}
|
||||
|
||||
public function authenticate(RequestEvent $event): void
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$response = $this->authenticatorManager->authenticateRequest($request);
|
||||
if (null === $response) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
132
vendor/symfony/security-http/Firewall/BasicAuthenticationListener.php
vendored
Normal file
132
vendor/symfony/security-http/Firewall/BasicAuthenticationListener.php
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', AnonymousAuthenticationListener::class);
|
||||
|
||||
/**
|
||||
* BasicAuthenticationListener implements Basic HTTP authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class BasicAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $authenticationManager;
|
||||
private $providerKey;
|
||||
private $authenticationEntryPoint;
|
||||
private $logger;
|
||||
private $ignoreFailure;
|
||||
private $sessionStrategy;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, string $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null)
|
||||
{
|
||||
if (empty($providerKey)) {
|
||||
throw new \InvalidArgumentException('$providerKey must not be empty.');
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->providerKey = $providerKey;
|
||||
$this->authenticationEntryPoint = $authenticationEntryPoint;
|
||||
$this->logger = $logger;
|
||||
$this->ignoreFailure = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null !== $request->headers->get('PHP_AUTH_USER');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles basic authentication.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (null === $username = $request->headers->get('PHP_AUTH_USER')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $token = $this->tokenStorage->getToken()) {
|
||||
// @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
|
||||
if ($token instanceof UsernamePasswordToken && $token->isAuthenticated(false) && (method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()) === $username) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Basic authentication Authorization header found for user.', ['username' => $username]);
|
||||
}
|
||||
|
||||
try {
|
||||
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey));
|
||||
|
||||
$this->migrateSession($request, $token);
|
||||
|
||||
$this->tokenStorage->setToken($token);
|
||||
} catch (AuthenticationException $e) {
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getFirewallName()) {
|
||||
$this->tokenStorage->setToken(null);
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Basic authentication failed for user.', ['username' => $username, 'exception' => $e]);
|
||||
}
|
||||
|
||||
if ($this->ignoreFailure) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->setResponse($this->authenticationEntryPoint->start($request, $e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method if your authentication token is stored to a session.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy)
|
||||
{
|
||||
$this->sessionStrategy = $sessionStrategy;
|
||||
}
|
||||
|
||||
private function migrateSession(Request $request, TokenInterface $token)
|
||||
{
|
||||
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sessionStrategy->onAuthentication($request, $token);
|
||||
}
|
||||
}
|
122
vendor/symfony/security-http/Firewall/ChannelListener.php
vendored
Normal file
122
vendor/symfony/security-http/Firewall/ChannelListener.php
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Http\AccessMapInterface;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
|
||||
/**
|
||||
* ChannelListener switches the HTTP protocol based on the access control
|
||||
* configuration.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ChannelListener extends AbstractListener
|
||||
{
|
||||
private $map;
|
||||
private $authenticationEntryPoint = null;
|
||||
private $logger;
|
||||
private $httpPort;
|
||||
private $httpsPort;
|
||||
|
||||
public function __construct(AccessMapInterface $map, /*LoggerInterface*/ $logger = null, /*int*/ $httpPort = 80, /*int*/ $httpsPort = 443)
|
||||
{
|
||||
if ($logger instanceof AuthenticationEntryPointInterface) {
|
||||
trigger_deprecation('symfony/security-http', '5.4', 'The "$authenticationEntryPoint" argument of "%s()" is deprecated.', __METHOD__);
|
||||
|
||||
$this->authenticationEntryPoint = $logger;
|
||||
$nrOfArgs = \func_num_args();
|
||||
$logger = $nrOfArgs > 2 ? func_get_arg(2) : null;
|
||||
$httpPort = $nrOfArgs > 3 ? func_get_arg(3) : 80;
|
||||
$httpsPort = $nrOfArgs > 4 ? func_get_arg(4) : 443;
|
||||
}
|
||||
|
||||
if (null !== $logger && !$logger instanceof LoggerInterface) {
|
||||
throw new \TypeError(sprintf('Argument "$logger" of "%s()" must be instance of "%s", "%s" given.', __METHOD__, LoggerInterface::class, get_debug_type($logger)));
|
||||
}
|
||||
|
||||
$this->map = $map;
|
||||
$this->logger = $logger;
|
||||
$this->httpPort = $httpPort;
|
||||
$this->httpsPort = $httpsPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles channel management.
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
[, $channel] = $this->map->getPatterns($request);
|
||||
|
||||
if ('https' === $channel && !$request->isSecure()) {
|
||||
if (null !== $this->logger) {
|
||||
if ('https' === $request->headers->get('X-Forwarded-Proto')) {
|
||||
$this->logger->info('Redirecting to HTTPS. ("X-Forwarded-Proto" header is set to "https" - did you set "trusted_proxies" correctly?)');
|
||||
} elseif (str_contains($request->headers->get('Forwarded', ''), 'proto=https')) {
|
||||
$this->logger->info('Redirecting to HTTPS. ("Forwarded" header is set to "proto=https" - did you set "trusted_proxies" correctly?)');
|
||||
} else {
|
||||
$this->logger->info('Redirecting to HTTPS.');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ('http' === $channel && $request->isSecure()) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Redirecting to HTTP.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$event->setResponse($this->createRedirectResponse($request));
|
||||
}
|
||||
|
||||
private function createRedirectResponse(Request $request): RedirectResponse
|
||||
{
|
||||
if (null !== $this->authenticationEntryPoint) {
|
||||
return $this->authenticationEntryPoint->start($request);
|
||||
}
|
||||
|
||||
$scheme = $request->isSecure() ? 'http' : 'https';
|
||||
if ('http' === $scheme && 80 != $this->httpPort) {
|
||||
$port = ':'.$this->httpPort;
|
||||
} elseif ('https' === $scheme && 443 != $this->httpsPort) {
|
||||
$port = ':'.$this->httpsPort;
|
||||
} else {
|
||||
$port = '';
|
||||
}
|
||||
|
||||
$qs = $request->getQueryString();
|
||||
if (null !== $qs) {
|
||||
$qs = '?'.$qs;
|
||||
}
|
||||
|
||||
$url = $scheme.'://'.$request->getHost().$port.$request->getBaseUrl().$request->getPathInfo().$qs;
|
||||
|
||||
return new RedirectResponse($url, 301);
|
||||
}
|
||||
}
|
402
vendor/symfony/security-http/Firewall/ContextListener.php
vendored
Normal file
402
vendor/symfony/security-http/Firewall/ContextListener.php
vendored
Normal file
@ -0,0 +1,402 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
|
||||
use Symfony\Component\Security\Core\User\EquatableInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Event\DeauthenticatedEvent;
|
||||
use Symfony\Component\Security\Http\Event\TokenDeauthenticatedEvent;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* ContextListener manages the SecurityContext persistence through a session.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ContextListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $sessionKey;
|
||||
private $logger;
|
||||
private $userProviders;
|
||||
private $dispatcher;
|
||||
private $registered;
|
||||
private $trustResolver;
|
||||
private $rememberMeServices;
|
||||
private $sessionTrackerEnabler;
|
||||
|
||||
/**
|
||||
* @param iterable<mixed, UserProviderInterface> $userProviders
|
||||
*/
|
||||
public function __construct(TokenStorageInterface $tokenStorage, iterable $userProviders, string $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, AuthenticationTrustResolverInterface $trustResolver = null, callable $sessionTrackerEnabler = null)
|
||||
{
|
||||
if (empty($contextKey)) {
|
||||
throw new \InvalidArgumentException('$contextKey must not be empty.');
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->userProviders = $userProviders;
|
||||
$this->sessionKey = '_security_'.$contextKey;
|
||||
$this->logger = $logger;
|
||||
$this->dispatcher = class_exists(Event::class) ? LegacyEventDispatcherProxy::decorate($dispatcher) : $dispatcher;
|
||||
|
||||
$this->trustResolver = $trustResolver ?? new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class);
|
||||
$this->sessionTrackerEnabler = $sessionTrackerEnabler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null; // always run authenticate() lazily with lazy firewalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Security Token from the session.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (!$this->registered && null !== $this->dispatcher && $event->isMainRequest()) {
|
||||
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
|
||||
$this->registered = true;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
$session = $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
|
||||
|
||||
$request->attributes->set('_security_firewall_run', $this->sessionKey);
|
||||
|
||||
if (null !== $session) {
|
||||
$usageIndexValue = $session instanceof Session ? $usageIndexReference = &$session->getUsageIndex() : 0;
|
||||
$usageIndexReference = \PHP_INT_MIN;
|
||||
$sessionId = $request->cookies->all()[$session->getName()] ?? null;
|
||||
$token = $session->get($this->sessionKey);
|
||||
|
||||
// sessionId = true is used in the tests
|
||||
if ($this->sessionTrackerEnabler && \in_array($sessionId, [true, $session->getId()], true)) {
|
||||
$usageIndexReference = $usageIndexValue;
|
||||
} else {
|
||||
$usageIndexReference = $usageIndexReference - \PHP_INT_MIN + $usageIndexValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $session || null === $token) {
|
||||
if ($this->sessionTrackerEnabler) {
|
||||
($this->sessionTrackerEnabler)();
|
||||
}
|
||||
|
||||
$this->tokenStorage->setToken(null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$token = $this->safelyUnserialize($token);
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Read existing security token from the session.', [
|
||||
'key' => $this->sessionKey,
|
||||
'token_class' => \is_object($token) ? \get_class($token) : null,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($token instanceof TokenInterface) {
|
||||
$originalToken = $token;
|
||||
$token = $this->refreshUser($token);
|
||||
|
||||
if (!$token) {
|
||||
if ($this->logger) {
|
||||
$this->logger->debug('Token was deauthenticated after trying to refresh it.');
|
||||
}
|
||||
|
||||
if ($this->dispatcher) {
|
||||
$this->dispatcher->dispatch(new TokenDeauthenticatedEvent($originalToken, $request));
|
||||
}
|
||||
|
||||
if ($this->rememberMeServices) {
|
||||
$this->rememberMeServices->loginFail($request);
|
||||
}
|
||||
}
|
||||
} elseif (null !== $token) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning('Expected a security token from the session, got something else.', ['key' => $this->sessionKey, 'received' => $token]);
|
||||
}
|
||||
|
||||
$token = null;
|
||||
}
|
||||
|
||||
if ($this->sessionTrackerEnabler) {
|
||||
($this->sessionTrackerEnabler)();
|
||||
}
|
||||
|
||||
$this->tokenStorage->setToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the security token into the session.
|
||||
*/
|
||||
public function onKernelResponse(ResponseEvent $event)
|
||||
{
|
||||
if (!$event->isMainRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$request->hasSession() || $request->attributes->get('_security_firewall_run') !== $this->sessionKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->dispatcher) {
|
||||
$this->dispatcher->removeListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
|
||||
}
|
||||
$this->registered = false;
|
||||
$session = $request->getSession();
|
||||
$sessionId = $session->getId();
|
||||
$usageIndexValue = $session instanceof Session ? $usageIndexReference = &$session->getUsageIndex() : null;
|
||||
$token = $this->tokenStorage->getToken();
|
||||
|
||||
// @deprecated always use isAuthenticated() in 6.0
|
||||
$notAuthenticated = method_exists($this->trustResolver, 'isAuthenticated') ? !$this->trustResolver->isAuthenticated($token) : (null === $token || $this->trustResolver->isAnonymous($token));
|
||||
if ($notAuthenticated) {
|
||||
if ($request->hasPreviousSession()) {
|
||||
$session->remove($this->sessionKey);
|
||||
}
|
||||
} else {
|
||||
$session->set($this->sessionKey, serialize($token));
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Stored the security token in the session.', ['key' => $this->sessionKey]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->sessionTrackerEnabler && $session->getId() === $sessionId) {
|
||||
$usageIndexReference = $usageIndexValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the user by reloading it from the user provider.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function refreshUser(TokenInterface $token): ?TokenInterface
|
||||
{
|
||||
$user = $token->getUser();
|
||||
if (!$user instanceof UserInterface) {
|
||||
return $token;
|
||||
}
|
||||
|
||||
$userNotFoundByProvider = false;
|
||||
$userDeauthenticated = false;
|
||||
$userClass = \get_class($user);
|
||||
|
||||
foreach ($this->userProviders as $provider) {
|
||||
if (!$provider instanceof UserProviderInterface) {
|
||||
throw new \InvalidArgumentException(sprintf('User provider "%s" must implement "%s".', get_debug_type($provider), UserProviderInterface::class));
|
||||
}
|
||||
|
||||
if (!$provider->supportsClass($userClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$refreshedUser = $provider->refreshUser($user);
|
||||
$newToken = clone $token;
|
||||
$newToken->setUser($refreshedUser, false);
|
||||
|
||||
// tokens can be deauthenticated if the user has been changed.
|
||||
if ($token instanceof AbstractToken && $this->hasUserChanged($user, $newToken)) {
|
||||
$userDeauthenticated = true;
|
||||
// @deprecated since Symfony 5.4
|
||||
if (method_exists($newToken, 'setAuthenticated')) {
|
||||
$newToken->setAuthenticated(false, false);
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
// @deprecated since Symfony 5.3, change to $refreshedUser->getUserIdentifier() in 6.0
|
||||
$this->logger->debug('Cannot refresh token because user has changed.', ['username' => method_exists($refreshedUser, 'getUserIdentifier') ? $refreshedUser->getUserIdentifier() : $refreshedUser->getUsername(), 'provider' => \get_class($provider)]);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$token->setUser($refreshedUser);
|
||||
|
||||
if (null !== $this->logger) {
|
||||
// @deprecated since Symfony 5.3, change to $refreshedUser->getUserIdentifier() in 6.0
|
||||
$context = ['provider' => \get_class($provider), 'username' => method_exists($refreshedUser, 'getUserIdentifier') ? $refreshedUser->getUserIdentifier() : $refreshedUser->getUsername()];
|
||||
|
||||
if ($token instanceof SwitchUserToken) {
|
||||
$originalToken = $token->getOriginalToken();
|
||||
// @deprecated since Symfony 5.3, change to $originalToken->getUserIdentifier() in 6.0
|
||||
$context['impersonator_username'] = method_exists($originalToken, 'getUserIdentifier') ? $originalToken->getUserIdentifier() : $originalToken->getUsername();
|
||||
}
|
||||
|
||||
$this->logger->debug('User was reloaded from a user provider.', $context);
|
||||
}
|
||||
|
||||
return $token;
|
||||
} catch (UnsupportedUserException $e) {
|
||||
// let's try the next user provider
|
||||
} catch (UserNotFoundException $e) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning('Username could not be found in the selected user provider.', ['username' => method_exists($e, 'getUserIdentifier') ? $e->getUserIdentifier() : $e->getUsername(), 'provider' => \get_class($provider)]);
|
||||
}
|
||||
|
||||
$userNotFoundByProvider = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($userDeauthenticated) {
|
||||
// @deprecated since Symfony 5.4
|
||||
if ($this->dispatcher) {
|
||||
$this->dispatcher->dispatch(new DeauthenticatedEvent($token, $newToken, false), DeauthenticatedEvent::class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($userNotFoundByProvider) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('There is no user provider for user "%s". Shouldn\'t the "supportsClass()" method of your user provider return true for this classname?', $userClass));
|
||||
}
|
||||
|
||||
private function safelyUnserialize(string $serializedToken)
|
||||
{
|
||||
$token = null;
|
||||
$prevUnserializeHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
|
||||
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler) {
|
||||
if (__FILE__ === $file) {
|
||||
throw new \ErrorException($msg, 0x37313BC, $type, $file, $line);
|
||||
}
|
||||
|
||||
return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false;
|
||||
});
|
||||
|
||||
try {
|
||||
$token = unserialize($serializedToken);
|
||||
} catch (\ErrorException $e) {
|
||||
if (0x37313BC !== $e->getCode()) {
|
||||
throw $e;
|
||||
}
|
||||
if ($this->logger) {
|
||||
$this->logger->warning('Failed to unserialize the security token from the session.', ['key' => $this->sessionKey, 'received' => $serializedToken, 'exception' => $e]);
|
||||
}
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
ini_set('unserialize_callback_func', $prevUnserializeHandler);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|\Stringable|UserInterface $originalUser
|
||||
*/
|
||||
private static function hasUserChanged($originalUser, TokenInterface $refreshedToken): bool
|
||||
{
|
||||
$refreshedUser = $refreshedToken->getUser();
|
||||
|
||||
if ($originalUser instanceof UserInterface) {
|
||||
if (!$refreshedUser instanceof UserInterface) {
|
||||
return true;
|
||||
} else {
|
||||
// noop
|
||||
}
|
||||
} elseif ($refreshedUser instanceof UserInterface) {
|
||||
return true;
|
||||
} else {
|
||||
return (string) $originalUser !== (string) $refreshedUser;
|
||||
}
|
||||
|
||||
if ($originalUser instanceof EquatableInterface) {
|
||||
return !(bool) $originalUser->isEqualTo($refreshedUser);
|
||||
}
|
||||
|
||||
// @deprecated since Symfony 5.3, check for PasswordAuthenticatedUserInterface on both user objects before comparing passwords
|
||||
if ($originalUser->getPassword() !== $refreshedUser->getPassword()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// @deprecated since Symfony 5.3, check for LegacyPasswordAuthenticatedUserInterface on both user objects before comparing salts
|
||||
if ($originalUser->getSalt() !== $refreshedUser->getSalt()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$userRoles = array_map('strval', (array) $refreshedUser->getRoles());
|
||||
|
||||
if ($refreshedToken instanceof SwitchUserToken) {
|
||||
$userRoles[] = 'ROLE_PREVIOUS_ADMIN';
|
||||
}
|
||||
|
||||
if (
|
||||
\count($userRoles) !== \count($refreshedToken->getRoleNames()) ||
|
||||
\count($userRoles) !== \count(array_intersect($userRoles, $refreshedToken->getRoleNames()))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// @deprecated since Symfony 5.3, drop getUsername() in 6.0
|
||||
$userIdentifier = function ($refreshedUser) {
|
||||
return method_exists($refreshedUser, 'getUserIdentifier') ? $refreshedUser->getUserIdentifier() : $refreshedUser->getUsername();
|
||||
};
|
||||
if ($userIdentifier($originalUser) !== $userIdentifier($refreshedUser)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function handleUnserializeCallback(string $class)
|
||||
{
|
||||
throw new \ErrorException('Class not found: '.$class, 0x37313BC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 5.4
|
||||
*/
|
||||
public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices)
|
||||
{
|
||||
trigger_deprecation('symfony/security-http', '5.4', 'Method "%s()" is deprecated, use the new remember me handlers instead.', __METHOD__);
|
||||
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
}
|
||||
}
|
250
vendor/symfony/security-http/Firewall/ExceptionListener.php
vendored
Normal file
250
vendor/symfony/security-http/Firewall/ExceptionListener.php
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Core\Exception\AccountStatusException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\LazyResponseException;
|
||||
use Symfony\Component\Security\Core\Exception\LogoutException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
|
||||
/**
|
||||
* ExceptionListener catches authentication exception and converts them to
|
||||
* Response instances.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ExceptionListener
|
||||
{
|
||||
use TargetPathTrait;
|
||||
|
||||
private $tokenStorage;
|
||||
private $firewallName;
|
||||
private $accessDeniedHandler;
|
||||
private $authenticationEntryPoint;
|
||||
private $authenticationTrustResolver;
|
||||
private $errorPage;
|
||||
private $logger;
|
||||
private $httpUtils;
|
||||
private $stateless;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, string $firewallName, AuthenticationEntryPointInterface $authenticationEntryPoint = null, string $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null, bool $stateless = false)
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->accessDeniedHandler = $accessDeniedHandler;
|
||||
$this->httpUtils = $httpUtils;
|
||||
$this->firewallName = $firewallName;
|
||||
$this->authenticationEntryPoint = $authenticationEntryPoint;
|
||||
$this->authenticationTrustResolver = $trustResolver;
|
||||
$this->errorPage = $errorPage;
|
||||
$this->logger = $logger;
|
||||
$this->stateless = $stateless;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a onKernelException listener to take care of security exceptions.
|
||||
*/
|
||||
public function register(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$dispatcher->addListener(KernelEvents::EXCEPTION, [$this, 'onKernelException'], 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the dispatcher.
|
||||
*/
|
||||
public function unregister(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$dispatcher->removeListener(KernelEvents::EXCEPTION, [$this, 'onKernelException']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles security related exceptions.
|
||||
*/
|
||||
public function onKernelException(ExceptionEvent $event)
|
||||
{
|
||||
$exception = $event->getThrowable();
|
||||
do {
|
||||
if ($exception instanceof AuthenticationException) {
|
||||
$this->handleAuthenticationException($event, $exception);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($exception instanceof AccessDeniedException) {
|
||||
$this->handleAccessDeniedException($event, $exception);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($exception instanceof LazyResponseException) {
|
||||
$event->setResponse($exception->getResponse());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($exception instanceof LogoutException) {
|
||||
$this->handleLogoutException($event, $exception);
|
||||
|
||||
return;
|
||||
}
|
||||
} while (null !== $exception = $exception->getPrevious());
|
||||
}
|
||||
|
||||
private function handleAuthenticationException(ExceptionEvent $event, AuthenticationException $exception): void
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('An AuthenticationException was thrown; redirecting to authentication entry point.', ['exception' => $exception]);
|
||||
}
|
||||
|
||||
try {
|
||||
$event->setResponse($this->startAuthentication($event->getRequest(), $exception));
|
||||
$event->allowCustomResponseCode();
|
||||
} catch (\Exception $e) {
|
||||
$event->setThrowable($e);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleAccessDeniedException(ExceptionEvent $event, AccessDeniedException $exception)
|
||||
{
|
||||
$event->setThrowable(new AccessDeniedHttpException($exception->getMessage(), $exception));
|
||||
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if (!$this->authenticationTrustResolver->isFullFledged($token)) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', ['exception' => $exception]);
|
||||
}
|
||||
|
||||
try {
|
||||
$insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception);
|
||||
if (null !== $token) {
|
||||
$insufficientAuthenticationException->setToken($token);
|
||||
}
|
||||
|
||||
$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
|
||||
} catch (\Exception $e) {
|
||||
$event->setThrowable($e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Access denied, the user is neither anonymous, nor remember-me.', ['exception' => $exception]);
|
||||
}
|
||||
|
||||
try {
|
||||
if (null !== $this->accessDeniedHandler) {
|
||||
$response = $this->accessDeniedHandler->handle($event->getRequest(), $exception);
|
||||
|
||||
if ($response instanceof Response) {
|
||||
$event->setResponse($response);
|
||||
}
|
||||
} elseif (null !== $this->errorPage) {
|
||||
$subRequest = $this->httpUtils->createRequest($event->getRequest(), $this->errorPage);
|
||||
$subRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $exception);
|
||||
|
||||
$event->setResponse($event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true));
|
||||
$event->allowCustomResponseCode();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->error('An exception was thrown when handling an AccessDeniedException.', ['exception' => $e]);
|
||||
}
|
||||
|
||||
$event->setThrowable(new \RuntimeException('Exception thrown when handling an exception.', 0, $e));
|
||||
}
|
||||
}
|
||||
|
||||
private function handleLogoutException(ExceptionEvent $event, LogoutException $exception): void
|
||||
{
|
||||
$event->setThrowable(new AccessDeniedHttpException($exception->getMessage(), $exception));
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('A LogoutException was thrown; wrapping with AccessDeniedHttpException', ['exception' => $exception]);
|
||||
}
|
||||
}
|
||||
|
||||
private function startAuthentication(Request $request, AuthenticationException $authException): Response
|
||||
{
|
||||
if (null === $this->authenticationEntryPoint) {
|
||||
$this->throwUnauthorizedException($authException);
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Calling Authentication entry point.');
|
||||
}
|
||||
|
||||
if (!$this->stateless) {
|
||||
$this->setTargetPath($request);
|
||||
}
|
||||
|
||||
if ($authException instanceof AccountStatusException) {
|
||||
// remove the security token to prevent infinite redirect loops
|
||||
$this->tokenStorage->setToken(null);
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('The security token was removed due to an AccountStatusException.', ['exception' => $authException]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->authenticationEntryPoint->start($request, $authException);
|
||||
} catch (NotAnEntryPointException $e) {
|
||||
$this->throwUnauthorizedException($authException);
|
||||
}
|
||||
|
||||
if (!$response instanceof Response) {
|
||||
$given = get_debug_type($response);
|
||||
|
||||
throw new \LogicException(sprintf('The "%s::start()" method must return a Response object ("%s" returned).', get_debug_type($this->authenticationEntryPoint), $given));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function setTargetPath(Request $request)
|
||||
{
|
||||
// session isn't required when using HTTP basic authentication mechanism for example
|
||||
if ($request->hasSession() && $request->isMethodSafe() && !$request->isXmlHttpRequest()) {
|
||||
$this->saveTargetPath($request->getSession(), $this->firewallName, $request->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
private function throwUnauthorizedException(AuthenticationException $authException)
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->notice(sprintf('No Authentication entry point configured, returning a %s HTTP response. Configure "entry_point" on the firewall "%s" if you want to modify the response.', Response::HTTP_UNAUTHORIZED, $this->firewallName));
|
||||
}
|
||||
|
||||
throw new HttpException(Response::HTTP_UNAUTHORIZED, $authException->getMessage(), $authException, [], $authException->getCode());
|
||||
}
|
||||
}
|
43
vendor/symfony/security-http/Firewall/FirewallListenerInterface.php
vendored
Normal file
43
vendor/symfony/security-http/Firewall/FirewallListenerInterface.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
|
||||
/**
|
||||
* Can be implemented by firewall listeners.
|
||||
*
|
||||
* @author Christian Scheb <me@christianscheb.de>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
interface FirewallListenerInterface
|
||||
{
|
||||
/**
|
||||
* Tells whether the authenticate() method should be called or not depending on the incoming request.
|
||||
*
|
||||
* Returning null means authenticate() can be called lazily when accessing the token storage.
|
||||
*/
|
||||
public function supports(Request $request): ?bool;
|
||||
|
||||
/**
|
||||
* Does whatever is required to authenticate the request, typically calling $event->setResponse() internally.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event);
|
||||
|
||||
/**
|
||||
* Defines the priority of the listener.
|
||||
* The higher the number, the earlier a listener is executed.
|
||||
*/
|
||||
public static function getPriority(): int;
|
||||
}
|
150
vendor/symfony/security-http/Firewall/LogoutListener.php
vendored
Normal file
150
vendor/symfony/security-http/Firewall/LogoutListener.php
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Exception\LogicException;
|
||||
use Symfony\Component\Security\Core\Exception\LogoutException;
|
||||
use Symfony\Component\Security\Csrf\CsrfToken;
|
||||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
|
||||
use Symfony\Component\Security\Http\Event\LogoutEvent;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\ParameterBagUtils;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* LogoutListener logout users.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class LogoutListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $options;
|
||||
private $httpUtils;
|
||||
private $csrfTokenManager;
|
||||
private $eventDispatcher;
|
||||
|
||||
/**
|
||||
* @param EventDispatcherInterface $eventDispatcher
|
||||
* @param array $options An array of options to process a logout attempt
|
||||
*/
|
||||
public function __construct(TokenStorageInterface $tokenStorage, HttpUtils $httpUtils, $eventDispatcher, array $options = [], CsrfTokenManagerInterface $csrfTokenManager = null)
|
||||
{
|
||||
if (!$eventDispatcher instanceof EventDispatcherInterface) {
|
||||
trigger_deprecation('symfony/security-http', '5.1', 'Passing a logout success handler to "%s" is deprecated, pass an instance of "%s" instead.', __METHOD__, EventDispatcherInterface::class);
|
||||
|
||||
if (!$eventDispatcher instanceof LogoutSuccessHandlerInterface) {
|
||||
throw new \TypeError(sprintf('Argument 3 of "%s" must be instance of "%s" or "%s", "%s" given.', __METHOD__, EventDispatcherInterface::class, LogoutSuccessHandlerInterface::class, get_debug_type($eventDispatcher)));
|
||||
}
|
||||
|
||||
$successHandler = $eventDispatcher;
|
||||
$eventDispatcher = new EventDispatcher();
|
||||
$eventDispatcher->addListener(LogoutEvent::class, function (LogoutEvent $event) use ($successHandler) {
|
||||
$event->setResponse($r = $successHandler->onLogoutSuccess($event->getRequest()));
|
||||
});
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->httpUtils = $httpUtils;
|
||||
$this->options = array_merge([
|
||||
'csrf_parameter' => '_csrf_token',
|
||||
'csrf_token_id' => 'logout',
|
||||
'logout_path' => '/logout',
|
||||
], $options);
|
||||
$this->csrfTokenManager = $csrfTokenManager;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 5.1
|
||||
*/
|
||||
public function addHandler(LogoutHandlerInterface $handler)
|
||||
{
|
||||
trigger_deprecation('symfony/security-http', '5.1', 'Calling "%s" is deprecated, register a listener on the "%s" event instead.', __METHOD__, LogoutEvent::class);
|
||||
|
||||
$this->eventDispatcher->addListener(LogoutEvent::class, function (LogoutEvent $event) use ($handler) {
|
||||
if (null === $event->getResponse()) {
|
||||
throw new LogicException(sprintf('No response was set for this logout action. Make sure the DefaultLogoutListener or another listener has set the response before "%s" is called.', __CLASS__));
|
||||
}
|
||||
|
||||
$handler->logout($event->getRequest(), $event->getResponse(), $event->getToken());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return $this->requiresLogout($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logout if requested.
|
||||
*
|
||||
* If a CsrfTokenManagerInterface instance is available, it will be used to
|
||||
* validate the request.
|
||||
*
|
||||
* @throws LogoutException if the CSRF token is invalid
|
||||
* @throws \RuntimeException if the LogoutSuccessHandlerInterface instance does not return a response
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (null !== $this->csrfTokenManager) {
|
||||
$csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);
|
||||
|
||||
if (!\is_string($csrfToken) || false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) {
|
||||
throw new LogoutException('Invalid CSRF token.');
|
||||
}
|
||||
}
|
||||
|
||||
$logoutEvent = new LogoutEvent($request, $this->tokenStorage->getToken());
|
||||
$this->eventDispatcher->dispatch($logoutEvent);
|
||||
|
||||
$response = $logoutEvent->getResponse();
|
||||
if (!$response instanceof Response) {
|
||||
throw new \RuntimeException('No logout listener set the Response, make sure at least the DefaultLogoutListener is registered.');
|
||||
}
|
||||
|
||||
$this->tokenStorage->setToken(null);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this request is asking for logout.
|
||||
*
|
||||
* The default implementation only processed requests to a specific path,
|
||||
* but a subclass could change this to logout requests where
|
||||
* certain parameters is present.
|
||||
*/
|
||||
protected function requiresLogout(Request $request): bool
|
||||
{
|
||||
return isset($this->options['logout_path']) && $this->httpUtils->checkRequestPath($request, $this->options['logout_path']);
|
||||
}
|
||||
|
||||
public static function getPriority(): int
|
||||
{
|
||||
return -127;
|
||||
}
|
||||
}
|
130
vendor/symfony/security-http/Firewall/RememberMeListener.php
vendored
Normal file
130
vendor/symfony/security-http/Firewall/RememberMeListener.php
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', RememberMeListener::class);
|
||||
|
||||
/**
|
||||
* RememberMeListener implements authentication capabilities via a cookie.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class RememberMeListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $rememberMeServices;
|
||||
private $authenticationManager;
|
||||
private $logger;
|
||||
private $dispatcher;
|
||||
private $catchExceptions = true;
|
||||
private $sessionStrategy;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, bool $catchExceptions = true, SessionAuthenticationStrategyInterface $sessionStrategy = null)
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->logger = $logger;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->catchExceptions = $catchExceptions;
|
||||
$this->sessionStrategy = $sessionStrategy ?? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
return null; // always run authenticate() lazily with lazy firewalls
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles remember-me cookie based authentication.
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
if (null !== $this->tokenStorage->getToken()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
try {
|
||||
if (null === $token = $this->rememberMeServices->autoLogin($request)) {
|
||||
return;
|
||||
}
|
||||
} catch (AuthenticationException $e) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning(
|
||||
'The token storage was not populated with remember-me token as the'
|
||||
.' RememberMeServices was not able to create a token from the remember'
|
||||
.' me information.', ['exception' => $e]
|
||||
);
|
||||
}
|
||||
|
||||
$this->rememberMeServices->loginFail($request);
|
||||
|
||||
if (!$this->catchExceptions) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$token = $this->authenticationManager->authenticate($token);
|
||||
if ($request->hasSession() && $request->getSession()->isStarted()) {
|
||||
$this->sessionStrategy->onAuthentication($request, $token);
|
||||
}
|
||||
$this->tokenStorage->setToken($token);
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$loginEvent = new InteractiveLoginEvent($request, $token);
|
||||
$this->dispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Populated the token storage with a remember-me token.');
|
||||
}
|
||||
} catch (AuthenticationException $e) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning(
|
||||
'The token storage was not populated with remember-me token as the'
|
||||
.' AuthenticationManager rejected the AuthenticationToken returned'
|
||||
.' by the RememberMeServices.', ['exception' => $e]
|
||||
);
|
||||
}
|
||||
|
||||
$this->rememberMeServices->loginFail($request, $e);
|
||||
|
||||
if (!$this->catchExceptions) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
vendor/symfony/security-http/Firewall/RemoteUserAuthenticationListener.php
vendored
Normal file
53
vendor/symfony/security-http/Firewall/RemoteUserAuthenticationListener.php
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', RemoteUserAuthenticationListener::class);
|
||||
|
||||
/**
|
||||
* REMOTE_USER authentication listener.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Maxime Douailin <maxime.douailin@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class RemoteUserAuthenticationListener extends AbstractPreAuthenticatedListener
|
||||
{
|
||||
private $userKey;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, string $providerKey, string $userKey = 'REMOTE_USER', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
parent::__construct($tokenStorage, $authenticationManager, $providerKey, $logger, $dispatcher);
|
||||
|
||||
$this->userKey = $userKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getPreAuthenticatedData(Request $request)
|
||||
{
|
||||
if (!$request->server->has($this->userKey)) {
|
||||
throw new BadCredentialsException(sprintf('User key was not found: "%s".', $this->userKey));
|
||||
}
|
||||
|
||||
return [$request->server->get($this->userKey), null];
|
||||
}
|
||||
}
|
235
vendor/symfony/security-http/Firewall/SwitchUserListener.php
vendored
Normal file
235
vendor/symfony/security-http/Firewall/SwitchUserListener.php
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* SwitchUserListener allows a user to impersonate another one temporarily
|
||||
* (like the Unix su command).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class SwitchUserListener extends AbstractListener
|
||||
{
|
||||
public const EXIT_VALUE = '_exit';
|
||||
|
||||
private $tokenStorage;
|
||||
private $provider;
|
||||
private $userChecker;
|
||||
private $firewallName;
|
||||
private $accessDecisionManager;
|
||||
private $usernameParameter;
|
||||
private $role;
|
||||
private $logger;
|
||||
private $dispatcher;
|
||||
private $stateless;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, string $firewallName, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, string $usernameParameter = '_switch_user', string $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null, bool $stateless = false)
|
||||
{
|
||||
if ('' === $firewallName) {
|
||||
throw new \InvalidArgumentException('$firewallName must not be empty.');
|
||||
}
|
||||
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->provider = $provider;
|
||||
$this->userChecker = $userChecker;
|
||||
$this->firewallName = $firewallName;
|
||||
$this->accessDecisionManager = $accessDecisionManager;
|
||||
$this->usernameParameter = $usernameParameter;
|
||||
$this->role = $role;
|
||||
$this->logger = $logger;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->stateless = $stateless;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
// usernames can be falsy
|
||||
$username = $request->get($this->usernameParameter);
|
||||
|
||||
if (null === $username || '' === $username) {
|
||||
$username = $request->headers->get($this->usernameParameter);
|
||||
}
|
||||
|
||||
// if it's still "empty", nothing to do.
|
||||
if (null === $username || '' === $username) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request->attributes->set('_switch_user_username', $username);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the switch to another user.
|
||||
*
|
||||
* @throws \LogicException if switching to a user failed
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$username = $request->attributes->get('_switch_user_username');
|
||||
$request->attributes->remove('_switch_user_username');
|
||||
|
||||
if (null === $this->tokenStorage->getToken()) {
|
||||
throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.');
|
||||
}
|
||||
|
||||
if (self::EXIT_VALUE === $username) {
|
||||
$this->tokenStorage->setToken($this->attemptExitUser($request));
|
||||
} else {
|
||||
try {
|
||||
$this->tokenStorage->setToken($this->attemptSwitchUser($request, $username));
|
||||
} catch (AuthenticationException $e) {
|
||||
// Generate 403 in any conditions to prevent user enumeration vulnerabilities
|
||||
throw new AccessDeniedException('Switch User failed: '.$e->getMessage(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->stateless) {
|
||||
$request->query->remove($this->usernameParameter);
|
||||
$request->server->set('QUERY_STRING', http_build_query($request->query->all(), '', '&'));
|
||||
$response = new RedirectResponse($request->getUri(), 302);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to switch to another user and returns the new token if successfully switched.
|
||||
*
|
||||
* @throws \LogicException
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
private function attemptSwitchUser(Request $request, string $username): ?TokenInterface
|
||||
{
|
||||
$token = $this->tokenStorage->getToken();
|
||||
$originalToken = $this->getOriginalToken($token);
|
||||
|
||||
if (null !== $originalToken) {
|
||||
// @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
|
||||
if ((method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()) === $username) {
|
||||
return $token;
|
||||
}
|
||||
|
||||
// User already switched, exit before seamlessly switching to another user
|
||||
$token = $this->attemptExitUser($request);
|
||||
}
|
||||
|
||||
// @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
|
||||
$currentUsername = method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername();
|
||||
$nonExistentUsername = '_'.md5(random_bytes(8).$username);
|
||||
|
||||
// To protect against user enumeration via timing measurements
|
||||
// we always load both successfully and unsuccessfully
|
||||
$methodName = 'loadUserByIdentifier';
|
||||
if (!method_exists($this->provider, $methodName)) {
|
||||
trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "loadUserByIdentifier()" in user provider "%s" is deprecated. This method will replace "loadUserByUsername()" in Symfony 6.0.', get_debug_type($this->provider));
|
||||
|
||||
$methodName = 'loadUserByUsername';
|
||||
}
|
||||
try {
|
||||
$user = $this->provider->$methodName($username);
|
||||
|
||||
try {
|
||||
$this->provider->$methodName($nonExistentUsername);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
} catch (AuthenticationException $e) {
|
||||
$this->provider->$methodName($currentUsername);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (false === $this->accessDecisionManager->decide($token, [$this->role], $user)) {
|
||||
$exception = new AccessDeniedException();
|
||||
$exception->setAttributes($this->role);
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Attempting to switch to user.', ['username' => $username]);
|
||||
}
|
||||
|
||||
$this->userChecker->checkPostAuth($user);
|
||||
|
||||
$roles = $user->getRoles();
|
||||
$roles[] = 'ROLE_PREVIOUS_ADMIN';
|
||||
$originatedFromUri = str_replace('/&', '/?', preg_replace('#[&?]'.$this->usernameParameter.'=[^&]*#', '', $request->getRequestUri()));
|
||||
$token = new SwitchUserToken($user, $this->firewallName, $roles, $token, $originatedFromUri);
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$switchEvent = new SwitchUserEvent($request, $token->getUser(), $token);
|
||||
$this->dispatcher->dispatch($switchEvent, SecurityEvents::SWITCH_USER);
|
||||
// use the token from the event in case any listeners have replaced it.
|
||||
$token = $switchEvent->getToken();
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to exit from an already switched user and returns the original token.
|
||||
*
|
||||
* @throws AuthenticationCredentialsNotFoundException
|
||||
*/
|
||||
private function attemptExitUser(Request $request): TokenInterface
|
||||
{
|
||||
if (null === ($currentToken = $this->tokenStorage->getToken()) || null === $original = $this->getOriginalToken($currentToken)) {
|
||||
throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.');
|
||||
}
|
||||
|
||||
if (null !== $this->dispatcher && $original->getUser() instanceof UserInterface) {
|
||||
$user = $this->provider->refreshUser($original->getUser());
|
||||
$original->setUser($user);
|
||||
$switchEvent = new SwitchUserEvent($request, $user, $original);
|
||||
$this->dispatcher->dispatch($switchEvent, SecurityEvents::SWITCH_USER);
|
||||
$original = $switchEvent->getToken();
|
||||
}
|
||||
|
||||
return $original;
|
||||
}
|
||||
|
||||
private function getOriginalToken(TokenInterface $token): ?TokenInterface
|
||||
{
|
||||
if ($token instanceof SwitchUserToken) {
|
||||
return $token->getOriginalToken();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
110
vendor/symfony/security-http/Firewall/UsernamePasswordFormAuthenticationListener.php
vendored
Normal file
110
vendor/symfony/security-http/Firewall/UsernamePasswordFormAuthenticationListener.php
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Csrf\CsrfToken;
|
||||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\ParameterBagUtils;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', UsernamePasswordFormAuthenticationListener::class);
|
||||
|
||||
/**
|
||||
* UsernamePasswordFormAuthenticationListener is the default implementation of
|
||||
* an authentication via a simple form composed of a username and a password.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
|
||||
{
|
||||
private $csrfTokenManager;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, string $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = [], LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null)
|
||||
{
|
||||
parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge([
|
||||
'username_parameter' => '_username',
|
||||
'password_parameter' => '_password',
|
||||
'csrf_parameter' => '_csrf_token',
|
||||
'csrf_token_id' => 'authenticate',
|
||||
'post_only' => true,
|
||||
], $options), $logger, $dispatcher);
|
||||
|
||||
$this->csrfTokenManager = $csrfTokenManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function requiresAuthentication(Request $request)
|
||||
{
|
||||
if ($this->options['post_only'] && !$request->isMethod('POST')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::requiresAuthentication($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function attemptAuthentication(Request $request)
|
||||
{
|
||||
if (null !== $this->csrfTokenManager) {
|
||||
$csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);
|
||||
|
||||
if (!\is_string($csrfToken) || false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) {
|
||||
throw new InvalidCsrfTokenException('Invalid CSRF token.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->options['post_only']) {
|
||||
$username = ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter']);
|
||||
$password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']);
|
||||
} else {
|
||||
$username = ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter']);
|
||||
$password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
|
||||
}
|
||||
|
||||
if (!\is_string($username) && (!\is_object($username) || !method_exists($username, '__toString'))) {
|
||||
throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], get_debug_type($username)));
|
||||
}
|
||||
|
||||
$username = trim($username);
|
||||
|
||||
if (\strlen($username) > Security::MAX_USERNAME_LENGTH) {
|
||||
throw new BadCredentialsException('Invalid username.');
|
||||
}
|
||||
|
||||
if (null === $password) {
|
||||
throw new \LogicException(sprintf('The key "%s" cannot be null; check that the password field name of the form matches.', $this->options['password_parameter']));
|
||||
}
|
||||
|
||||
$request->getSession()->set(Security::LAST_USERNAME, $username);
|
||||
|
||||
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
|
||||
}
|
||||
}
|
235
vendor/symfony/security-http/Firewall/UsernamePasswordJsonAuthenticationListener.php
vendored
Normal file
235
vendor/symfony/security-http/Firewall/UsernamePasswordJsonAuthenticationListener.php
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\PropertyAccess\Exception\AccessException;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', UsernamePasswordJsonAuthenticationListener::class);
|
||||
|
||||
/**
|
||||
* UsernamePasswordJsonAuthenticationListener is a stateless implementation of
|
||||
* an authentication via a JSON document composed of a username and a password.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class UsernamePasswordJsonAuthenticationListener extends AbstractListener
|
||||
{
|
||||
private $tokenStorage;
|
||||
private $authenticationManager;
|
||||
private $httpUtils;
|
||||
private $providerKey;
|
||||
private $successHandler;
|
||||
private $failureHandler;
|
||||
private $options;
|
||||
private $logger;
|
||||
private $eventDispatcher;
|
||||
private $propertyAccessor;
|
||||
private $sessionStrategy;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface|null
|
||||
*/
|
||||
private $translator;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, HttpUtils $httpUtils, string $providerKey, AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, array $options = [], LoggerInterface $logger = null, EventDispatcherInterface $eventDispatcher = null, PropertyAccessorInterface $propertyAccessor = null)
|
||||
{
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->httpUtils = $httpUtils;
|
||||
$this->providerKey = $providerKey;
|
||||
$this->successHandler = $successHandler;
|
||||
$this->failureHandler = $failureHandler;
|
||||
$this->logger = $logger;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->options = array_merge(['username_path' => 'username', 'password_path' => 'password'], $options);
|
||||
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
if (!str_contains($request->getRequestFormat() ?? '', 'json')
|
||||
&& !str_contains($request->getContentType() ?? '', 'json')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($this->options['check_path']) && !$this->httpUtils->checkRequestPath($request, $this->options['check_path'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$data = json_decode($request->getContent());
|
||||
|
||||
try {
|
||||
if (!$data instanceof \stdClass) {
|
||||
throw new BadRequestHttpException('Invalid JSON.');
|
||||
}
|
||||
|
||||
try {
|
||||
$username = $this->propertyAccessor->getValue($data, $this->options['username_path']);
|
||||
} catch (AccessException $e) {
|
||||
throw new BadRequestHttpException(sprintf('The key "%s" must be provided.', $this->options['username_path']), $e);
|
||||
}
|
||||
|
||||
try {
|
||||
$password = $this->propertyAccessor->getValue($data, $this->options['password_path']);
|
||||
} catch (AccessException $e) {
|
||||
throw new BadRequestHttpException(sprintf('The key "%s" must be provided.', $this->options['password_path']), $e);
|
||||
}
|
||||
|
||||
if (!\is_string($username)) {
|
||||
throw new BadRequestHttpException(sprintf('The key "%s" must be a string.', $this->options['username_path']));
|
||||
}
|
||||
|
||||
if (\strlen($username) > Security::MAX_USERNAME_LENGTH) {
|
||||
throw new BadCredentialsException('Invalid username.');
|
||||
}
|
||||
|
||||
if (!\is_string($password)) {
|
||||
throw new BadRequestHttpException(sprintf('The key "%s" must be a string.', $this->options['password_path']));
|
||||
}
|
||||
|
||||
$token = new UsernamePasswordToken($username, $password, $this->providerKey);
|
||||
|
||||
$authenticatedToken = $this->authenticationManager->authenticate($token);
|
||||
$response = $this->onSuccess($request, $authenticatedToken);
|
||||
} catch (AuthenticationException $e) {
|
||||
$response = $this->onFailure($request, $e);
|
||||
} catch (BadRequestHttpException $e) {
|
||||
$request->setRequestFormat('json');
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (null === $response) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
private function onSuccess(Request $request, TokenInterface $token): ?Response
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
// @deprecated since Symfony 5.3, change to $token->getUserIdentifier() in 6.0
|
||||
$this->logger->info('User has been authenticated successfully.', ['username' => method_exists($token, 'getUserIdentifier') ? $token->getUserIdentifier() : $token->getUsername()]);
|
||||
}
|
||||
|
||||
$this->migrateSession($request, $token);
|
||||
|
||||
$this->tokenStorage->setToken($token);
|
||||
|
||||
if (null !== $this->eventDispatcher) {
|
||||
$loginEvent = new InteractiveLoginEvent($request, $token);
|
||||
$this->eventDispatcher->dispatch($loginEvent, SecurityEvents::INTERACTIVE_LOGIN);
|
||||
}
|
||||
|
||||
if (!$this->successHandler) {
|
||||
return null; // let the original request succeeds
|
||||
}
|
||||
|
||||
$response = $this->successHandler->onAuthenticationSuccess($request, $token);
|
||||
|
||||
if (!$response instanceof Response) {
|
||||
throw new \RuntimeException('Authentication Success Handler did not return a Response.');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function onFailure(Request $request, AuthenticationException $failed): Response
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->info('Authentication request failed.', ['exception' => $failed]);
|
||||
}
|
||||
|
||||
$token = $this->tokenStorage->getToken();
|
||||
if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getFirewallName()) {
|
||||
$this->tokenStorage->setToken(null);
|
||||
}
|
||||
|
||||
if (!$this->failureHandler) {
|
||||
if (null !== $this->translator) {
|
||||
$errorMessage = $this->translator->trans($failed->getMessageKey(), $failed->getMessageData(), 'security');
|
||||
} else {
|
||||
$errorMessage = strtr($failed->getMessageKey(), $failed->getMessageData());
|
||||
}
|
||||
|
||||
return new JsonResponse(['error' => $errorMessage], 401);
|
||||
}
|
||||
|
||||
$response = $this->failureHandler->onAuthenticationFailure($request, $failed);
|
||||
|
||||
if (!$response instanceof Response) {
|
||||
throw new \RuntimeException('Authentication Failure Handler did not return a Response.');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method if your authentication token is stored to a session.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyInterface $sessionStrategy)
|
||||
{
|
||||
$this->sessionStrategy = $sessionStrategy;
|
||||
}
|
||||
|
||||
public function setTranslator(TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
private function migrateSession(Request $request, TokenInterface $token)
|
||||
{
|
||||
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sessionStrategy->onAuthentication($request, $token);
|
||||
}
|
||||
}
|
64
vendor/symfony/security-http/Firewall/X509AuthenticationListener.php
vendored
Normal file
64
vendor/symfony/security-http/Firewall/X509AuthenticationListener.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Firewall;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
trigger_deprecation('symfony/security-http', '5.3', 'The "%s" class is deprecated, use the new authenticator system instead.', X509AuthenticationListener::class);
|
||||
|
||||
/**
|
||||
* X509 authentication listener.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.3, use the new authenticator system instead
|
||||
*/
|
||||
class X509AuthenticationListener extends AbstractPreAuthenticatedListener
|
||||
{
|
||||
private $userKey;
|
||||
private $credentialKey;
|
||||
|
||||
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, string $providerKey, string $userKey = 'SSL_CLIENT_S_DN_Email', string $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
parent::__construct($tokenStorage, $authenticationManager, $providerKey, $logger, $dispatcher);
|
||||
|
||||
$this->userKey = $userKey;
|
||||
$this->credentialKey = $credentialKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getPreAuthenticatedData(Request $request)
|
||||
{
|
||||
$user = null;
|
||||
if ($request->server->has($this->userKey)) {
|
||||
$user = $request->server->get($this->userKey);
|
||||
} elseif (
|
||||
$request->server->has($this->credentialKey)
|
||||
&& preg_match('#emailAddress=([^,/@]++@[^,/]++)#', $request->server->get($this->credentialKey), $matches)
|
||||
) {
|
||||
$user = $matches[1];
|
||||
}
|
||||
|
||||
if (null === $user) {
|
||||
throw new BadCredentialsException(sprintf('SSL credentials not found: "%s", "%s".', $this->userKey, $this->credentialKey));
|
||||
}
|
||||
|
||||
return [$user, $request->server->get($this->credentialKey, '')];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user