Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
<?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\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
use Symfony\Component\Security\Core\Security;
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\AuthenticationException;
use Symfony\Component\Security\Core\Exception\SessionUnavailableException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\Security\Http\HttpUtils;
/**
* 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 HttpUtils 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|null $logger A LoggerInterface instance
* @param EventDispatcherInterface|null $dispatcher An EventDispatcherInterface instance
*
* @throws \InvalidArgumentException
*/
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), 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(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 $request, AuthenticationException $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 $request, TokenInterface $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;
}
}

View File

@@ -0,0 +1,123 @@
<?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\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\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
/**
* 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>
*/
abstract class AbstractPreAuthenticatedListener implements ListenerInterface
{
protected $logger;
private $tokenStorage;
private $authenticationManager;
private $providerKey;
private $dispatcher;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
{
$this->tokenStorage = $tokenStorage;
$this->authenticationManager = $authenticationManager;
$this->providerKey = $providerKey;
$this->logger = $logger;
$this->dispatcher = $dispatcher;
}
/**
* Handles pre-authentication.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
final public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
try {
list($user, $credentials) = $this->getPreAuthenticatedData($request);
} catch (BadCredentialsException $e) {
$this->clearToken($e);
return;
}
if (null !== $this->logger) {
$this->logger->debug('Checking current security token.', array('token' => (string) $this->tokenStorage->getToken()));
}
if (null !== $token = $this->tokenStorage->getToken()) {
if ($token instanceof PreAuthenticatedToken && $this->providerKey == $token->getProviderKey() && $token->isAuthenticated() && $token->getUsername() === $user) {
return;
}
}
if (null !== $this->logger) {
$this->logger->debug('Trying to pre-authenticate user.', array('username' => (string) $user));
}
try {
$token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials, $this->providerKey));
if (null !== $this->logger) {
$this->logger->info('Pre-authentication successful.', array('token' => (string) $token));
}
$this->tokenStorage->setToken($token);
if (null !== $this->dispatcher) {
$loginEvent = new InteractiveLoginEvent($request, $token);
$this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent);
}
} catch (AuthenticationException $e) {
$this->clearToken($e);
}
}
/**
* Clears a PreAuthenticatedToken for this provider (if present).
*
* @param AuthenticationException $exception
*/
private function clearToken(AuthenticationException $exception)
{
$token = $this->tokenStorage->getToken();
if ($token instanceof PreAuthenticatedToken && $this->providerKey === $token->getProviderKey()) {
$this->tokenStorage->setToken(null);
if (null !== $this->logger) {
$this->logger->info('Cleared security token due to an exception.', array('exception' => $exception));
}
}
}
/**
* Gets the user and credentials from the Request.
*
* @param Request $request A Request instance
*
* @return array An array composed of the user and the credentials
*/
abstract protected function getPreAuthenticatedData(Request $request);
}

View File

@@ -0,0 +1,77 @@
<?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\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* AccessListener enforces access control rules.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AccessListener implements ListenerInterface
{
private $tokenStorage;
private $accessDecisionManager;
private $map;
private $authManager;
public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager)
{
$this->tokenStorage = $tokenStorage;
$this->accessDecisionManager = $accessDecisionManager;
$this->map = $map;
$this->authManager = $authManager;
}
/**
* Handles access authorization.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*
* @throws AccessDeniedException
* @throws AuthenticationCredentialsNotFoundException
*/
public function handle(GetResponseEvent $event)
{
if (null === $token = $this->tokenStorage->getToken()) {
throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.');
}
$request = $event->getRequest();
list($attributes) = $this->map->getPatterns($request);
if (null === $attributes) {
return;
}
if (!$token->isAuthenticated()) {
$token = $this->authManager->authenticate($token);
$this->tokenStorage->setToken($token);
}
if (!$this->accessDecisionManager->decide($token, $attributes, $request)) {
$exception = new AccessDeniedException();
$exception->setAttributes($attributes);
$exception->setSubject($request);
throw $exception;
}
}
}

View File

@@ -0,0 +1,70 @@
<?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\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
/**
* AnonymousAuthenticationListener automatically adds a Token if none is
* already present.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AnonymousAuthenticationListener implements ListenerInterface
{
private $tokenStorage;
private $secret;
private $authenticationManager;
private $logger;
public function __construct(TokenStorageInterface $tokenStorage, $secret, LoggerInterface $logger = null, AuthenticationManagerInterface $authenticationManager = null)
{
$this->tokenStorage = $tokenStorage;
$this->secret = $secret;
$this->authenticationManager = $authenticationManager;
$this->logger = $logger;
}
/**
* Handles anonymous authentication.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
public function handle(GetResponseEvent $event)
{
if (null !== $this->tokenStorage->getToken()) {
return;
}
try {
$token = new AnonymousToken($this->secret, 'anon.', array());
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.', array('exception' => $failed));
}
}
}
}

View File

@@ -0,0 +1,93 @@
<?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\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
/**
* BasicAuthenticationListener implements Basic HTTP authentication.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class BasicAuthenticationListener implements ListenerInterface
{
private $tokenStorage;
private $authenticationManager;
private $providerKey;
private $authenticationEntryPoint;
private $logger;
private $ignoreFailure;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $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;
}
/**
* Handles basic authentication.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (null === $username = $request->headers->get('PHP_AUTH_USER')) {
return;
}
if (null !== $token = $this->tokenStorage->getToken()) {
if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $username) {
return;
}
}
if (null !== $this->logger) {
$this->logger->info('Basic authentication Authorization header found for user.', array('username' => $username));
}
try {
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey));
$this->tokenStorage->setToken($token);
} catch (AuthenticationException $e) {
$token = $this->tokenStorage->getToken();
if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) {
$this->tokenStorage->setToken(null);
}
if (null !== $this->logger) {
$this->logger->info('Basic authentication failed for user.', array('username' => $username, 'exception' => $e));
}
if ($this->ignoreFailure) {
return;
}
$event->setResponse($this->authenticationEntryPoint->start($request, $e));
}
}
}

View File

@@ -0,0 +1,71 @@
<?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\Security\Http\AccessMapInterface;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
/**
* ChannelListener switches the HTTP protocol based on the access control
* configuration.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ChannelListener implements ListenerInterface
{
private $map;
private $authenticationEntryPoint;
private $logger;
public function __construct(AccessMapInterface $map, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null)
{
$this->map = $map;
$this->authenticationEntryPoint = $authenticationEntryPoint;
$this->logger = $logger;
}
/**
* Handles channel management.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
list(, $channel) = $this->map->getPatterns($request);
if ('https' === $channel && !$request->isSecure()) {
if (null !== $this->logger) {
$this->logger->info('Redirecting to HTTPS.');
}
$response = $this->authenticationEntryPoint->start($request);
$event->setResponse($response);
return;
}
if ('http' === $channel && $request->isSecure()) {
if (null !== $this->logger) {
$this->logger->info('Redirecting to HTTP.');
}
$response = $this->authenticationEntryPoint->start($request);
$event->setResponse($response);
}
}
}

View File

@@ -0,0 +1,187 @@
<?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\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
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\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\TokenInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* ContextListener manages the SecurityContext persistence through a session.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ContextListener implements ListenerInterface
{
private $tokenStorage;
private $contextKey;
private $sessionKey;
private $logger;
private $userProviders;
private $dispatcher;
private $registered;
private $trustResolver;
public function __construct(TokenStorageInterface $tokenStorage, array $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, AuthenticationTrustResolverInterface $trustResolver = null)
{
if (empty($contextKey)) {
throw new \InvalidArgumentException('$contextKey must not be empty.');
}
foreach ($userProviders as $userProvider) {
if (!$userProvider instanceof UserProviderInterface) {
throw new \InvalidArgumentException(sprintf('User provider "%s" must implement "Symfony\Component\Security\Core\User\UserProviderInterface".', get_class($userProvider)));
}
}
$this->tokenStorage = $tokenStorage;
$this->userProviders = $userProviders;
$this->contextKey = $contextKey;
$this->sessionKey = '_security_'.$contextKey;
$this->logger = $logger;
$this->dispatcher = $dispatcher;
$this->trustResolver = $trustResolver ?: new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class);
}
/**
* Reads the Security Token from the session.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
public function handle(GetResponseEvent $event)
{
if (!$this->registered && null !== $this->dispatcher && $event->isMasterRequest()) {
$this->dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
$this->registered = true;
}
$request = $event->getRequest();
$session = $request->hasPreviousSession() ? $request->getSession() : null;
if (null === $session || null === $token = $session->get($this->sessionKey)) {
$this->tokenStorage->setToken(null);
return;
}
$token = unserialize($token);
if (null !== $this->logger) {
$this->logger->debug('Read existing security token from the session.', array('key' => $this->sessionKey));
}
if ($token instanceof TokenInterface) {
$token = $this->refreshUser($token);
} elseif (null !== $token) {
if (null !== $this->logger) {
$this->logger->warning('Expected a security token from the session, got something else.', array('key' => $this->sessionKey, 'received' => $token));
}
$token = null;
}
$this->tokenStorage->setToken($token);
}
/**
* Writes the security token into the session.
*
* @param FilterResponseEvent $event A FilterResponseEvent instance
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}
if (!$event->getRequest()->hasSession()) {
return;
}
$this->dispatcher->removeListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
$this->registered = false;
$request = $event->getRequest();
$session = $request->getSession();
if ((null === $token = $this->tokenStorage->getToken()) || $this->trustResolver->isAnonymous($token)) {
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.', array('key' => $this->sessionKey));
}
}
}
/**
* Refreshes the user by reloading it from the user provider.
*
* @param TokenInterface $token
*
* @return TokenInterface|null
*
* @throws \RuntimeException
*/
protected function refreshUser(TokenInterface $token)
{
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return $token;
}
$userNotFoundByProvider = false;
foreach ($this->userProviders as $provider) {
try {
$refreshedUser = $provider->refreshUser($user);
$token->setUser($refreshedUser);
if (null !== $this->logger) {
$this->logger->debug('User was reloaded from a user provider.', array('username' => $refreshedUser->getUsername(), 'provider' => get_class($provider)));
}
return $token;
} catch (UnsupportedUserException $e) {
// let's try the next user provider
} catch (UsernameNotFoundException $e) {
if (null !== $this->logger) {
$this->logger->warning('Username could not be found in the selected user provider.', array('username' => $e->getUsername(), 'provider' => get_class($provider)));
}
$userNotFoundByProvider = true;
}
}
if ($userNotFoundByProvider) {
return;
}
throw new \RuntimeException(sprintf('There is no user provider for user "%s".', get_class($user)));
}
}

View File

@@ -0,0 +1,219 @@
<?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\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\NonceExpiredException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
/**
* DigestAuthenticationListener implements Digest HTTP authentication.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DigestAuthenticationListener implements ListenerInterface
{
private $tokenStorage;
private $provider;
private $providerKey;
private $authenticationEntryPoint;
private $logger;
public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->tokenStorage = $tokenStorage;
$this->provider = $provider;
$this->providerKey = $providerKey;
$this->authenticationEntryPoint = $authenticationEntryPoint;
$this->logger = $logger;
}
/**
* Handles digest authentication.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*
* @throws AuthenticationServiceException
*/
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$header = $request->server->get('PHP_AUTH_DIGEST')) {
return;
}
$digestAuth = new DigestData($header);
if (null !== $token = $this->tokenStorage->getToken()) {
if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $digestAuth->getUsername()) {
return;
}
}
if (null !== $this->logger) {
$this->logger->debug('Digest Authorization header received from user agent.', array('header' => $header));
}
try {
$digestAuth->validateAndDecode($this->authenticationEntryPoint->getSecret(), $this->authenticationEntryPoint->getRealmName());
} catch (BadCredentialsException $e) {
$this->fail($event, $request, $e);
return;
}
try {
$user = $this->provider->loadUserByUsername($digestAuth->getUsername());
if (null === $user) {
throw new AuthenticationServiceException('Digest User provider returned null, which is an interface contract violation');
}
$serverDigestMd5 = $digestAuth->calculateServerDigest($user->getPassword(), $request->getMethod());
} catch (UsernameNotFoundException $e) {
$this->fail($event, $request, new BadCredentialsException(sprintf('Username %s not found.', $digestAuth->getUsername())));
return;
}
if (!hash_equals($serverDigestMd5, $digestAuth->getResponse())) {
if (null !== $this->logger) {
$this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse()));
}
$this->fail($event, $request, new BadCredentialsException('Incorrect response'));
return;
}
if ($digestAuth->isNonceExpired()) {
$this->fail($event, $request, new NonceExpiredException('Nonce has expired/timed out.'));
return;
}
if (null !== $this->logger) {
$this->logger->info('Digest authentication successful.', array('username' => $digestAuth->getUsername(), 'received' => $digestAuth->getResponse()));
}
$this->tokenStorage->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey));
}
private function fail(GetResponseEvent $event, Request $request, AuthenticationException $authException)
{
$token = $this->tokenStorage->getToken();
if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) {
$this->tokenStorage->setToken(null);
}
if (null !== $this->logger) {
$this->logger->info('Digest authentication failed.', array('exception' => $authException));
}
$event->setResponse($this->authenticationEntryPoint->start($request, $authException));
}
}
class DigestData
{
private $elements = array();
private $header;
private $nonceExpiryTime;
public function __construct($header)
{
$this->header = $header;
preg_match_all('/(\w+)=("((?:[^"\\\\]|\\\\.)+)"|([^\s,$]+))/', $header, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
if (isset($match[1]) && isset($match[3])) {
$this->elements[$match[1]] = isset($match[4]) ? $match[4] : $match[3];
}
}
}
public function getResponse()
{
return $this->elements['response'];
}
public function getUsername()
{
return strtr($this->elements['username'], array('\\"' => '"', '\\\\' => '\\'));
}
public function validateAndDecode($entryPointKey, $expectedRealm)
{
if ($keys = array_diff(array('username', 'realm', 'nonce', 'uri', 'response'), array_keys($this->elements))) {
throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s" (%s)', $this->header, implode(', ', $keys)));
}
if ('auth' === $this->elements['qop'] && !isset($this->elements['nc'], $this->elements['cnonce'])) {
throw new BadCredentialsException(sprintf('Missing mandatory digest value; received header "%s"', $this->header));
}
if ($expectedRealm !== $this->elements['realm']) {
throw new BadCredentialsException(sprintf('Response realm name "%s" does not match system realm name of "%s".', $this->elements['realm'], $expectedRealm));
}
if (false === $nonceAsPlainText = base64_decode($this->elements['nonce'])) {
throw new BadCredentialsException(sprintf('Nonce is not encoded in Base64; received nonce "%s".', $this->elements['nonce']));
}
$nonceTokens = explode(':', $nonceAsPlainText);
if (2 !== count($nonceTokens)) {
throw new BadCredentialsException(sprintf('Nonce should have yielded two tokens but was "%s".', $nonceAsPlainText));
}
$this->nonceExpiryTime = $nonceTokens[0];
if (md5($this->nonceExpiryTime.':'.$entryPointKey) !== $nonceTokens[1]) {
throw new BadCredentialsException(sprintf('Nonce token compromised "%s".', $nonceAsPlainText));
}
}
public function calculateServerDigest($password, $httpMethod)
{
$a2Md5 = md5(strtoupper($httpMethod).':'.$this->elements['uri']);
$a1Md5 = md5($this->elements['username'].':'.$this->elements['realm'].':'.$password);
$digest = $a1Md5.':'.$this->elements['nonce'];
if (!isset($this->elements['qop'])) {
} elseif ('auth' === $this->elements['qop']) {
$digest .= ':'.$this->elements['nc'].':'.$this->elements['cnonce'].':'.$this->elements['qop'];
} else {
throw new \InvalidArgumentException(sprintf('This method does not support a qop: "%s".', $this->elements['qop']));
}
$digest .= ':'.$a2Md5;
return md5($digest);
}
public function isNonceExpired()
{
return $this->nonceExpiryTime < microtime(true);
}
}

View File

@@ -0,0 +1,227 @@
<?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\Response;
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Core\Exception\AccountStatusException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException;
use Symfony\Component\Security\Core\Exception\LogoutException;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\Request;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* ExceptionListener catches authentication exception and converts them to
* Response instances.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExceptionListener
{
use TargetPathTrait;
private $tokenStorage;
private $providerKey;
private $accessDeniedHandler;
private $authenticationEntryPoint;
private $authenticationTrustResolver;
private $errorPage;
private $logger;
private $httpUtils;
private $stateless;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null, $stateless = false)
{
$this->tokenStorage = $tokenStorage;
$this->accessDeniedHandler = $accessDeniedHandler;
$this->httpUtils = $httpUtils;
$this->providerKey = $providerKey;
$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.
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
*/
public function register(EventDispatcherInterface $dispatcher)
{
$dispatcher->addListener(KernelEvents::EXCEPTION, array($this, 'onKernelException'));
}
/**
* Unregisters the dispatcher.
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
*/
public function unregister(EventDispatcherInterface $dispatcher)
{
$dispatcher->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException'));
}
/**
* Handles security related exceptions.
*
* @param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
*/
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
do {
if ($exception instanceof AuthenticationException) {
return $this->handleAuthenticationException($event, $exception);
} elseif ($exception instanceof AccessDeniedException) {
return $this->handleAccessDeniedException($event, $exception);
} elseif ($exception instanceof LogoutException) {
return $this->handleLogoutException($exception);
}
} while (null !== $exception = $exception->getPrevious());
}
private function handleAuthenticationException(GetResponseForExceptionEvent $event, AuthenticationException $exception)
{
if (null !== $this->logger) {
$this->logger->info('An AuthenticationException was thrown; redirecting to authentication entry point.', array('exception' => $exception));
}
try {
$event->setResponse($this->startAuthentication($event->getRequest(), $exception));
} catch (\Exception $e) {
$event->setException($e);
}
}
private function handleAccessDeniedException(GetResponseForExceptionEvent $event, AccessDeniedException $exception)
{
$event->setException(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.', array('exception' => $exception));
}
try {
$insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception);
$insufficientAuthenticationException->setToken($token);
$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
} catch (\Exception $e) {
$event->setException($e);
}
return;
}
if (null !== $this->logger) {
$this->logger->debug('Access denied, the user is neither anonymous, nor remember-me.', array('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));
}
} catch (\Exception $e) {
if (null !== $this->logger) {
$this->logger->error('An exception was thrown when handling an AccessDeniedException.', array('exception' => $e));
}
$event->setException(new \RuntimeException('Exception thrown when handling an exception.', 0, $e));
}
}
private function handleLogoutException(LogoutException $exception)
{
if (null !== $this->logger) {
$this->logger->info('A LogoutException was thrown.', array('exception' => $exception));
}
}
/**
* @param Request $request
* @param AuthenticationException $authException
*
* @return Response
*
* @throws AuthenticationException
*/
private function startAuthentication(Request $request, AuthenticationException $authException)
{
if (null === $this->authenticationEntryPoint) {
throw $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.', array('exception' => $authException));
}
}
$response = $this->authenticationEntryPoint->start($request, $authException);
if (!$response instanceof Response) {
$given = is_object($response) ? get_class($response) : gettype($response);
throw new \LogicException(sprintf('The %s::start() method must return a Response object (%s returned)', get_class($this->authenticationEntryPoint), $given));
}
return $response;
}
/**
* @param Request $request
*/
protected function setTargetPath(Request $request)
{
// session isn't required when using HTTP basic authentication mechanism for example
if ($request->hasSession() && $request->isMethodSafe(false) && !$request->isXmlHttpRequest()) {
$this->saveTargetPath($request->getSession(), $this->providerKey, $request->getUri());
}
}
}

View File

@@ -0,0 +1,29 @@
<?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\GetResponseEvent;
/**
* Interface that must be implemented by firewall listeners.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface ListenerInterface
{
/**
* This interface must be implemented by firewall listeners.
*
* @param GetResponseEvent $event
*/
public function handle(GetResponseEvent $event);
}

View 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 Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\LogoutException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
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;
/**
* LogoutListener logout users.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class LogoutListener implements ListenerInterface
{
private $tokenStorage;
private $options;
private $handlers;
private $successHandler;
private $httpUtils;
private $csrfTokenManager;
/**
* Constructor.
*
* @param TokenStorageInterface $tokenStorage
* @param HttpUtils $httpUtils An HttpUtils instance
* @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance
* @param array $options An array of options to process a logout attempt
* @param CsrfTokenManagerInterface|null $csrfTokenManager A CsrfTokenManagerInterface instance
*/
public function __construct(TokenStorageInterface $tokenStorage, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfTokenManagerInterface $csrfTokenManager = null)
{
$this->tokenStorage = $tokenStorage;
$this->httpUtils = $httpUtils;
$this->options = array_merge(array(
'csrf_parameter' => '_csrf_token',
'csrf_token_id' => 'logout',
'logout_path' => '/logout',
), $options);
$this->successHandler = $successHandler;
$this->csrfTokenManager = $csrfTokenManager;
$this->handlers = array();
}
/**
* Adds a logout handler.
*
* @param LogoutHandlerInterface $handler
*/
public function addHandler(LogoutHandlerInterface $handler)
{
$this->handlers[] = $handler;
}
/**
* Performs the logout if requested.
*
* If a CsrfTokenManagerInterface instance is available, it will be used to
* validate the request.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*
* @throws LogoutException if the CSRF token is invalid
* @throws \RuntimeException if the LogoutSuccessHandlerInterface instance does not return a response
*/
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$this->requiresLogout($request)) {
return;
}
if (null !== $this->csrfTokenManager) {
$csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);
if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) {
throw new LogoutException('Invalid CSRF token.');
}
}
$response = $this->successHandler->onLogoutSuccess($request);
if (!$response instanceof Response) {
throw new \RuntimeException('Logout Success Handler did not return a Response.');
}
// handle multiple logout attempts gracefully
if ($token = $this->tokenStorage->getToken()) {
foreach ($this->handlers as $handler) {
$handler->logout($request, $response, $token);
}
}
$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.
*
* @param Request $request
*
* @return bool
*/
protected function requiresLogout(Request $request)
{
return isset($this->options['logout_path']) && $this->httpUtils->checkRequestPath($request, $this->options['logout_path']);
}
}

View 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\HttpKernel\Event\GetResponseEvent;
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\RememberMe\RememberMeServicesInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
/**
* RememberMeListener implements authentication capabilities via a cookie.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RememberMeListener implements ListenerInterface
{
private $tokenStorage;
private $rememberMeServices;
private $authenticationManager;
private $logger;
private $dispatcher;
private $catchExceptions = true;
private $sessionStrategy;
/**
* Constructor.
*
* @param TokenStorageInterface $tokenStorage
* @param RememberMeServicesInterface $rememberMeServices
* @param AuthenticationManagerInterface $authenticationManager
* @param LoggerInterface|null $logger
* @param EventDispatcherInterface|null $dispatcher
* @param bool $catchExceptions
* @param SessionAuthenticationStrategyInterface|null $sessionStrategy
*/
public function __construct(TokenStorageInterface $tokenStorage, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $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 = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy;
}
/**
* Handles remember-me cookie based authentication.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
public function handle(GetResponseEvent $event)
{
if (null !== $this->tokenStorage->getToken()) {
return;
}
$request = $event->getRequest();
if (null === $token = $this->rememberMeServices->autoLogin($request)) {
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(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent);
}
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.', array('exception' => $e)
);
}
$this->rememberMeServices->loginFail($request);
if (!$this->catchExceptions) {
throw $e;
}
}
}
}

View File

@@ -0,0 +1,49 @@
<?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\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* REMOTE_USER authentication listener.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Maxime Douailin <maxime.douailin@gmail.com>
*/
class RemoteUserAuthenticationListener extends AbstractPreAuthenticatedListener
{
private $userKey;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, $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 array($request->server->get($this->userKey), null);
}
}

View File

@@ -0,0 +1,121 @@
<?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\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
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\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\ParameterBagUtils;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Psr\Log\LoggerInterface;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
{
private $simpleAuthenticator;
private $csrfTokenManager;
/**
* Constructor.
*
* @param TokenStorageInterface $tokenStorage A TokenStorageInterface instance
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param SessionAuthenticationStrategyInterface $sessionStrategy
* @param HttpUtils $httpUtils An HttpUtils 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|null $logger A LoggerInterface instance
* @param EventDispatcherInterface|null $dispatcher An EventDispatcherInterface instance
* @param CsrfTokenManagerInterface|null $csrfTokenManager A CsrfTokenManagerInterface instance
* @param SimpleFormAuthenticatorInterface|null $simpleAuthenticator A SimpleFormAuthenticatorInterface instance
*
* @throws \InvalidArgumentException In case no simple authenticator is provided
*/
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
{
if (!$simpleAuthenticator) {
throw new \InvalidArgumentException('Missing simple authenticator');
}
$this->simpleAuthenticator = $simpleAuthenticator;
$this->csrfTokenManager = $csrfTokenManager;
$options = array_merge(array(
'username_parameter' => '_username',
'password_parameter' => '_password',
'csrf_parameter' => '_csrf_token',
'csrf_token_id' => 'authenticate',
'post_only' => true,
), $options);
parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, $options, $logger, $dispatcher);
}
/**
* {@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 (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
}
if ($this->options['post_only']) {
$username = trim(ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter']));
$password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']);
} else {
$username = trim(ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter']));
$password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
}
if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
throw new BadCredentialsException('Invalid username.');
}
$request->getSession()->set(Security::LAST_USERNAME, $username);
$token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey);
return $this->authenticationManager->authenticate($token);
}
}

View File

@@ -0,0 +1,126 @@
<?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\Security\Core\Authentication\AuthenticationManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Authentication\SimplePreAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
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\SecurityEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* SimplePreAuthenticationListener implements simple proxying to an authenticator.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SimplePreAuthenticationListener implements ListenerInterface
{
private $tokenStorage;
private $authenticationManager;
private $providerKey;
private $simpleAuthenticator;
private $logger;
private $dispatcher;
/**
* Constructor.
*
* @param TokenStorageInterface $tokenStorage A TokenStorageInterface instance
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param string $providerKey
* @param SimplePreAuthenticatorInterface $simpleAuthenticator A SimplePreAuthenticatorInterface instance
* @param LoggerInterface|null $logger A LoggerInterface instance
* @param EventDispatcherInterface|null $dispatcher An EventDispatcherInterface instance
*/
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, SimplePreAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->tokenStorage = $tokenStorage;
$this->authenticationManager = $authenticationManager;
$this->providerKey = $providerKey;
$this->simpleAuthenticator = $simpleAuthenticator;
$this->logger = $logger;
$this->dispatcher = $dispatcher;
}
/**
* Handles basic authentication.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*/
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (null !== $this->logger) {
$this->logger->info('Attempting SimplePreAuthentication.', array('key' => $this->providerKey, 'authenticator' => get_class($this->simpleAuthenticator)));
}
if (null !== $this->tokenStorage->getToken() && !$this->tokenStorage->getToken() instanceof AnonymousToken) {
return;
}
try {
$token = $this->simpleAuthenticator->createToken($request, $this->providerKey);
// allow null to be returned to skip authentication
if (null === $token) {
return;
}
$token = $this->authenticationManager->authenticate($token);
$this->tokenStorage->setToken($token);
if (null !== $this->dispatcher) {
$loginEvent = new InteractiveLoginEvent($request, $token);
$this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent);
}
} catch (AuthenticationException $e) {
$this->tokenStorage->setToken(null);
if (null !== $this->logger) {
$this->logger->info('SimplePreAuthentication request failed.', array('exception' => $e, 'authenticator' => get_class($this->simpleAuthenticator)));
}
if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) {
$response = $this->simpleAuthenticator->onAuthenticationFailure($request, $e);
if ($response instanceof Response) {
$event->setResponse($response);
} elseif (null !== $response) {
throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null or a Response object', get_class($this->simpleAuthenticator)));
}
}
return;
}
if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) {
$response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token);
if ($response instanceof Response) {
$event->setResponse($response);
} elseif (null !== $response) {
throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null or a Response object', get_class($this->simpleAuthenticator)));
}
}
}
}

View File

@@ -0,0 +1,194 @@
<?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\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\SwitchUserRole;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* SwitchUserListener allows a user to impersonate another one temporarily
* (like the Unix su command).
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class SwitchUserListener implements ListenerInterface
{
private $tokenStorage;
private $provider;
private $userChecker;
private $providerKey;
private $accessDecisionManager;
private $usernameParameter;
private $role;
private $logger;
private $dispatcher;
public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->tokenStorage = $tokenStorage;
$this->provider = $provider;
$this->userChecker = $userChecker;
$this->providerKey = $providerKey;
$this->accessDecisionManager = $accessDecisionManager;
$this->usernameParameter = $usernameParameter;
$this->role = $role;
$this->logger = $logger;
$this->dispatcher = $dispatcher;
}
/**
* Handles the switch to another user.
*
* @param GetResponseEvent $event A GetResponseEvent instance
*
* @throws \LogicException if switching to a user failed
*/
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$request->get($this->usernameParameter)) {
return;
}
if ('_exit' === $request->get($this->usernameParameter)) {
$this->tokenStorage->setToken($this->attemptExitUser($request));
} else {
try {
$this->tokenStorage->setToken($this->attemptSwitchUser($request));
} catch (AuthenticationException $e) {
throw new \LogicException(sprintf('Switch User failed: "%s"', $e->getMessage()));
}
}
$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.
*
* @param Request $request A Request instance
*
* @return TokenInterface|null The new TokenInterface if successfully switched, null otherwise
*
* @throws \LogicException
* @throws AccessDeniedException
*/
private function attemptSwitchUser(Request $request)
{
$token = $this->tokenStorage->getToken();
$originalToken = $this->getOriginalToken($token);
if (false !== $originalToken) {
if ($token->getUsername() === $request->get($this->usernameParameter)) {
return $token;
}
throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername()));
}
if (false === $this->accessDecisionManager->decide($token, array($this->role))) {
$exception = new AccessDeniedException();
$exception->setAttributes($this->role);
throw $exception;
}
$username = $request->get($this->usernameParameter);
if (null !== $this->logger) {
$this->logger->info('Attempting to switch to user.', array('username' => $username));
}
$user = $this->provider->loadUserByUsername($username);
$this->userChecker->checkPostAuth($user);
$roles = $user->getRoles();
$roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->tokenStorage->getToken());
$token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles);
if (null !== $this->dispatcher) {
$switchEvent = new SwitchUserEvent($request, $token->getUser());
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
}
return $token;
}
/**
* Attempts to exit from an already switched user.
*
* @param Request $request A Request instance
*
* @return TokenInterface The original TokenInterface instance
*
* @throws AuthenticationCredentialsNotFoundException
*/
private function attemptExitUser(Request $request)
{
if (null === ($currentToken = $this->tokenStorage->getToken()) || false === $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());
$switchEvent = new SwitchUserEvent($request, $user);
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
}
return $original;
}
/**
* Gets the original Token from a switched one.
*
* @param TokenInterface $token A switched TokenInterface instance
*
* @return TokenInterface|false The original TokenInterface instance, false if the current TokenInterface is not switched
*/
private function getOriginalToken(TokenInterface $token)
{
foreach ($token->getRoles() as $role) {
if ($role instanceof SwitchUserRole) {
return $role->getSource();
}
}
return false;
}
}

View File

@@ -0,0 +1,95 @@
<?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 Psr\Log\LoggerInterface;
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\ParameterBagUtils;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\HttpUtils;
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\EventDispatcher\EventDispatcherInterface;
/**
* 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>
*/
class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
{
private $csrfTokenManager;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null)
{
parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
'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 (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['csrf_token_id'], $csrfToken))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
}
if ($this->options['post_only']) {
$username = trim(ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter']));
$password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']);
} else {
$username = trim(ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter']));
$password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']);
}
if (strlen($username) > Security::MAX_USERNAME_LENGTH) {
throw new BadCredentialsException('Invalid username.');
}
$request->getSession()->set(Security::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
}
}

View File

@@ -0,0 +1,57 @@
<?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\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* X509 authentication listener.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class X509AuthenticationListener extends AbstractPreAuthenticatedListener
{
private $userKey;
private $credentialKey;
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $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 array($user, $request->server->get($this->credentialKey, ''));
}
}