diff options
Diffstat (limited to 'Http')
33 files changed, 559 insertions, 267 deletions
diff --git a/Http/AccessMap.php b/Http/AccessMap.php index 6d12b42..de78e15 100644 --- a/Http/AccessMap.php +++ b/Http/AccessMap.php @@ -20,7 +20,7 @@ use Symfony\Component\HttpFoundation\Request; * * @author Fabien Potencier <fabien@symfony.com> */ -class AccessMap +class AccessMap implements AccessMapInterface { private $map = array(); diff --git a/Http/AccessMapInterface.php b/Http/AccessMapInterface.php new file mode 100644 index 0000000..7d15fee --- /dev/null +++ b/Http/AccessMapInterface.php @@ -0,0 +1,33 @@ +<?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; + +use Symfony\Component\HttpFoundation\Request; + +/** + * AccessMap allows configuration of different access control rules for + * specific parts of the website. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Kris Wallsmith <kris@symfony.com> + */ +interface AccessMapInterface +{ + /** + * Returns security attributes and required channel for the supplied request. + * + * @param Request $request The current request + * + * @return array A tuple of security attributes and the required channel + */ + public function getPatterns(Request $request); +} diff --git a/Http/Authentication/AuthenticationFailureHandlerInterface.php b/Http/Authentication/AuthenticationFailureHandlerInterface.php index 69b5426..8dbd29a 100644 --- a/Http/Authentication/AuthenticationFailureHandlerInterface.php +++ b/Http/Authentication/AuthenticationFailureHandlerInterface.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Authentication; @@ -33,7 +33,7 @@ interface AuthenticationFailureHandlerInterface * @param Request $request * @param AuthenticationException $exception * - * @return Response the response to return + * @return Response The response to return, never null */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception); } diff --git a/Http/Authentication/AuthenticationSuccessHandlerInterface.php b/Http/Authentication/AuthenticationSuccessHandlerInterface.php index ed44ee5..5c08e73 100644 --- a/Http/Authentication/AuthenticationSuccessHandlerInterface.php +++ b/Http/Authentication/AuthenticationSuccessHandlerInterface.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Authentication; @@ -33,7 +33,7 @@ interface AuthenticationSuccessHandlerInterface * @param Request $request * @param TokenInterface $token * - * @return Response the response to return + * @return Response never null */ public function onAuthenticationSuccess(Request $request, TokenInterface $token); } diff --git a/Http/Authentication/DefaultAuthenticationFailureHandler.php b/Http/Authentication/DefaultAuthenticationFailureHandler.php new file mode 100644 index 0000000..61d77a8 --- /dev/null +++ b/Http/Authentication/DefaultAuthenticationFailureHandler.php @@ -0,0 +1,87 @@ +<?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\Authentication; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Http\HttpUtils; + +/** + * Class with the default authentication failure handling logic. + * + * Can be optionally be extended from by the developer to alter the behaviour + * while keeping the default behaviour. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + * @author Alexander <iam.asm89@gmail.com> + */ +class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandlerInterface +{ + protected $httpKernel; + protected $httpUtils; + protected $logger; + protected $options; + + /** + * Constructor. + * + * @param HttpKernelInterface $httpKernel + * @param HttpUtils $httpUtils + * @param array $options Options for processing a failed authentication attempt. + * @param LoggerInterface $logger Optional logger + */ + public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null) + { + $this->httpKernel = $httpKernel; + $this->httpUtils = $httpUtils; + $this->logger = $logger; + + $this->options = array_merge(array( + 'failure_path' => null, + 'failure_forward' => false, + 'login_path' => '/login', + ), $options); + } + + /** + * {@inheritDoc} + */ + public function onAuthenticationFailure(Request $request, AuthenticationException $exception) + { + if (null === $this->options['failure_path']) { + $this->options['failure_path'] = $this->options['login_path']; + } + + if ($this->options['failure_forward']) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Forwarding to %s', $this->options['failure_path'])); + } + + $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']); + $subRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + + return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); + } + + if (null !== $this->logger) { + $this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path'])); + } + + $request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + + return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']); + } +} diff --git a/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/Http/Authentication/DefaultAuthenticationSuccessHandler.php new file mode 100644 index 0000000..dc7cbe5 --- /dev/null +++ b/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -0,0 +1,111 @@ +<?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\Authentication; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\HttpUtils; + +/** + * Class with the default authentication success handling logic. + * + * Can be optionally be extended from by the developer to alter the behaviour + * while keeping the default behaviour. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + * @author Alexander <iam.asm89@gmail.com> + */ +class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface +{ + protected $httpUtils; + protected $options; + protected $providerKey; + + /** + * Constructor. + * + * @param HttpUtils $httpUtils + * @param array $options Options for processing a successful authentication attempt. + */ + public function __construct(HttpUtils $httpUtils, array $options) + { + $this->httpUtils = $httpUtils; + + $this->options = array_merge(array( + 'always_use_default_target_path' => false, + 'default_target_path' => '/', + 'login_path' => '/login', + 'target_path_parameter' => '_target_path', + 'use_referer' => false, + ), $options); + } + + /** + * {@inheritDoc} + */ + public function onAuthenticationSuccess(Request $request, TokenInterface $token) + { + return $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request)); + } + + + /** + * Get the provider key. + * + * @return string + */ + public function getProviderKey() + { + return $this->providerKey; + } + + /** + * Set the provider key. + * + * @param string $providerKey + */ + public function setProviderKey($providerKey) + { + $this->providerKey = $providerKey; + } + + /** + * Builds the target URL according to the defined options. + * + * @param Request $request + * + * @return string + */ + protected function determineTargetUrl(Request $request) + { + if ($this->options['always_use_default_target_path']) { + return $this->options['default_target_path']; + } + + if ($targetUrl = $request->get($this->options['target_path_parameter'], null, true)) { + return $targetUrl; + } + + if (null !== $this->providerKey && $targetUrl = $request->getSession()->get('_security.'.$this->providerKey.'.target_path')) { + $request->getSession()->remove('_security.'.$this->providerKey.'.target_path'); + + return $targetUrl; + } + + if ($this->options['use_referer'] && ($targetUrl = $request->headers->get('Referer')) && $targetUrl !== $this->httpUtils->generateUri($request, $this->options['login_path'])) { + return $targetUrl; + } + + return $this->options['default_target_path']; + } +} diff --git a/Http/Authorization/AccessDeniedHandlerInterface.php b/Http/Authorization/AccessDeniedHandlerInterface.php index 3811bf0..a10a5d0 100644 --- a/Http/Authorization/AccessDeniedHandlerInterface.php +++ b/Http/Authorization/AccessDeniedHandlerInterface.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Authorization; diff --git a/Http/Event/InteractiveLoginEvent.php b/Http/Event/InteractiveLoginEvent.php index f242501..2225d92 100644 --- a/Http/Event/InteractiveLoginEvent.php +++ b/Http/Event/InteractiveLoginEvent.php @@ -21,17 +21,33 @@ class InteractiveLoginEvent extends Event private $authenticationToken; + /** + * Constructor. + * + * @param Request $request A Request instance + * @param TokenInterface $authenticationToken A TokenInterface instance + */ public function __construct(Request $request, TokenInterface $authenticationToken) { $this->request = $request; $this->authenticationToken = $authenticationToken; } + /** + * Gets the request. + * + * @return Request A Request instance + */ public function getRequest() { return $this->request; } + /** + * Gets the authentication token. + * + * @return TokenInterface A TokenInterface instance + */ public function getAuthenticationToken() { return $this->authenticationToken; diff --git a/Http/Firewall.php b/Http/Firewall.php index 91eb6a9..a590fd9 100644 --- a/Http/Firewall.php +++ b/Http/Firewall.php @@ -33,7 +33,7 @@ class Firewall /** * Constructor. * - * @param FirewallMap $map A FirewallMap instance + * @param FirewallMapInterface $map A FirewallMapInterface instance * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance */ public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher) diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php index 8403ec7..410fb73 100644 --- a/Http/Firewall/AbstractAuthenticationListener.php +++ b/Http/Firewall/AbstractAuthenticationListener.php @@ -20,7 +20,6 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\SessionUnavailableException; use Symfony\Component\HttpKernel\Log\LoggerInterface; -use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -70,14 +69,14 @@ abstract class AbstractAuthenticationListener implements ListenerInterface * @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 AuthenticationSuccessHandlerInterface $successHandler - * @param AuthenticationFailureHandlerInterface $failureHandler - * @param LoggerInterface $logger A LoggerInterface instance - * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(SecurityContextInterface $securityContext, 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.'); @@ -91,13 +90,6 @@ abstract class AbstractAuthenticationListener implements ListenerInterface $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, ), $options); $this->logger = $logger; $this->dispatcher = $dispatcher; @@ -133,7 +125,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface try { if (!$request->hasPreviousSession()) { - throw new SessionUnavailableException('Your session has timed-out, or you have disabled cookies.'); + throw new SessionUnavailableException('Your session has timed out, or you have disabled cookies.'); } if (null === $returnValue = $this->attemptAuthentication($request)) { @@ -177,7 +169,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface * * @param Request $request A Request instance * - * @return TokenInterface The authenticated token, or null if full authentication is not possible + * @return TokenInterface|Response|null The authenticated token, null if full authentication is not possible, or a Response * * @throws AuthenticationException if the authentication fails */ @@ -191,32 +183,13 @@ abstract class AbstractAuthenticationListener implements ListenerInterface $this->securityContext->setToken(null); - if (null !== $this->failureHandler) { - return $this->failureHandler->onAuthenticationFailure($request, $failed); - } - - if (null === $this->options['failure_path']) { - $this->options['failure_path'] = $this->options['login_path']; - } - - if ($this->options['failure_forward']) { - if (null !== $this->logger) { - $this->logger->debug(sprintf('Forwarding to %s', $this->options['failure_path'])); - } - - $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']); - $subRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $failed); + $response = $this->failureHandler->onAuthenticationFailure($request, $failed); - return $event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST); + if (!$response instanceof Response) { + throw new \RuntimeException('Authentication Failure Handler did not return a Response.'); } - if (null !== $this->logger) { - $this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path'])); - } - - $request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $failed); - - return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']); + return $response; } private function onSuccess(GetResponseEvent $event, Request $request, TokenInterface $token) @@ -236,10 +209,10 @@ abstract class AbstractAuthenticationListener implements ListenerInterface $this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent); } - if (null !== $this->successHandler) { - $response = $this->successHandler->onAuthenticationSuccess($request, $token); - } else { - $response = $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request)); + $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) { @@ -248,35 +221,4 @@ abstract class AbstractAuthenticationListener implements ListenerInterface return $response; } - - /** - * Builds the target URL according to the defined options. - * - * @param Request $request - * - * @return string - */ - private function determineTargetUrl(Request $request) - { - if ($this->options['always_use_default_target_path']) { - return $this->options['default_target_path']; - } - - if ($targetUrl = $request->get($this->options['target_path_parameter'], null, true)) { - return $targetUrl; - } - - $session = $request->getSession(); - if ($targetUrl = $session->get('_security.target_path')) { - $session->remove('_security.target_path'); - - return $targetUrl; - } - - if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) { - return $targetUrl; - } - - return $this->options['default_target_path']; - } } diff --git a/Http/Firewall/AccessListener.php b/Http/Firewall/AccessListener.php index 877b6c3..3e2d3a5 100644 --- a/Http/Firewall/AccessListener.php +++ b/Http/Firewall/AccessListener.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; -use Symfony\Component\Security\Http\AccessMap; +use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -33,7 +33,7 @@ class AccessListener implements ListenerInterface private $authManager; private $logger; - public function __construct(SecurityContextInterface $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMap $map, AuthenticationManagerInterface $authManager, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager, LoggerInterface $logger = null) { $this->context = $context; $this->accessDecisionManager = $accessDecisionManager; diff --git a/Http/Firewall/ChannelListener.php b/Http/Firewall/ChannelListener.php index 847753f..9b0f8c6 100644 --- a/Http/Firewall/ChannelListener.php +++ b/Http/Firewall/ChannelListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Http\AccessMap; +use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -28,7 +28,7 @@ class ChannelListener implements ListenerInterface private $authenticationEntryPoint; private $logger; - public function __construct(AccessMap $map, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) + public function __construct(AccessMapInterface $map, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) { $this->map = $map; $this->authenticationEntryPoint = $authenticationEntryPoint; diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php index 0bf5cff..fddd3c7 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -22,6 +22,7 @@ use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -36,6 +37,7 @@ class ContextListener implements ListenerInterface private $contextKey; private $logger; private $userProviders; + private $dispatcher; public function __construct(SecurityContextInterface $context, array $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { @@ -43,14 +45,17 @@ class ContextListener implements ListenerInterface 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->context = $context; $this->userProviders = $userProviders; $this->contextKey = $contextKey; $this->logger = $logger; - - if (null !== $dispatcher) { - $dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse')); - } + $this->dispatcher = $dispatcher; } /** @@ -60,6 +65,10 @@ class ContextListener implements ListenerInterface */ public function handle(GetResponseEvent $event) { + if (null !== $this->dispatcher && HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { + $this->dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse')); + } + $request = $event->getRequest(); $session = $request->hasPreviousSession() ? $request->getSession() : null; @@ -104,19 +113,19 @@ class ContextListener implements ListenerInterface return; } - if (null === $token = $this->context->getToken()) { - return; + if (null !== $this->logger) { + $this->logger->debug('Write SecurityContext in the session'); } - if (null === $token || $token instanceof AnonymousToken) { + if (null === $session = $event->getRequest()->getSession()) { return; } - if (null !== $this->logger) { - $this->logger->debug('Write SecurityContext in the session'); + if ((null === $token = $this->context->getToken()) || ($token instanceof AnonymousToken)) { + $session->remove('_security_'.$this->contextKey); + } else { + $session->set('_security_'.$this->contextKey, serialize($token)); } - - $event->getRequest()->getSession()->set('_security_'.$this->contextKey, serialize($token)); } /** diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php index b704262..f134f9c 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -15,12 +15,12 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; -use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; 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\HttpUtils; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Log\LoggerInterface; @@ -39,6 +39,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; class ExceptionListener { private $context; + private $providerKey; private $accessDeniedHandler; private $authenticationEntryPoint; private $authenticationTrustResolver; @@ -46,11 +47,12 @@ class ExceptionListener private $logger; private $httpUtils; - public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null) { $this->context = $context; $this->accessDeniedHandler = $accessDeniedHandler; $this->httpUtils = $httpUtils; + $this->providerKey = $providerKey; $this->authenticationEntryPoint = $authenticationEntryPoint; $this->authenticationTrustResolver = $trustResolver; $this->errorPage = $errorPage; @@ -95,10 +97,12 @@ class ExceptionListener return; } } elseif ($exception instanceof AccessDeniedException) { + $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception)); + $token = $this->context->getToken(); if (!$this->authenticationTrustResolver->isFullFledged($token)) { if (null !== $this->logger) { - $this->logger->debug('Access denied (user is not fully authenticated); redirecting to authentication entry point'); + $this->logger->debug(sprintf('Access is denied (user is not fully authenticated) by "%s" at line %s; redirecting to authentication entry point', $exception->getFile(), $exception->getLine())); } try { @@ -110,7 +114,7 @@ class ExceptionListener } } else { if (null !== $this->logger) { - $this->logger->debug('Access is denied (and user is neither anonymous, nor remember-me)'); + $this->logger->debug(sprintf('Access is denied (and user is neither anonymous, nor remember-me) by "%s" at line %s', $exception->getFile(), $exception->getLine())); } try { @@ -125,10 +129,7 @@ class ExceptionListener $subRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $exception); $response = $event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true); - $response->setStatusCode(403); } else { - $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception)); - return; } } catch (\Exception $e) { @@ -141,6 +142,12 @@ class ExceptionListener return; } } + } elseif ($exception instanceof LogoutException) { + if (null !== $this->logger) { + $this->logger->info(sprintf('Logout exception occurred; wrapping with AccessDeniedHttpException (%s)', $exception->getMessage())); + } + + return; } else { return; } @@ -160,10 +167,9 @@ class ExceptionListener $this->setTargetPath($request); - if ($authException instanceof AccountStatusException && ($token = $this->context->getToken()) instanceof UsernamePasswordToken) { + if ($authException instanceof AccountStatusException) { // remove the security token to prevent infinite redirect loops $this->context->setToken(null); - $request->getSession()->remove('_security_'.$token->getProviderKey()); } return $this->authenticationEntryPoint->start($request, $authException); @@ -173,7 +179,7 @@ class ExceptionListener { // session isn't required when using http basic authentication mechanism for example if ($request->hasSession() && $request->isMethodSafe()) { - $request->getSession()->set('_security.target_path', $request->getUri()); + $request->getSession()->set('_security.' . $this->providerKey . '.target_path', $request->getUri()); } } } diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php index 07244f5..32a0511 100644 --- a/Http/Firewall/LogoutListener.php +++ b/Http/Firewall/LogoutListener.php @@ -11,13 +11,15 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; - -use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; -use Symfony\Component\Security\Core\SecurityContextInterface; -use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Exception\LogoutException; +use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; +use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; /** * LogoutListener logout users. @@ -27,28 +29,32 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent; class LogoutListener implements ListenerInterface { private $securityContext; - private $logoutPath; - private $targetUrl; + private $options; private $handlers; private $successHandler; private $httpUtils; + private $csrfProvider; /** * Constructor * * @param SecurityContextInterface $securityContext * @param HttpUtils $httpUtils An HttpUtilsInterface instance - * @param string $logoutPath The path that starts the logout process - * @param string $targetUrl The URL to redirect to after logout - * @param LogoutSuccessHandlerInterface $successHandler + * @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance + * @param array $options An array of options to process a logout attempt + * @param CsrfProviderInterface $csrfProvider A CsrfProviderInterface instance */ - public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, $logoutPath, $targetUrl = '/', LogoutSuccessHandlerInterface $successHandler = null) + public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfProviderInterface $csrfProvider = null) { $this->securityContext = $securityContext; $this->httpUtils = $httpUtils; - $this->logoutPath = $logoutPath; - $this->targetUrl = $targetUrl; + $this->options = array_merge(array( + 'csrf_parameter' => '_csrf_token', + 'intention' => 'logout', + 'logout_path' => '/logout', + ), $options); $this->successHandler = $successHandler; + $this->csrfProvider = $csrfProvider; $this->handlers = array(); } @@ -56,8 +62,6 @@ class LogoutListener implements ListenerInterface * Adds a logout handler * * @param LogoutHandlerInterface $handler - * - * @return void */ public function addHandler(LogoutHandlerInterface $handler) { @@ -67,24 +71,32 @@ class LogoutListener implements ListenerInterface /** * Performs the logout if requested * + * If a CsrfProviderInterface instance is available, it will be used to + * validate the request. + * * @param GetResponseEvent $event A GetResponseEvent instance + * @throws InvalidCsrfTokenException 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->httpUtils->checkRequestPath($request, $this->logoutPath)) { + if (!$this->requiresLogout($request)) { return; } - if (null !== $this->successHandler) { - $response = $this->successHandler->onLogoutSuccess($request); + if (null !== $this->csrfProvider) { + $csrfToken = $request->get($this->options['csrf_parameter'], null, true); - if (!$response instanceof Response) { - throw new \RuntimeException('Logout Success Handler did not return a Response.'); + if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) { + throw new LogoutException('Invalid CSRF token.'); } - } else { - $response = $this->httpUtils->createRedirectResponse($request, $this->targetUrl); + } + + $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 @@ -98,4 +110,20 @@ class LogoutListener implements ListenerInterface $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 Boolean + */ + protected function requiresLogout(Request $request) + { + return $this->httpUtils->checkRequestPath($request, $this->options['logout_path']); + } } diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php index ccda113..3614f79 100644 --- a/Http/Firewall/RememberMeListener.php +++ b/Http/Firewall/RememberMeListener.php @@ -1,5 +1,14 @@ <?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\Log\LoggerInterface; @@ -12,15 +21,6 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -/* - * This file is part of the Symfony framework. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - /** * RememberMeListener implements authentication capabilities via a cookie * diff --git a/Http/Firewall/SwitchUserListener.php b/Http/Firewall/SwitchUserListener.php index 9780860..7f0aa78 100644 --- a/Http/Firewall/SwitchUserListener.php +++ b/Http/Firewall/SwitchUserListener.php @@ -86,9 +86,7 @@ class SwitchUserListener implements ListenerInterface try { $this->securityContext->setToken($this->attemptSwitchUser($request)); } catch (AuthenticationException $e) { - if (null !== $this->logger) { - $this->logger->warn(sprintf('Switch User failed: "%s"', $e->getMessage())); - } + throw new \LogicException(sprintf('Switch User failed: "%s"', $e->getMessage())); } } @@ -108,8 +106,14 @@ class SwitchUserListener implements ListenerInterface private function attemptSwitchUser(Request $request) { $token = $this->securityContext->getToken(); - if (false !== $this->getOriginalToken($token)) { - throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); + $originalToken = $this->getOriginalToken($token); + + if (false !== $originalToken) { + if ($token->getUsername() === $request->get($this->usernameParameter)) { + return $token; + } else { + throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); + } } if (false === $this->accessDecisionManager->decide($token, array($this->role))) { @@ -148,7 +152,7 @@ class SwitchUserListener implements ListenerInterface private function attemptExitUser(Request $request) { if (false === $original = $this->getOriginalToken($this->securityContext->getToken())) { - throw new AuthenticationCredentialsNotFoundException(sprintf('Could not find original Token object.')); + throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); } if (null !== $this->dispatcher) { diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index bd2cec1..22330a8 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -37,15 +37,15 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL /** * {@inheritdoc} */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null) { - parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, array_merge(array( + parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', 'intention' => 'authenticate', 'post_only' => true, - ), $options), $successHandler, $failureHandler, $logger, $dispatcher); + ), $options), $logger, $dispatcher); $this->csrfProvider = $csrfProvider; } @@ -53,6 +53,18 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL /** * {@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 ($this->options['post_only'] && 'post' !== strtolower($request->getMethod())) { diff --git a/Http/FirewallMap.php b/Http/FirewallMap.php index d5fc331..dfc0984 100644 --- a/Http/FirewallMap.php +++ b/Http/FirewallMap.php @@ -1,20 +1,20 @@ <?php -namespace Symfony\Component\Security\Http; - -use Symfony\Component\HttpFoundation\RequestMatcherInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Security\Http\Firewall\ExceptionListener; - /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ +namespace Symfony\Component\Security\Http; + +use Symfony\Component\HttpFoundation\RequestMatcherInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\Firewall\ExceptionListener; + /** * FirewallMap allows configuration of different firewalls for specific parts * of the website. diff --git a/Http/FirewallMapInterface.php b/Http/FirewallMapInterface.php index 57afc75..336125f 100644 --- a/Http/FirewallMapInterface.php +++ b/Http/FirewallMapInterface.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http; diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php index cac130e..76cfc6a 100644 --- a/Http/HttpUtils.php +++ b/Http/HttpUtils.php @@ -15,7 +15,8 @@ use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\Routing\RouterInterface; +use Symfony\Component\Routing\Matcher\UrlMatcherInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; @@ -26,16 +27,19 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException; */ class HttpUtils { - private $router; + private $urlGenerator; + private $urlMatcher; /** * Constructor. * - * @param RouterInterface $router An RouterInterface instance + * @param UrlGeneratorInterface $urlGenerator A UrlGeneratorInterface instance + * @param UrlMatcherInterface $urlMatcher A UrlMatcherInterface instance */ - public function __construct(RouterInterface $router = null) + public function __construct(UrlGeneratorInterface $urlGenerator = null, UrlMatcherInterface $urlMatcher = null) { - $this->router = $router; + $this->urlGenerator = $urlGenerator; + $this->urlMatcher = $urlMatcher; } /** @@ -49,14 +53,7 @@ class HttpUtils */ public function createRedirectResponse(Request $request, $path, $status = 302) { - if ('/' === $path[0]) { - $path = $request->getUriForPath($path); - } elseif (0 !== strpos($path, 'http')) { - $this->resetLocale($request); - $path = $this->generateUrl($path, true); - } - - return new RedirectResponse($path, $status); + return new RedirectResponse($this->generateUri($request, $path), $status); } /** @@ -69,15 +66,7 @@ class HttpUtils */ public function createRequest(Request $request, $path) { - if ($path && '/' !== $path[0] && 0 !== strpos($path, 'http')) { - $this->resetLocale($request); - $path = $this->generateUrl($path, true); - } - if (0 !== strpos($path, 'http')) { - $path = $request->getUriForPath($path); - } - - $newRequest = Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all()); + $newRequest = Request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all()); if ($session = $request->getSession()) { $newRequest->setSession($session); } @@ -99,7 +88,7 @@ class HttpUtils * Checks that a given path matches the Request. * * @param Request $request A Request instance - * @param string $path A path (an absolute path (/foo) or a route name (foo)) + * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) * * @return Boolean true if the path is the same as the one from the Request, false otherwise */ @@ -107,7 +96,7 @@ class HttpUtils { if ('/' !== $path[0]) { try { - $parameters = $this->router->match($request->getPathInfo()); + $parameters = $this->urlMatcher->match($request->getPathInfo()); return $path === $parameters['_route']; } catch (MethodNotAllowedException $e) { @@ -117,36 +106,36 @@ class HttpUtils } } - return $path === $request->getPathInfo(); + return $path === rawurldecode($request->getPathInfo()); } - // hack (don't have a better solution for now) - private function resetLocale(Request $request) + /** + * Generates a URI, based on the given path or absolute URL. + * + * @param Request $request A Request instance + * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) + * + * @return string An absolute URL + */ + public function generateUri($request, $path) { - $context = $this->router->getContext(); - if ($context->getParameter('_locale')) { - return; + if (0 === strpos($path, 'http') || !$path) { + return $path; } - try { - $parameters = $this->router->match($request->getPathInfo()); - - if (isset($parameters['_locale'])) { - $context->setParameter('_locale', $parameters['_locale']); - } elseif ($session = $request->getSession()) { - $context->setParameter('_locale', $session->getLocale()); - } - } catch (\Exception $e) { - // let's hope user doesn't use the locale in the path + if ('/' === $path[0]) { + return $request->getUriForPath($path); } + + return $this->generateUrl($path, true); } private function generateUrl($route, $absolute = false) { - if (null === $this->router) { - throw new \LogicException('You must provide a RouterInterface instance to be able to use routes.'); + if (null === $this->urlGenerator) { + throw new \LogicException('You must provide a UrlGeneratorInterface instance to be able to use routes.'); } - return $this->router->generate($route, array(), $absolute); + return $this->urlGenerator->generate($route, array(), $absolute); } } diff --git a/Http/Logout/CookieClearingLogoutHandler.php b/Http/Logout/CookieClearingLogoutHandler.php index ddb24e3..6838be5 100644 --- a/Http/Logout/CookieClearingLogoutHandler.php +++ b/Http/Logout/CookieClearingLogoutHandler.php @@ -40,8 +40,6 @@ class CookieClearingLogoutHandler implements LogoutHandlerInterface * @param Request $request * @param Response $response * @param TokenInterface $token - * - * @return void */ public function logout(Request $request, Response $response, TokenInterface $token) { diff --git a/Http/Logout/DefaultLogoutSuccessHandler.php b/Http/Logout/DefaultLogoutSuccessHandler.php new file mode 100644 index 0000000..e06cb6d --- /dev/null +++ b/Http/Logout/DefaultLogoutSuccessHandler.php @@ -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\Logout; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; + +/** + * Default logout success handler will redirect users to a configured path. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Alexander <iam.asm89@gmail.com> + */ +class DefaultLogoutSuccessHandler implements LogoutSuccessHandlerInterface +{ + protected $httpUtils; + protected $targetUrl; + + /** + * @param HttpUtils $httpUtils + * @param string $targetUrl + */ + public function __construct(HttpUtils $httpUtils, $targetUrl = '/') + { + $this->httpUtils = $httpUtils; + + $this->targetUrl = $targetUrl; + } + + /** + * {@inheritDoc} + */ + public function onLogoutSuccess(Request $request) + { + return $this->httpUtils->createRedirectResponse($request, $this->targetUrl); + } +} diff --git a/Http/Logout/LogoutHandlerInterface.php b/Http/Logout/LogoutHandlerInterface.php index 6780e4d..5e1cea8 100644 --- a/Http/Logout/LogoutHandlerInterface.php +++ b/Http/Logout/LogoutHandlerInterface.php @@ -30,8 +30,6 @@ interface LogoutHandlerInterface * @param Request $request * @param Response $response * @param TokenInterface $token - * - * @return void */ public function logout(Request $request, Response $response, TokenInterface $token); } diff --git a/Http/Logout/LogoutSuccessHandlerInterface.php b/Http/Logout/LogoutSuccessHandlerInterface.php index ad878e6..61642a8 100644 --- a/Http/Logout/LogoutSuccessHandlerInterface.php +++ b/Http/Logout/LogoutSuccessHandlerInterface.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Logout; diff --git a/Http/Logout/SessionLogoutHandler.php b/Http/Logout/SessionLogoutHandler.php index 0a7e5cd..e91cf17 100644 --- a/Http/Logout/SessionLogoutHandler.php +++ b/Http/Logout/SessionLogoutHandler.php @@ -28,8 +28,6 @@ class SessionLogoutHandler implements LogoutHandlerInterface * @param Request $request * @param Response $response * @param TokenInterface $token - * - * @return void */ public function logout(Request $request, Response $response, TokenInterface $token) { diff --git a/Http/RememberMe/AbstractRememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php index 92472ee..4f7c5b9 100644 --- a/Http/RememberMe/AbstractRememberMeServices.php +++ b/Http/RememberMe/AbstractRememberMeServices.php @@ -1,5 +1,14 @@ <?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\RememberMe; use Symfony\Component\Security\Core\Exception\AuthenticationException; @@ -15,15 +24,6 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpKernel\Log\LoggerInterface; -/* - * 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. - */ - /** * Base class implementing the RememberMeServicesInterface * @@ -144,8 +144,6 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface * @param Request $request * @param Response $response * @param TokenInterface $token - * - * @return void */ public function logout(Request $request, Response $response, TokenInterface $token) { @@ -157,8 +155,6 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface * an attempted authentication fails. * * @param Request $request - * - * @return void */ final public function loginFail(Request $request) { @@ -173,8 +169,6 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface * @param Request $request * @param Response $response * @param TokenInterface $token The token that resulted in a successful authentication - * - * @return void */ final public function loginSuccess(Request $request, Response $response, TokenInterface $token) { @@ -224,8 +218,6 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface * @param Request $request * @param Response $response * @param TokenInterface $token - * - * @return void */ abstract protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token); @@ -268,8 +260,6 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface * Deletes the remember-me cookie * * @param Request $request - * - * @return void */ protected function cancelCookie(Request $request) { @@ -293,7 +283,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface return true; } - $parameter = $request->request->get($this->options['remember_me_parameter'], null, true); + $parameter = $request->get($this->options['remember_me_parameter'], null, true); if ($parameter === null && null !== $this->logger) { $this->logger->debug(sprintf('Did not send remember-me cookie (remember-me parameter "%s" was not sent).', $this->options['remember_me_parameter'])); diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index e9d22ba..8944672 100644 --- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -1,5 +1,14 @@ <?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\RememberMe; use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface; @@ -11,15 +20,6 @@ use Symfony\Component\Security\Core\Exception\CookieTheftException; use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -/* - * 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. - */ - /** * Concrete implementation of the RememberMeServicesInterface which needs * an implementation of TokenProviderInterface for providing remember-me @@ -35,8 +35,6 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices * Sets the token provider * * @param TokenProviderInterface $tokenProvider - * - * @return void */ public function setTokenProvider(TokenProviderInterface $tokenProvider) { diff --git a/Http/RememberMe/RememberMeServicesInterface.php b/Http/RememberMe/RememberMeServicesInterface.php index 116a6b1..a00dcef 100644 --- a/Http/RememberMe/RememberMeServicesInterface.php +++ b/Http/RememberMe/RememberMeServicesInterface.php @@ -60,8 +60,6 @@ interface RememberMeServicesInterface * This method needs to take care of invalidating the cookie. * * @param Request $request - * - * @return void */ public function loginFail(Request $request); @@ -79,8 +77,6 @@ interface RememberMeServicesInterface * @param Request $request * @param Response $response * @param TokenInterface $token - * - * @return void */ public function loginSuccess(Request $request, Response $response, TokenInterface $token); } diff --git a/Http/RememberMe/ResponseListener.php b/Http/RememberMe/ResponseListener.php new file mode 100644 index 0000000..6cbdcb3 --- /dev/null +++ b/Http/RememberMe/ResponseListener.php @@ -0,0 +1,32 @@ +<?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\RememberMe; + +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; + +/** + * Adds remember-me cookies to the Response. + * + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +class ResponseListener +{ + public function onKernelResponse(FilterResponseEvent $event) + { + $request = $event->getRequest(); + $response = $event->getResponse(); + + if ($request->attributes->has(RememberMeServicesInterface::COOKIE_ATTR_NAME)) { + $response->headers->setCookie($request->attributes->get(RememberMeServicesInterface::COOKIE_ATTR_NAME)); + } + } +} diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php index aa76228..bd828f2 100644 --- a/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/Http/RememberMe/TokenBasedRememberMeServices.php @@ -1,14 +1,5 @@ <?php -namespace Symfony\Component\Security\Http\RememberMe; - -use Symfony\Component\HttpFoundation\Cookie; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\User\UserInterface; - /* * This file is part of the Symfony package. * @@ -18,6 +9,15 @@ use Symfony\Component\Security\Core\User\UserInterface; * file that was distributed with this source code. */ +namespace Symfony\Component\Security\Http\RememberMe; + +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\User\UserInterface; + /** * Concrete implementation of the RememberMeServicesInterface providing * remember-me capabilities without requiring a TokenProvider. diff --git a/Http/Session/SessionAuthenticationStrategy.php b/Http/Session/SessionAuthenticationStrategy.php index 7e0c20a..e9c9826 100644 --- a/Http/Session/SessionAuthenticationStrategy.php +++ b/Http/Session/SessionAuthenticationStrategy.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Session; diff --git a/Http/Session/SessionAuthenticationStrategyInterface.php b/Http/Session/SessionAuthenticationStrategyInterface.php index 38dc343..2bc292b 100644 --- a/Http/Session/SessionAuthenticationStrategyInterface.php +++ b/Http/Session/SessionAuthenticationStrategyInterface.php @@ -1,12 +1,12 @@ <?php /* - * This file is part of the Symfony framework. + * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Session; @@ -32,8 +32,6 @@ interface SessionAuthenticationStrategyInterface * * @param Request $request * @param TokenInterface $token - * - * @return void */ public function onAuthentication(Request $request, TokenInterface $token); } |