From 18dfe37ac1a8f87b71c3dda1aabafe88ee22845e Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sat, 6 Feb 2016 17:29:58 -0500 Subject: [PATCH] Adding new TargetPathTrait to get/set the authentication "target_path" --- .../AbstractFormLoginAuthenticator.php | 5 +- .../DefaultAuthenticationSuccessHandler.php | 7 +- .../Http/Firewall/ExceptionListener.php | 5 +- .../Http/Tests/Util/TargetPathTraitTest.php | 76 +++++++++++++++++++ .../Security/Http/Util/TargetPathTrait.php | 58 ++++++++++++++ 5 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Component/Security/Http/Tests/Util/TargetPathTraitTest.php create mode 100644 src/Symfony/Component/Security/Http/Util/TargetPathTrait.php diff --git a/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php b/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php index b3c6bd73a0a9..cefafc1e542f 100644 --- a/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php +++ b/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php @@ -17,6 +17,7 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Security; +use Symfony\Component\Security\Http\Util\TargetPathTrait; /** * A base class to make form login authentication easier! @@ -25,6 +26,8 @@ */ abstract class AbstractFormLoginAuthenticator extends AbstractGuardAuthenticator { + use TargetPathTrait; + /** * Return the URL to the login page. * @@ -71,7 +74,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token, { // if the user hit a secure page and start() was called, this was // the URL they were on, and probably where you want to redirect to - $targetPath = $request->getSession()->get('_security.'.$providerKey.'.target_path'); + $targetPath = $this->getTargetPath($request->getSession(), $providerKey); if (!$targetPath) { $targetPath = $this->getDefaultSuccessRedirectUrl(); diff --git a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php index 078a3663847d..38690c7e5186 100644 --- a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php +++ b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -13,6 +13,7 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\Util\TargetPathTrait; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\ParameterBagUtils; @@ -25,6 +26,8 @@ */ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface { + use TargetPathTrait; + protected $httpUtils; protected $options; protected $providerKey; @@ -113,8 +116,8 @@ protected function determineTargetUrl(Request $request) return $targetUrl; } - if (null !== $this->providerKey && $targetUrl = $request->getSession()->get('_security.'.$this->providerKey.'.target_path')) { - $request->getSession()->remove('_security.'.$this->providerKey.'.target_path'); + if (null !== $this->providerKey && $targetUrl = $this->getTargetPath($request->getSession(), $this->providerKey)) { + $this->removeTargetPath($request->getSession(), $this->providerKey); return $targetUrl; } diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index a1cae2a43721..2804d0e820b5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -22,6 +22,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; use Symfony\Component\Security\Core\Exception\LogoutException; +use Symfony\Component\Security\Http\Util\TargetPathTrait; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\HttpFoundation\Request; use Psr\Log\LoggerInterface; @@ -39,6 +40,8 @@ */ class ExceptionListener { + use TargetPathTrait; + private $tokenStorage; private $providerKey; private $accessDeniedHandler; @@ -210,7 +213,7 @@ protected function setTargetPath(Request $request) { // session isn't required when using HTTP basic authentication mechanism for example if ($request->hasSession() && $request->isMethodSafe() && !$request->isXmlHttpRequest()) { - $request->getSession()->set('_security.'.$this->providerKey.'.target_path', $request->getUri()); + $this->saveTargetPath($request->getSession(), $this->providerKey, $request->getUri()); } } } diff --git a/src/Symfony/Component/Security/Http/Tests/Util/TargetPathTraitTest.php b/src/Symfony/Component/Security/Http/Tests/Util/TargetPathTraitTest.php new file mode 100644 index 000000000000..b2c4dc72c9d8 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Tests/Util/TargetPathTraitTest.php @@ -0,0 +1,76 @@ +getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface') + ->getMock(); + + $session->expects($this->once()) + ->method('set') + ->with('_security.firewall_name.target_path', '/foo'); + + $obj->doSetTargetPath($session, 'firewall_name', '/foo'); + } + + public function testGetTargetPath() + { + $obj = new TestClassWithTargetPathTrait(); + + $session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface') + ->getMock(); + + $session->expects($this->once()) + ->method('get') + ->with('_security.cool_firewall.target_path') + ->willReturn('/bar'); + + $actualUri = $obj->doGetTargetPath($session, 'cool_firewall'); + $this->assertEquals( + '/bar', + $actualUri + ); + } + + public function testRemoveTargetPath() + { + $obj = new TestClassWithTargetPathTrait(); + + $session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface') + ->getMock(); + + $session->expects($this->once()) + ->method('remove') + ->with('_security.best_firewall.target_path'); + + $obj->doRemoveTargetPath($session, 'best_firewall'); + } +} + +class TestClassWithTargetPathTrait +{ + use TargetPathTrait; + + public function doSetTargetPath(SessionInterface $session, $providerKey, $uri) + { + $this->saveTargetPath($session, $providerKey, $uri); + } + + public function doGetTargetPath(SessionInterface $session, $providerKey) + { + return $this->getTargetPath($session, $providerKey); + } + + public function doRemoveTargetPath(SessionInterface $session, $providerKey) + { + $this->removeTargetPath($session, $providerKey); + } +} diff --git a/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php b/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php new file mode 100644 index 000000000000..62a196ea537c --- /dev/null +++ b/src/Symfony/Component/Security/Http/Util/TargetPathTrait.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Util; + +use Symfony\Component\HttpFoundation\Session\SessionInterface; + +/** + * Trait to get (and set) the URL the user last visited before being forced to authenticate. + */ +trait TargetPathTrait +{ + /** + * Set the target path the user should be redirected to after authentication. + * + * Usually, you do not need to set this directly. + * + * @param SessionInterface $session + * @param string $providerKey The name of your firewall + * @param string $uri The URI to set as the target path + */ + private function saveTargetPath(SessionInterface $session, $providerKey, $uri) + { + $session->set('_security.'.$providerKey.'.target_path', $uri); + } + + /** + * Returns the URL (if any) the user visited that forced them to login. + * + * @param SessionInterface $session + * @param string $providerKey The name of your firewall + * + * @return string + */ + private function getTargetPath(SessionInterface $session, $providerKey) + { + return $session->get('_security.'.$providerKey.'.target_path'); + } + + /** + * Removes the target path from the session. + * + * @param SessionInterface $session + * @param string $providerKey The name of your firewall + */ + private function removeTargetPath(SessionInterface $session, $providerKey) + { + $session->remove('_security.'.$providerKey.'.target_path'); + } +}