Вход Регистрация
Файл: symfony-2.7/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php
Строк: 540
<?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 SymfonyComponentSecurityHttpFirewall;

use 
SymfonyComponentSecurityHttpSessionSessionAuthenticationStrategyInterface;
use 
SymfonyComponentSecurityHttpAuthenticationAuthenticationFailureHandlerInterface;
use 
SymfonyComponentSecurityHttpAuthenticationAuthenticationSuccessHandlerInterface;
use 
SymfonyComponentSecurityHttpRememberMeRememberMeServicesInterface;
use 
SymfonyComponentSecurityCoreSecurity;
use 
SymfonyComponentSecurityCoreAuthenticationAuthenticationManagerInterface;
use 
SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorageInterface;
use 
SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
use 
SymfonyComponentSecurityCoreExceptionAuthenticationException;
use 
SymfonyComponentSecurityCoreExceptionSessionUnavailableException;
use 
PsrLogLoggerInterface;
use 
SymfonyComponentHttpKernelEventGetResponseEvent;
use 
SymfonyComponentHttpFoundationRequest;
use 
SymfonyComponentHttpFoundationResponse;
use 
SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use 
SymfonyComponentEventDispatcherEventDispatcherInterface;
use 
SymfonyComponentSecurityHttpEventInteractiveLoginEvent;
use 
SymfonyComponentSecurityHttpSecurityEvents;
use 
SymfonyComponentSecurityHttpHttpUtils;

/**
 * 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>
 */
abstract class AbstractAuthenticationListener implements ListenerInterface
{
    protected 
$options;
    protected 
$logger;
    protected 
$authenticationManager;
    protected 
$providerKey;
    protected 
$httpUtils;

    private 
$tokenStorage;
    private 
$sessionStrategy;
    private 
$dispatcher;
    private 
$successHandler;
    private 
$failureHandler;
    private 
$rememberMeServices;

    
/**
     * Constructor.
     *
     * @param TokenStorageInterface                  $tokenStorage          A TokenStorageInterface instance
     * @param AuthenticationManagerInterface         $authenticationManager An AuthenticationManagerInterface instance
     * @param SessionAuthenticationStrategyInterface $sessionStrategy
     * @param HttpUtils                              $httpUtils             An HttpUtilsInterface instance
     * @param string                                 $providerKey
     * @param AuthenticationSuccessHandlerInterface  $successHandler
     * @param AuthenticationFailureHandlerInterface  $failureHandler
     * @param array                                  $options               An array of options for the processing of a
     *                                                                      successful, or failed authentication attempt
     * @param LoggerInterface                        $logger                A LoggerInterface instance
     * @param EventDispatcherInterface               $dispatcher            An EventDispatcherInterface instance
     *
     * @throws InvalidArgumentException
     */
    
public function __construct(TokenStorageInterface $tokenStorageAuthenticationManagerInterface $authenticationManagerSessionAuthenticationStrategyInterface $sessionStrategyHttpUtils $httpUtils$providerKeyAuthenticationSuccessHandlerInterface $successHandlerAuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger nullEventDispatcherInterface $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(array(
            
'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.
     *
     * @param RememberMeServicesInterface $rememberMeServices
     */
    
public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices)
    {
        
$this->rememberMeServices $rememberMeServices;
    }

    
/**
     * Handles form based authentication.
     *
     * @param GetResponseEvent $event A GetResponseEvent instance
     *
     * @throws RuntimeException
     * @throws SessionUnavailableException
     */
    
final public function handle(GetResponseEvent $event)
    {
        
$request $event->getRequest();

        if (!
$this->requiresAuthentication($request)) {
            return;
        }

        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.
     *
     * @param Request $request
     *
     * @return bool
     */
    
protected function requiresAuthentication(Request $request)
    {
        return 
$this->httpUtils->checkRequestPath($request$this->options['check_path']);
    }

    
/**
     * Performs authentication.
     *
     * @param Request $request A Request instance
     *
     * @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 $requestAuthenticationException $failed)
    {
        if (
null !== $this->logger) {
            
$this->logger->info('Authentication request failed.', array('exception' => $failed));
        }

        
$token $this->tokenStorage->getToken();
        if (
$token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) {
            
$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 $requestTokenInterface $token)
    {
        if (
null !== $this->logger) {
            
$this->logger->info('User has been authenticated successfully.', array('username' => $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(SecurityEvents::INTERACTIVE_LOGIN$loginEvent);
        }

        
$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;
    }
}
Онлайн: 0
Реклама