From a4f05ac7ab35e9c0e0be245ec3cc5033ae13ca48 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 19 Jul 2011 14:50:39 +0200 Subject: [PATCH 1/4] added some tests --- .../Controller/LocalizedController.php | 46 ++++++++++++++++++ .../Resources/config/localized_routing.yml | 19 ++++++++ .../Resources/config/routing.yml | 8 ++++ .../Resources/views/Localized/login.html.twig | 21 +++++++++ .../Tests/Functional/FormLoginTest.php | 36 ++++++++++---- .../Functional/LocalizedRoutesAsPathTest.php | 47 +++++++++++++++++++ .../Tests/Functional/app/AppKernel.php | 32 +++++++++++-- .../app/StandardFormLogin/config.yml | 1 + .../StandardFormLogin/localized_routes.yml | 22 +++++++++ .../app/StandardFormLogin/routes_as_path.yml | 13 +++++ .../app/StandardFormLogin/routing.yml | 3 ++ .../Tests/Functional/app/config/framework.yml | 3 +- 12 files changed, 237 insertions(+), 14 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routes_as_path.yml diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php new file mode 100644 index 0000000000..ee4c47469c --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php @@ -0,0 +1,46 @@ +container->get('request')->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) { + $error = $this->container->get('request')->attributes->get(SecurityContext::AUTHENTICATION_ERROR); + } else { + $error = $this->container->get('request')->getSession()->get(SecurityContext::AUTHENTICATION_ERROR); + } + + return $this->container->get('templating')->renderResponse('FormLoginBundle:Localized:login.html.twig', array( + // last username entered by the user + 'last_username' => $this->container->get('request')->getSession()->get(SecurityContext::LAST_USERNAME), + 'error' => $error, + )); + } + + public function loginCheckAction() + { + throw new \RuntimeException('loginCheckAction() should never be called.'); + } + + public function logoutAction() + { + throw new \RuntimeException('logoutAction() should never be called.'); + } + + public function profileAction() + { + return new Response('Profile'); + } + + public function homepageAction() + { + return new Response('Homepage'); + } +} \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml new file mode 100644 index 0000000000..2c38fee9be --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml @@ -0,0 +1,19 @@ +localized_login_path: + pattern: /{_locale}/login + defaults: { _controller: FormLoginBundle:Localized:login } + +localized_check_path: + pattern: /{_locale}/login_check + defaults: { _controller: FormLoginBundle:Localized:loginCheck } + +localized_default_target_path: + pattern: /{_locale}/profile + defaults: { _controller: FormLoginBundle:Localized:profile } + +localized_logout_path: + pattern: /{_locale}/logout + defaults: { _controller: FormLoginBundle:Localized:logout } + +localized_logout_target_path: + pattern: /{_locale}/ + defaults: { _controller: FormLoginBundle:Localized:homepage } \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml index 21c0841d75..5fab7f17d1 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml @@ -14,6 +14,14 @@ form_login_custom_target_path: pattern: /foo defaults: { _controller: FormLoginBundle:Login:afterLogin } +form_login_default_target_path: + pattern: /profile + defaults: { _controller: FormLoginBundle:Login:afterLogin } + form_login_redirect_to_protected_resource_after_login: pattern: /protected-resource defaults: { _controller: FormLoginBundle:Login:afterLogin } + +form_logout: + pattern: /logout_path + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig new file mode 100644 index 0000000000..60dd2f1ffa --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/views/Localized/login.html.twig @@ -0,0 +1,21 @@ +{% extends "::base.html.twig" %} + +{% block body %} + + {% if error %} +
{{ error.message }}
+ {% endif %} + +
+ + + + + + + + + +
+ +{% endblock %} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php index 5f0ad88097..fe50eb2672 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/FormLoginTest.php @@ -16,25 +16,33 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional; */ class FormLoginTest extends WebTestCase { - public function testFormLogin() + /** + * @dataProvider getConfigs + */ + public function testFormLogin($config) { - $client = $this->createClient(array('test_case' => 'StandardFormLogin')); + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config)); + $client->insulate(); $form = $client->request('GET', '/login')->selectButton('login')->form(); $form['_username'] = 'johannes'; $form['_password'] = 'test'; $client->submit($form); - $this->assertRedirect($client->getResponse(), '/'); + $this->assertRedirect($client->getResponse(), '/profile'); $text = $client->followRedirect()->text(); $this->assertContains('Hello johannes!', $text); - $this->assertContains('You\'re browsing to path "/".', $text); + $this->assertContains('You\'re browsing to path "/profile".', $text); } - public function testFormLoginWithCustomTargetPath() + /** + * @dataProvider getConfigs + */ + public function testFormLoginWithCustomTargetPath($config) { - $client = $this->createClient(array('test_case' => 'StandardFormLogin')); + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config)); + $client->insulate(); $form = $client->request('GET', '/login')->selectButton('login')->form(); $form['_username'] = 'johannes'; @@ -49,9 +57,13 @@ class FormLoginTest extends WebTestCase $this->assertContains('You\'re browsing to path "/foo".', $text); } - public function testFormLoginRedirectsToProtectedResourceAfterLogin() + /** + * @dataProvider getConfigs + */ + public function testFormLoginRedirectsToProtectedResourceAfterLogin($config) { - $client = $this->createClient(array('test_case' => 'StandardFormLogin')); + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config)); + $client->insulate(); $client->request('GET', '/protected-resource'); $this->assertRedirect($client->getResponse(), '/login'); @@ -67,6 +79,14 @@ class FormLoginTest extends WebTestCase $this->assertContains('You\'re browsing to path "/protected-resource".', $text); } + public function getConfigs() + { + return array( + array('config.yml'), + array('routes_as_path.yml'), + ); + } + protected function setUp() { parent::setUp(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php new file mode 100644 index 0000000000..c4502c60dd --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php @@ -0,0 +1,47 @@ +createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml')); + $client->insulate(); + + $crawler = $client->request('GET', '/'.$locale.'/login'); + $form = $crawler->selectButton('login')->form(); + $form['_username'] = 'johannes'; + $form['_password'] = 'test'; + $client->submit($form); + + $this->assertRedirect($client->getResponse(), '/'.$locale.'/profile'); + $this->assertEquals('Profile', $client->followRedirect()->text()); + + $client->request('GET', '/'.$locale.'/logout'); + $this->assertRedirect($client->getResponse(), '/'.$locale.'/'); + $this->assertEquals('Homepage', $client->followRedirect()->text()); + } + + public function getLocales() + { + return array(array('en'), array('de')); + } + + protected function setUp() + { + parent::setUp(); + + $this->deleteTmpDir('StandardFormLogin'); + } + + protected function tearDown() + { + parent::setUp(); + + $this->deleteTmpDir('StandardFormLogin'); + } +} \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php index 7ed45efa1c..cd2445a6da 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/AppKernel.php @@ -11,8 +11,21 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional; -use Symfony\Component\HttpKernel\Util\Filesystem; +// get the autoload file +$dir = __DIR__; +$lastDir = null; +while ($dir !== $lastDir) { + $lastDir = $dir; + if (file_exists($dir.'/autoload.php.dist')) { + require_once $dir.'/autoload.php.dist'; + break; + } + + $dir = dirname($dir); +} + +use Symfony\Component\HttpKernel\Util\Filesystem; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\HttpKernel\Kernel; @@ -33,10 +46,11 @@ class AppKernel extends Kernel } $this->testCase = $testCase; - if (!file_exists($filename = __DIR__.'/'.$testCase.'/'.$rootConfig)) { - throw new \InvalidArgumentException(sprintf('The root config "%s" does not exist.', $filename)); + $fs = new Filesystem(); + if (!$fs->isAbsolutePath($rootConfig) && !file_exists($rootConfig = __DIR__.'/'.$testCase.'/'.$rootConfig)) { + throw new \InvalidArgumentException(sprintf('The root config "%s" does not exist.', $rootConfig)); } - $this->rootConfig = $filename; + $this->rootConfig = $rootConfig; parent::__construct($environment, $debug); } @@ -74,6 +88,16 @@ class AppKernel extends Kernel $loader->load($this->rootConfig); } + public function serialize() + { + return serialize(array($this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug())); + } + + public function unserialize($str) + { + call_user_func_array(array($this, '__construct'), unserialize($str)); + } + protected function getKernelParameters() { $parameters = parent::getKernelParameters(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml index e121c0b4d8..7c60e3c3e4 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml @@ -21,6 +21,7 @@ security: default: form_login: check_path: /login_check + default_target_path: /profile anonymous: ~ access_control: diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml new file mode 100644 index 0000000000..7157f29592 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml @@ -0,0 +1,22 @@ +imports: + - { resource: ./../config/default.yml } + +security: + encoders: + Symfony\Component\Security\Core\User\User: plaintext + + providers: + in_memory: + users: + johannes: { password: test, roles: [ROLE_USER] } + + firewalls: + default: + form_login: + login_path: localized_login_path + check_path: localized_check_path + default_target_path: localized_default_target_path + logout: + path: localized_logout_path + target: localized_logout_target_path + anonymous: ~ \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routes_as_path.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routes_as_path.yml new file mode 100644 index 0000000000..800b8ac4e7 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routes_as_path.yml @@ -0,0 +1,13 @@ +imports: + - { resource: ./config.yml } + +security: + firewalls: + default: + form_login: + login_path: form_login + check_path: form_login_check + default_target_path: form_login_default_target_path + logout: + path: form_logout + target: form_login_homepage \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routing.yml index d3d46d054b..e4f13cf060 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routing.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/routing.yml @@ -1,2 +1,5 @@ _form_login_bundle: resource: @FormLoginBundle/Resources/config/routing.yml + +_form_login_localized: + resource: @FormLoginBundle/Resources/config/localized_routing.yml \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml index 77e9f2241d..4cafd76671 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml @@ -9,9 +9,8 @@ framework: test: ~ session: default_locale: en - lifetime: 3600 auto_start: true - storage_id: session.storage.filesystem + storage_id: session.storage.filesystem services: logger: { class: Symfony\Component\HttpKernel\Log\NullLogger } From f300edebe4c27171a4fc7c6dfd0a71f219a6d850 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 19 Jul 2011 16:21:58 +0200 Subject: [PATCH 2/4] fixes several bugs --- UPDATE.md | 3 + .../Controller/LocalizedController.php | 5 ++ .../Resources/config/localized_routing.yml | 13 ++++- .../Functional/LocalizedRoutesAsPathTest.php | 24 ++++++++ .../SecurityRoutingIntegrationTest.php | 31 +++++++--- .../Tests/Functional/WebTestCase.php | 2 +- .../StandardFormLogin/localized_routes.yml | 6 +- .../localized_routes_with_forward.yml | 9 +++ .../HttpFoundation/RequestMatcher.php | 6 +- .../Component/Security/Http/HttpUtils.php | 57 ++++++++++++++----- .../HttpFoundation/RequestMatcherTest.php | 5 +- .../Component/Security/Http/HttpUtilsTest.php | 11 ++++ 12 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes_with_forward.yml diff --git a/UPDATE.md b/UPDATE.md index 407bc43aa1..459156a8cd 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -77,6 +77,9 @@ RC4 to RC5 Session::getAttributes() -> Session::all() Session::setAttributes() -> Session::replace() +* {_locale} is not supported in paths in the access_control section anymore. You can + rewrite the paths using a regular expression such as "(?:[a-z]{2})". + RC3 to RC4 ---------- diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php index ee4c47469c..7ac6bbdfc8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php @@ -34,6 +34,11 @@ class LocalizedController extends ContainerAware throw new \RuntimeException('logoutAction() should never be called.'); } + public function secureAction() + { + throw new \RuntimeException('secureAction() should never be called.'); + } + public function profileAction() { return new Response('Profile'); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml index 2c38fee9be..803558f300 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/localized_routing.yml @@ -1,19 +1,30 @@ localized_login_path: pattern: /{_locale}/login defaults: { _controller: FormLoginBundle:Localized:login } + requirements: { _locale: "^[a-z]{2}$" } localized_check_path: pattern: /{_locale}/login_check defaults: { _controller: FormLoginBundle:Localized:loginCheck } + requirements: { _locale: "^[a-z]{2}$" } localized_default_target_path: pattern: /{_locale}/profile defaults: { _controller: FormLoginBundle:Localized:profile } + requirements: { _locale: "^[a-z]{2}$" } localized_logout_path: pattern: /{_locale}/logout defaults: { _controller: FormLoginBundle:Localized:logout } + requirements: { _locale: "^[a-z]{2}$" } localized_logout_target_path: pattern: /{_locale}/ - defaults: { _controller: FormLoginBundle:Localized:homepage } \ No newline at end of file + defaults: { _controller: FormLoginBundle:Localized:homepage } + requirements: { _locale: "^[a-z]{2}$" } + +localized_secure_path: + pattern: /{_locale}/secure/ + defaults: { _controller: FormLoginBundle:Localized:secure } + requirements: { _locale: "^[a-z]{2}$" } + \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php index c4502c60dd..1ad67ac542 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LocalizedRoutesAsPathTest.php @@ -26,6 +26,30 @@ class LocalizedRoutesAsPathTest extends WebTestCase $this->assertEquals('Homepage', $client->followRedirect()->text()); } + /** + * @dataProvider getLocales + */ + public function testAccessRestrictedResource($locale) + { + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes.yml')); + $client->insulate(); + + $client->request('GET', '/'.$locale.'/secure/'); + $this->assertRedirect($client->getResponse(), '/'.$locale.'/login'); + } + + /** + * @dataProvider getLocales + */ + public function testAccessRestrictedResourceWithForward($locale) + { + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'localized_routes_with_forward.yml')); + $client->insulate(); + + $crawler = $client->request('GET', '/'.$locale.'/secure/'); + $this->assertEquals(1, count($crawler->selectButton('login')), (string) $client->getResponse()); + } + public function getLocales() { return array(array('en'), array('de')); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php index d066f5aea5..d649d4434d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php @@ -13,25 +13,37 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional; class SecurityRoutingIntegrationTest extends WebTestCase { - public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous() + /** + * @dataProvider getConfigs + */ + public function testRoutingErrorIsNotExposedForProtectedResourceWhenAnonymous($config) { - $client = $this->createClient(array('test_case' => 'StandardFormLogin')); + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config)); + $client->insulate(); $client->request('GET', '/protected_resource'); $this->assertRedirect($client->getResponse(), '/login'); } - public function testRoutingErrorIsExposedWhenNotProtected() + /** + * @dataProvider getConfigs + */ + public function testRoutingErrorIsExposedWhenNotProtected($config) { - $client = $this->createClient(array('test_case' => 'StandardFormLogin')); + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config)); + $client->insulate(); $client->request('GET', '/unprotected_resource'); - $this->assertEquals(404, $client->getResponse()->getStatusCode()); + $this->assertEquals(404, $client->getResponse()->getStatusCode(), (string) $client->getResponse()); } - public function testRoutingErrorIsNotExposedForProtectedResourceWhenLoggedInWithInsufficientRights() + /** + * @dataProvider getConfigs + */ + public function testRoutingErrorIsNotExposedForProtectedResourceWhenLoggedInWithInsufficientRights($config) { - $client = $this->createClient(array('test_case' => 'StandardFormLogin')); + $client = $this->createClient(array('test_case' => 'StandardFormLogin', 'root_config' => $config)); + $client->insulate(); $form = $client->request('GET', '/login')->selectButton('login')->form(); $form['_username'] = 'johannes'; @@ -43,6 +55,11 @@ class SecurityRoutingIntegrationTest extends WebTestCase $this->assertNotEquals(404, $client->getResponse()->getStatusCode()); } + public function getConfigs() + { + return array(array('config.yml'), array('routes_as_path.yml')); + } + protected function setUp() { parent::setUp(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php index 953e9f08b9..c5f4f79355 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php @@ -18,7 +18,7 @@ class WebTestCase extends BaseWebTestCase { static public function assertRedirect($response, $location) { - self::assertTrue($response->isRedirect()); + self::assertTrue($response->isRedirect(), 'Response is not a redirect, got status code: '.$response->getStatusCode()); self::assertEquals('http://localhost'.$location, $response->headers->get('Location')); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml index 7157f29592..291cd2051b 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes.yml @@ -19,4 +19,8 @@ security: logout: path: localized_logout_path target: localized_logout_target_path - anonymous: ~ \ No newline at end of file + anonymous: ~ + + access_control: + - { path: '^/(?:[a-z]{2})/secure/.*', roles: ROLE_USER } + \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes_with_forward.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes_with_forward.yml new file mode 100644 index 0000000000..d57f84e8ef --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/localized_routes_with_forward.yml @@ -0,0 +1,9 @@ +imports: + - { resource: ./localized_routes.yml } + +security: + firewalls: + default: + form_login: + use_forward: true + failure_forward: true diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher.php index dc5a2c34f7..9adf780bcc 100644 --- a/src/Symfony/Component/HttpFoundation/RequestMatcher.php +++ b/src/Symfony/Component/HttpFoundation/RequestMatcher.php @@ -100,11 +100,7 @@ class RequestMatcher implements RequestMatcherInterface } if (null !== $this->path) { - if (null !== $session = $request->getSession()) { - $path = strtr($this->path, array('{_locale}' => $session->getLocale(), '#' => '\\#')); - } else { - $path = str_replace('#', '\\#', $this->path); - } + $path = str_replace('#', '\\#', $this->path); if (!preg_match('#'.$path.'#', $request->getPathInfo())) { return false; diff --git a/src/Symfony/Component/Security/Http/HttpUtils.php b/src/Symfony/Component/Security/Http/HttpUtils.php index 51168cc1e3..3eccb4188b 100644 --- a/src/Symfony/Component/Security/Http/HttpUtils.php +++ b/src/Symfony/Component/Security/Http/HttpUtils.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Http; +use Symfony\Component\Security\Core\SecurityContextInterface; + use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\RouterInterface; @@ -45,22 +47,10 @@ class HttpUtils */ public function createRedirectResponse(Request $request, $path, $status = 302) { - if (0 === strpos($path, '/')) { + if ('/' === $path[0]) { $path = $request->getUriForPath($path); } elseif (0 !== strpos($path, 'http')) { - // hack (don't have a better solution for now) - $context = $this->router->getContext(); - try { - $parameters = $this->router->match($request->getPathInfo()); - } catch (\Exception $e) { - } - - if (isset($parameters['_locale'])) { - $context->setParameter('_locale', $parameters['_locale']); - } elseif ($session = $request->getSession()) { - $context->setParameter('_locale', $session->getLocale()); - } - + $this->resetLocale($request); $path = $this->generateUrl($path, true); } @@ -78,10 +68,26 @@ class HttpUtils public function createRequest(Request $request, $path) { if ($path && '/' !== $path[0] && 0 !== strpos($path, 'http')) { + $this->resetLocale($request); $path = $this->generateUrl($path, true); } - return Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all()); + $newRequest = Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all()); + if ($session = $request->getSession()) { + $newRequest->setSession($session); + } + + if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { + $newRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR)); + } + if ($request->attributes->has(SecurityContextInterface::ACCESS_DENIED_ERROR)) { + $newRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $request->attributes->get(SecurityContextInterface::ACCESS_DENIED_ERROR)); + } + if ($request->attributes->has(SecurityContextInterface::LAST_USERNAME)) { + $newRequest->attributes->set(SecurityContextInterface::LAST_USERNAME, $request->attributes->get(SecurityContextInterface::LAST_USERNAME)); + } + + return $newRequest; } /** @@ -107,6 +113,27 @@ class HttpUtils return $path === $request->getPathInfo(); } + // hack (don't have a better solution for now) + private function resetLocale(Request $request) + { + $context = $this->router->getContext(); + if ($context->getParameter('_locale')) { + return; + } + + 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 + } + } + private function generateUrl($route, $absolute = false) { if (null === $this->router) { diff --git a/tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php b/tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php index 677c286fa8..d807d22893 100644 --- a/tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php +++ b/tests/Symfony/Tests/Component/HttpFoundation/RequestMatcherTest.php @@ -142,7 +142,7 @@ class RequestMatcherTest extends \PHPUnit_Framework_TestCase $this->assertFalse($matcher->matches($request)); } - public function testPathWithLocale() + public function testPathWithLocaleIsNotSupported() { $matcher = new RequestMatcher(); $request = Request::create('/en/login'); @@ -152,9 +152,6 @@ class RequestMatcherTest extends \PHPUnit_Framework_TestCase $request->setSession($session); $matcher->matchPath('^/{_locale}/login$'); - $this->assertTrue($matcher->matches($request)); - - $session->setLocale('de'); $this->assertFalse($matcher->matches($request)); } diff --git a/tests/Symfony/Tests/Component/Security/Http/HttpUtilsTest.php b/tests/Symfony/Tests/Component/Security/Http/HttpUtilsTest.php index cfba0f0094..4bea58e8e2 100644 --- a/tests/Symfony/Tests/Component/Security/Http/HttpUtilsTest.php +++ b/tests/Symfony/Tests/Component/Security/Http/HttpUtilsTest.php @@ -61,6 +61,17 @@ class HttpUtilsTest extends \PHPUnit_Framework_TestCase $this->assertEquals('bar', $subRequest->server->get('Foo')); // route name + $utils = new HttpUtils($router = $this->getMockBuilder('Symfony\Component\Routing\Router')->disableOriginalConstructor()->getMock()); + $router + ->expects($this->once()) + ->method('generate') + ->will($this->returnValue('/foo/bar')) + ; + $router + ->expects($this->any()) + ->method('getContext') + ->will($this->returnValue($this->getMock('Symfony\Component\Routing\RequestContext'))) + ; $subRequest = $utils->createRequest($this->getRequest(), 'foobar'); $this->assertEquals('/foo/bar', $subRequest->getPathInfo()); From d0a175b6cde66199ae06ba6a8d41a37ec0d257f9 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Tue, 19 Jul 2011 20:51:30 +0200 Subject: [PATCH 3/4] fixes #1659 --- .../Functional/AuthenticationCommencingTest.php | 15 +++++++++++++++ .../Controller/LoginController.php | 6 ++++++ .../FormLoginBundle/Resources/config/routing.yml | 3 +++ .../Functional/app/StandardFormLogin/config.yml | 1 + .../Security/Http/Firewall/ExceptionListener.php | 5 +++++ 5 files changed, 30 insertions(+) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php new file mode 100644 index 0000000000..157472fb1e --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php @@ -0,0 +1,15 @@ +createClient(array('test_case' => 'StandardFormLogin', 'root_config' => 'config.yml')); + $client->insulate(); + + $client->request('GET', '/secure-but-not-covered-by-access-control'); + $this->assertRedirect($client->getResponse(), '/login'); + } +} \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php index 2781509dc7..0e48ff2f19 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LoginController.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Controller; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\SecurityContext; use Symfony\Component\DependencyInjection\ContainerAware; @@ -42,4 +43,9 @@ class LoginController extends ContainerAware { return new Response('', 400); } + + public function secureAction() + { + throw new \Exception('Wrapper', 0, new \Exception('Another Wrapper', 0, new AccessDeniedException())); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml index 5fab7f17d1..7660608c08 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml @@ -25,3 +25,6 @@ form_login_redirect_to_protected_resource_after_login: form_logout: pattern: /logout_path +form_secure_action: + pattern: /secure-but-not-covered-by-access-control + defaults: { _controller: FormLoginBundle:Login:secure } \ No newline at end of file diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml index 7c60e3c3e4..f4b21982ac 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml @@ -26,5 +26,6 @@ security: access_control: - { path: ^/unprotected_resource$, roles: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/secure-but-not-covered-by-access-control$, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/highly_protected_resource$, roles: IS_ADMIN } - { path: .*, roles: IS_AUTHENTICATED_FULLY } diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index c75739080f..46ffde83e6 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -76,6 +76,11 @@ class ExceptionListener $exception = $event->getException(); $request = $event->getRequest(); + // determine the actual cause for the exception + while (null !== $previous = $exception->getPrevious()) { + $exception = $previous; + } + if ($exception instanceof AuthenticationException) { if (null !== $this->logger) { $this->logger->info(sprintf('Authentication exception occurred; redirecting to authentication entry point (%s)', $exception->getMessage())); From eae6a773c6ca217eae5f0dd5980e540cf7776586 Mon Sep 17 00:00:00 2001 From: Johannes Schmitt Date: Wed, 20 Jul 2011 08:43:26 +0200 Subject: [PATCH 4/4] fixed wrong case --- .../Tests/Functional/AuthenticationCommencingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php index 157472fb1e..f13ea64134 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/AuthenticationCommencingTest.php @@ -1,6 +1,6 @@