diff options
author | Christian Flothmann <christian.flothmann@xabbuh.de> | 2015-04-03 18:13:34 +0200 |
---|---|---|
committer | Christian Flothmann <christian.flothmann@xabbuh.de> | 2015-09-30 09:55:52 +0200 |
commit | d37cee9ea33b5ece6837253a15d83e0740074bba (patch) | |
tree | 476021f595a02fa111ccd0b29a38dd61cd14ea6a | |
parent | 889a989997c4b038fb4e354e57e35ede82370581 (diff) | |
download | symfony-security-d37cee9ea33b5ece6837253a15d83e0740074bba.zip symfony-security-d37cee9ea33b5ece6837253a15d83e0740074bba.tar.gz symfony-security-d37cee9ea33b5ece6837253a15d83e0740074bba.tar.bz2 |
deprecate finding deep items in request parameters
-rw-r--r-- | Http/Authentication/DefaultAuthenticationFailureHandler.php | 3 | ||||
-rw-r--r-- | Http/Authentication/DefaultAuthenticationSuccessHandler.php | 3 | ||||
-rw-r--r-- | Http/Firewall/LogoutListener.php | 3 | ||||
-rw-r--r-- | Http/Firewall/SimpleFormAuthenticationListener.php | 11 | ||||
-rw-r--r-- | Http/Firewall/UsernamePasswordFormAuthenticationListener.php | 11 | ||||
-rw-r--r-- | Http/ParameterBagUtils.php | 96 | ||||
-rw-r--r-- | Http/RememberMe/AbstractRememberMeServices.php | 3 | ||||
-rw-r--r-- | Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php | 17 | ||||
-rw-r--r-- | Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php | 14 | ||||
-rw-r--r-- | Http/composer.json | 3 |
10 files changed, 147 insertions, 17 deletions
diff --git a/Http/Authentication/DefaultAuthenticationFailureHandler.php b/Http/Authentication/DefaultAuthenticationFailureHandler.php index f8004d6..3e63992 100644 --- a/Http/Authentication/DefaultAuthenticationFailureHandler.php +++ b/Http/Authentication/DefaultAuthenticationFailureHandler.php @@ -17,6 +17,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Security\Http\ParameterBagUtils; /** * Class with the default authentication failure handling logic. @@ -82,7 +83,7 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { - if ($failureUrl = $request->get($this->options['failure_path_parameter'], null, true)) { + if ($failureUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['failure_path_parameter'])) { $this->options['failure_path'] = $failureUrl; } diff --git a/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/Http/Authentication/DefaultAuthenticationSuccessHandler.php index 5fa7071..078a366 100644 --- a/Http/Authentication/DefaultAuthenticationSuccessHandler.php +++ b/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -14,6 +14,7 @@ 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; +use Symfony\Component\Security\Http\ParameterBagUtils; /** * Class with the default authentication success handling logic. @@ -108,7 +109,7 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle return $this->options['default_target_path']; } - if ($targetUrl = $request->get($this->options['target_path_parameter'], null, true)) { + if ($targetUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['target_path_parameter'])) { return $targetUrl; } diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php index 96f5685..6211ee0 100644 --- a/Http/Firewall/LogoutListener.php +++ b/Http/Firewall/LogoutListener.php @@ -24,6 +24,7 @@ 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. @@ -98,7 +99,7 @@ class LogoutListener implements ListenerInterface } if (null !== $this->csrfTokenManager) { - $csrfToken = $request->get($this->options['csrf_parameter'], null, true); + $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { throw new LogoutException('Invalid CSRF token.'); diff --git a/Http/Firewall/SimpleFormAuthenticationListener.php b/Http/Firewall/SimpleFormAuthenticationListener.php index 4733b6a..fedaa4e 100644 --- a/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/Http/Firewall/SimpleFormAuthenticationListener.php @@ -26,6 +26,7 @@ use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterf use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 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; @@ -101,7 +102,7 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener protected function attemptAuthentication(Request $request) { if (null !== $this->csrfTokenManager) { - $csrfToken = $request->get($this->options['csrf_parameter'], null, true); + $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); @@ -109,11 +110,11 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener } if ($this->options['post_only']) { - $username = trim($request->request->get($this->options['username_parameter'], null, true)); - $password = $request->request->get($this->options['password_parameter'], null, true); + $username = trim(ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter'])); + $password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']); } else { - $username = trim($request->get($this->options['username_parameter'], null, true)); - $password = $request->get($this->options['password_parameter'], null, true); + $username = trim(ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter'])); + $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); } $request->getSession()->set(Security::LAST_USERNAME, $username); diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 07ab85a..d20ab19 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -19,6 +19,7 @@ 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; @@ -76,7 +77,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL protected function attemptAuthentication(Request $request) { if (null !== $this->csrfTokenManager) { - $csrfToken = $request->get($this->options['csrf_parameter'], null, true); + $csrfToken = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']); if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); @@ -84,11 +85,11 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL } if ($this->options['post_only']) { - $username = trim($request->request->get($this->options['username_parameter'], null, true)); - $password = $request->request->get($this->options['password_parameter'], null, true); + $username = trim(ParameterBagUtils::getParameterBagValue($request->request, $this->options['username_parameter'])); + $password = ParameterBagUtils::getParameterBagValue($request->request, $this->options['password_parameter']); } else { - $username = trim($request->get($this->options['username_parameter'], null, true)); - $password = $request->get($this->options['password_parameter'], null, true); + $username = trim(ParameterBagUtils::getRequestParameterValue($request, $this->options['username_parameter'])); + $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); } $request->getSession()->set(Security::LAST_USERNAME, $username); diff --git a/Http/ParameterBagUtils.php b/Http/ParameterBagUtils.php new file mode 100644 index 0000000..eed5421 --- /dev/null +++ b/Http/ParameterBagUtils.php @@ -0,0 +1,96 @@ +<?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\ParameterBag; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\PropertyAccess\Exception\AccessException; +use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException; +use Symfony\Component\PropertyAccess\PropertyAccess; + +/** + * @internal + */ +final class ParameterBagUtils +{ + private static $propertyAccessor; + + /** + * Returns a "parameter" value. + * + * Paths like foo[bar] will be evaluated to find deeper items in nested data structures. + * + * @param ParameterBag $parameters The parameter bag + * @param string $path The key + * + * @return mixed + * + * @throws InvalidArgumentException when the given path is malformed + */ + public static function getParameterBagValue(ParameterBag $parameters, $path) + { + if (false === $pos = strpos($path, '[')) { + return $parameters->get($path); + } + + $root = substr($path, 0, $pos); + + if (null === $value = $parameters->get($root)) { + return; + } + + if (null === self::$propertyAccessor) { + self::$propertyAccessor = PropertyAccess::createPropertyAccessor(); + } + + try { + return self::$propertyAccessor->getValue($value, substr($path, $pos)); + } catch (AccessException $e) { + return; + } + } + + /** + * Returns a request "parameter" value. + * + * Paths like foo[bar] will be evaluated to find deeper items in nested data structures. + * + * @param Request $request The request + * @param string $path The key + * + * @return mixed + * + * @throws InvalidArgumentException when the given path is malformed + */ + public static function getRequestParameterValue(Request $request, $path) + { + if (false === $pos = strpos($path, '[')) { + return $request->get($path); + } + + $root = substr($path, 0, $pos); + + if (null === $value = $request->get($root)) { + return; + } + + if (null === self::$propertyAccessor) { + self::$propertyAccessor = PropertyAccess::createPropertyAccessor(); + } + + try { + return self::$propertyAccessor->getValue($value, substr($path, $pos)); + } catch (AccessException $e) { + return; + } + } +} diff --git a/Http/RememberMe/AbstractRememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php index 16810bd..04d95ea 100644 --- a/Http/RememberMe/AbstractRememberMeServices.php +++ b/Http/RememberMe/AbstractRememberMeServices.php @@ -23,6 +23,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Cookie; use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Http\ParameterBagUtils; /** * Base class implementing the RememberMeServicesInterface. @@ -319,7 +320,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface return true; } - $parameter = $request->get($this->options['remember_me_parameter'], null, true); + $parameter = ParameterBagUtils::getRequestParameterValue($request, $this->options['remember_me_parameter']); if (null === $parameter && null !== $this->logger) { $this->logger->debug('Did not send remember-me cookie.', array('parameter' => $this->options['remember_me_parameter'])); diff --git a/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php index 82b5533..2ed8872 100644 --- a/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php +++ b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php @@ -145,7 +145,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas public function testFailurePathCanBeOverwrittenWithRequest() { $this->request->expects($this->once()) - ->method('get')->with('_failure_path', null, true) + ->method('get')->with('_failure_path', null, false) ->will($this->returnValue('/auth/login')); $this->httpUtils->expects($this->once()) @@ -155,12 +155,25 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas $handler->onAuthenticationFailure($this->request, $this->exception); } + public function testFailurePathCanBeOverwrittenWithNestedAttributeInRequest() + { + $this->request->expects($this->once()) + ->method('get')->with('_failure_path', null, false) + ->will($this->returnValue(array('value' => '/auth/login'))); + + $this->httpUtils->expects($this->once()) + ->method('createRedirectResponse')->with($this->request, '/auth/login'); + + $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array('failure_path_parameter' => '_failure_path[value]'), $this->logger); + $handler->onAuthenticationFailure($this->request, $this->exception); + } + public function testFailurePathParameterCanBeOverwritten() { $options = array('failure_path_parameter' => '_my_failure_path'); $this->request->expects($this->once()) - ->method('get')->with('_my_failure_path', null, true) + ->method('get')->with('_my_failure_path', null, false) ->will($this->returnValue('/auth/login')); $this->httpUtils->expects($this->once()) diff --git a/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php index 4d1847d..2c22da6 100644 --- a/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php +++ b/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php @@ -68,6 +68,20 @@ class DefaultAuthenticationSuccessHandlerTest extends \PHPUnit_Framework_TestCas $this->assertSame($response, $result); } + public function testTargetPathIsPassedAsNestedParameterWithRequest() + { + $this->request->expects($this->once()) + ->method('get')->with('_target_path') + ->will($this->returnValue(array('value' => '/dashboard'))); + + $response = $this->expectRedirectResponse('/dashboard'); + + $handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array('target_path_parameter' => '_target_path[value]')); + $result = $handler->onAuthenticationSuccess($this->request, $this->token); + + $this->assertSame($response, $result); + } + public function testTargetPathParameterIsCustomised() { $options = array('target_path_parameter' => '_my_target_path'); diff --git a/Http/composer.json b/Http/composer.json index 43dff2e..c4a4349 100644 --- a/Http/composer.json +++ b/Http/composer.json @@ -20,7 +20,8 @@ "symfony/security-core": "~2.8", "symfony/event-dispatcher": "~2.1|~3.0.0", "symfony/http-foundation": "~2.4|~3.0.0", - "symfony/http-kernel": "~2.4|~3.0.0" + "symfony/http-kernel": "~2.4|~3.0.0", + "symfony/property-access": "~2.3|~3.0.0" }, "require-dev": { "symfony/phpunit-bridge": "~2.7|~3.0.0", |