summaryrefslogtreecommitdiffstats
path: root/Http
diff options
context:
space:
mode:
authorFabien Potencier <fabien.potencier@gmail.com>2011-06-20 07:08:46 +0200
committerFabien Potencier <fabien.potencier@gmail.com>2011-06-22 14:47:19 +0200
commit100bc023abb4c1908b0d468dda6869e47494e355 (patch)
tree2780db9d5ab963bd0c8216622c647771f343fc64 /Http
parent2ebfd97612d3d5ef4fc6f632b27a242eed8a1f0f (diff)
downloadsymfony-security-100bc023abb4c1908b0d468dda6869e47494e355.zip
symfony-security-100bc023abb4c1908b0d468dda6869e47494e355.tar.gz
symfony-security-100bc023abb4c1908b0d468dda6869e47494e355.tar.bz2
[Security] added an HttpUtils class to manage logic related to Requests and Responses
This change removes the need for the {_locale} hack. Now, all paths in the Security component can be: * An absolute path (/login) * An absolute URL (http://symfony.com/login) * A route name (login) So, if you want to use a path that includes a global parameter (like _locale), use a route instead of a path.
Diffstat (limited to 'Http')
-rw-r--r--Http/EntryPoint/FormAuthenticationEntryPoint.php13
-rw-r--r--Http/Firewall/AbstractAuthenticationListener.php22
-rw-r--r--Http/Firewall/ExceptionListener.php9
-rw-r--r--Http/Firewall/LogoutListener.php17
-rw-r--r--Http/Firewall/UsernamePasswordFormAuthenticationListener.php5
-rw-r--r--Http/HttpUtils.php99
6 files changed, 135 insertions, 30 deletions
diff --git a/Http/EntryPoint/FormAuthenticationEntryPoint.php b/Http/EntryPoint/FormAuthenticationEntryPoint.php
index 6301606..1a35784 100644
--- a/Http/EntryPoint/FormAuthenticationEntryPoint.php
+++ b/Http/EntryPoint/FormAuthenticationEntryPoint.php
@@ -12,10 +12,9 @@
namespace Symfony\Component\Security\Http\EntryPoint;
use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
@@ -28,17 +27,20 @@ class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface
private $loginPath;
private $useForward;
private $httpKernel;
+ private $httpUtils;
/**
* Constructor
*
* @param HttpKernelInterface $kernel
+ * @param HttpUtils $httpUtils An HttpUtils instance
* @param string $loginPath The path to the login form
* @param Boolean $useForward Whether to forward or redirect to the login form
*/
- public function __construct(HttpKernelInterface $kernel, $loginPath, $useForward = false)
+ public function __construct(HttpKernelInterface $kernel, HttpUtils $httpUtils, $loginPath, $useForward = false)
{
$this->httpKernel = $kernel;
+ $this->httpUtils = $httpUtils;
$this->loginPath = $loginPath;
$this->useForward = (Boolean) $useForward;
}
@@ -48,13 +50,12 @@ class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface
*/
public function start(Request $request, AuthenticationException $authException = null)
{
- $path = str_replace('{_locale}', $request->getSession()->getLocale(), $this->loginPath);
if ($this->useForward) {
- $subRequest = Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all());
+ $path = $this->httpUtils->createRequest($request, $this->loginPath);
return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
- return new RedirectResponse(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302);
+ return $this->httpUtils->createRedirectResponse($request, $this->loginPath);
}
}
diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php
index 4cbd6dd..52aff57 100644
--- a/Http/Firewall/AbstractAuthenticationListener.php
+++ b/Http/Firewall/AbstractAuthenticationListener.php
@@ -24,11 +24,11 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpFoundation\RedirectResponse;
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
@@ -59,6 +59,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
private $successHandler;
private $failureHandler;
private $rememberMeServices;
+ private $httpUtils;
/**
* Constructor.
@@ -66,6 +67,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
* @param SecurityContextInterface $securityContext A SecurityContext instance
* @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance
* @param SessionAuthenticationStrategyInterface $sessionStrategy
+ * @param HttpUtils $httpUtils An HttpUtilsInterface instance
* @param string $providerKey
* @param array $options An array of options for the processing of a
* successful, or failed authentication attempt
@@ -74,7 +76,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
* @param LoggerInterface $logger A LoggerInterface instance
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
*/
- public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $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, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
@@ -98,6 +100,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
), $options);
$this->logger = $logger;
$this->dispatcher = $dispatcher;
+ $this->httpUtils = $httpUtils;
}
/**
@@ -165,7 +168,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
*/
protected function requiresAuthentication(Request $request)
{
- return str_replace('{_locale}', $request->getSession()->getLocale(), $this->options['check_path']) === $request->getPathInfo();
+ return $this->httpUtils->checkRequestPath($request, $this->options['check_path']);
}
/**
@@ -195,26 +198,24 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
$this->options['failure_path'] = $this->options['login_path'];
}
- $path = str_replace('{_locale}', $request->getSession()->getLocale(), $this->options['failure_path']);
-
if ($this->options['failure_forward']) {
if (null !== $this->logger) {
- $this->logger->debug(sprintf('Forwarding to %s', $path));
+ $this->logger->debug(sprintf('Forwarding to %s', $this->options['failure_path']));
}
- $subRequest = Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all());
+ $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']);
$subRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $failed);
return $event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
if (null !== $this->logger) {
- $this->logger->debug(sprintf('Redirecting to %s', $path));
+ $this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path']));
}
$request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $failed);
- return new RedirectResponse(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302);
+ return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']);
}
private function onSuccess(GetResponseEvent $event, Request $request, TokenInterface $token)
@@ -237,8 +238,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface
if (null !== $this->successHandler) {
$response = $this->successHandler->onAuthenticationSuccess($request, $token);
} else {
- $path = str_replace('{_locale}', $session->getLocale(), $this->determineTargetUrl($request));
- $response = new RedirectResponse(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302);
+ $response = $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request));
}
if (null !== $this->rememberMeServices) {
diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php
index 5242815..737d644 100644
--- a/Http/Firewall/ExceptionListener.php
+++ b/Http/Firewall/ExceptionListener.php
@@ -16,12 +16,13 @@ use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
-use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException;
+use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
@@ -41,11 +42,13 @@ class ExceptionListener
private $authenticationTrustResolver;
private $errorPage;
private $logger;
+ private $httpUtils;
- public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null)
+ public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null)
{
$this->context = $context;
$this->accessDeniedHandler = $accessDeniedHandler;
+ $this->httpUtils = $httpUtils;
$this->authenticationEntryPoint = $authenticationEntryPoint;
$this->authenticationTrustResolver = $trustResolver;
$this->errorPage = $errorPage;
@@ -115,7 +118,7 @@ class ExceptionListener
return;
}
- $subRequest = Request::create($this->errorPage, 'get', array(), $request->cookies->all(), array(), $request->server->all());
+ $subRequest = $this->httpUtils->createRequest($request, $this->errorPage);
$subRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $exception);
$response = $event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php
index e1a5f3d..06454a3 100644
--- a/Http/Firewall/LogoutListener.php
+++ b/Http/Firewall/LogoutListener.php
@@ -15,6 +15,7 @@ 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\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -31,18 +32,21 @@ class LogoutListener implements ListenerInterface
private $targetUrl;
private $handlers;
private $successHandler;
+ private $httpUtils;
/**
* Constructor
*
* @param SecurityContextInterface $securityContext
- * @param string $logoutPath The path that starts the logout process
- * @param string $targetUrl The URL to redirect to after logout
+ * @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
*/
- public function __construct(SecurityContextInterface $securityContext, $logoutPath, $targetUrl = '/', LogoutSuccessHandlerInterface $successHandler = null)
+ public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, $logoutPath, $targetUrl = '/', LogoutSuccessHandlerInterface $successHandler = null)
{
$this->securityContext = $securityContext;
+ $this->httpUtils = $httpUtils;
$this->logoutPath = $logoutPath;
$this->targetUrl = $targetUrl;
$this->successHandler = $successHandler;
@@ -69,10 +73,7 @@ class LogoutListener implements ListenerInterface
{
$request = $event->getRequest();
- $logoutPath = str_replace('{_locale}', $request->getSession()->getLocale(), $this->logoutPath);
- $targetUrl = str_replace('{_locale}', $request->getSession()->getLocale(), $this->targetUrl);
-
- if ($logoutPath !== $request->getPathInfo()) {
+ if (!$this->httpUtils->checkRequestPath($request, $this->logoutPath)) {
return;
}
@@ -83,7 +84,7 @@ class LogoutListener implements ListenerInterface
throw new \RuntimeException('Logout Success Handler did not return a Response.');
}
} else {
- $response = new RedirectResponse(0 !== strpos($targetUrl, 'http') ? $request->getUriForPath($targetUrl) : $targetUrl, 302);
+ $response = $this->httpUtils->createRedirectResponse($request, $this->targetUrl);
}
// handle multiple logout attempts gracefully
diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
index a6b6968..bd2cec1 100644
--- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
+++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
@@ -17,6 +17,7 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
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\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
@@ -36,9 +37,9 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
/**
* {@inheritdoc}
*/
- public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $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, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
{
- parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $providerKey, array_merge(array(
+ parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, array_merge(array(
'username_parameter' => '_username',
'password_parameter' => '_password',
'csrf_parameter' => '_csrf_token',
diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php
new file mode 100644
index 0000000..6b674aa
--- /dev/null
+++ b/Http/HttpUtils.php
@@ -0,0 +1,99 @@
+<?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;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+/**
+ * Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class HttpUtils
+{
+ private $urlGenerator;
+
+ /**
+ * Constructor.
+ *
+ * @param UrlGeneratorInterface $urlGenerator An UrlGeneratorInterface instance
+ */
+ public function __construct(UrlGeneratorInterface $urlGenerator = null)
+ {
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ /**
+ * Creates a redirect Response.
+ *
+ * @param Request $request A Request instance
+ * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
+ * @param integer $status The status code
+ *
+ * @return Response A RedirectResponse instance
+ */
+ public function createRedirectResponse(Request $request, $path, $status = 302)
+ {
+ if (0 === strpos($path, '/')) {
+ $path = $request->getUriForPath($path);
+ } elseif (0 !== strpos($path, 'http')) {
+ $path = $this->generateUrl($path, true);
+ }
+
+ return new RedirectResponse($path, 302);
+ }
+
+ /**
+ * Creates a Request.
+ *
+ * @param Request $request The current Request instance
+ * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
+ *
+ * @return Request A Request instance
+ */
+ public function createRequest(Request $request, $path)
+ {
+ if ($path && '/' !== $path[0] && 0 !== strpos($path, 'http')) {
+ $path = $this->generateUrl($path, true);
+ }
+
+ return Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all());
+ }
+
+ /**
+ * Checks that a given path matches the Request.
+ *
+ * @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 Boolean true if the path is the same as the one from the Request, false otherwise
+ */
+ public function checkRequestPath(Request $request, $path)
+ {
+ if ('/' !== $path[0]) {
+ $path = preg_replace('#'.preg_quote($request->getBaseUrl(), '#').'#', '', $this->generateUrl($path));
+ }
+
+ return $path === $request->getPathInfo();
+ }
+
+ private function generateUrl($route, $absolute = false)
+ {
+ if (null === $this->urlGenerator) {
+ throw new \LogicException('You must provide a UrlGeneratorInterface instance to be able to use routes.');
+ }
+
+ return $this->urlGenerator->generate($route, array(), $absolute);
+ }
+}