From 455840f75d75722e15000e17c7f53ac0852ffd72 Mon Sep 17 00:00:00 2001 From: Alex Pott Date: Sat, 12 Apr 2014 14:23:29 -0400 Subject: [PATCH] Issue #2206909 by jhodgdon, dawehner: Regression: Form submit redirects from 403/404 pages are no longer possible. --- .../Core/Controller/ExceptionController.php | 13 --- .../Drupal/system/Tests/Form/RedirectTest.php | 32 +++++++- .../form_test/Form/RedirectBlockForm.php | 43 ++++++++++ .../Plugin/Block/RedirectFormBlock.php | 79 +++++++++++++++++++ .../lib/Drupal/user/Form/UserLoginForm.php | 15 +++- .../lib/Drupal/user/Tests/UserLoginTest.php | 12 +++ 6 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/RedirectBlockForm.php create mode 100644 core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Plugin/Block/RedirectFormBlock.php diff --git a/core/lib/Drupal/Core/Controller/ExceptionController.php b/core/lib/Drupal/Core/Controller/ExceptionController.php index d79567c3ba9..5e9d2165471 100644 --- a/core/lib/Drupal/Core/Controller/ExceptionController.php +++ b/core/lib/Drupal/Core/Controller/ExceptionController.php @@ -141,14 +141,8 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn $system_config = $this->container->get('config.factory')->get('system.site'); $path = $this->container->get('path.alias_manager')->getSystemPath($system_config->get('page.403')); if ($path && $path != $system_path) { - // Keep old path for reference, and to allow forms to redirect to it. - if (!$request->query->has('destination')) { - $request->query->set('destination', $system_path); - } - if ($request->getMethod() === 'POST') { $subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'POST', array('destination' => $system_path, '_exception_statuscode' => 403) + $request->request->all(), $request->cookies->all(), array(), $request->server->all()); - $subrequest->query->set('destination', $system_path); } else { $subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 403), $request->cookies->all(), array(), $request->server->all()); @@ -217,21 +211,14 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn $system_path = $request->attributes->get('_system_path'); - // Keep old path for reference, and to allow forms to redirect to it. - if (!$request->query->has('destination')) { - $request->query->set('destination', $system_path); - } - $path = $this->container->get('path.alias_manager')->getSystemPath(\Drupal::config('system.site')->get('page.404')); if ($path && $path != $system_path) { // @todo Um, how do I specify an override URL again? Totally not clear. Do // that and sub-call the kernel rather than using meah(). // @todo The create() method expects a slash-prefixed path, but we store a // normal system path in the site_404 variable. - if ($request->getMethod() === 'POST') { $subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'POST', array('destination' => $system_path, '_exception_statuscode' => 404) + $request->request->all(), $request->cookies->all(), array(), $request->server->all()); - $subrequest->query->set('destination', $system_path); } else { $subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 404), $request->cookies->all(), array(), $request->server->all()); diff --git a/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php b/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php index 52f71d40c49..faa7c7ce2d5 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Form/RedirectTest.php @@ -19,12 +19,12 @@ class RedirectTest extends WebTestBase { * * @var array */ - public static $modules = array('form_test'); + public static $modules = array('form_test', 'block'); public static function getInfo() { return array( 'name' => 'Form redirecting', - 'description' => 'Tests functionality of drupal_redirect_form().', + 'description' => 'Tests form redirection functionality.', 'group' => 'Form API', ); } @@ -85,4 +85,32 @@ class RedirectTest extends WebTestBase { $this->assertUrl($path, $options, 'When using an empty redirection string, there should be no redirection, and the query parameters should be passed along.'); } + /** + * Tests form redirection from 404/403 pages with the Block form. + */ + public function testRedirectFromErrorPages() { + // Make sure the block containing the redirect form is placed. + $this->drupalPlaceBlock('redirect_form_block'); + + // Create a user that does not have permission to administer blocks. + $user = $this->drupalCreateUser(array('administer themes')); + $this->drupalLogin($user); + + // Visit page 'foo' (404 page) and submit the form. Verify it ends up + // at the right URL. + $expected = \Drupal::url('form_test.route1', array(), array('query' => array('test1' => 'test2'), 'absolute' => TRUE)); + $this->drupalGet('foo'); + $this->assertResponse(404); + $this->drupalPostForm(NULL, array(), t('Submit')); + $this->assertResponse(200); + $this->assertEqual($this->getUrl(), $expected, 'Redirected to correct url/query.'); + + // Visit the block admin page (403 page) and submit the form. Verify it + // ends up at the right URL. + $this->drupalGet('admin/structure/block'); + $this->assertResponse(403); + $this->drupalPostForm(NULL, array(), t('Submit')); + $this->assertResponse(200); + $this->assertEqual($this->getUrl(), $expected, 'Redirected to correct url/query.'); + } } diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/RedirectBlockForm.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/RedirectBlockForm.php new file mode 100644 index 00000000000..7d134d04325 --- /dev/null +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Form/RedirectBlockForm.php @@ -0,0 +1,43 @@ + 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Submit')); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $form_state['redirect_route'] = new Url('form_test.route1', array(), array('query' => array('test1' => 'test2'))); + } +} diff --git a/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Plugin/Block/RedirectFormBlock.php b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Plugin/Block/RedirectFormBlock.php new file mode 100644 index 00000000000..9703f4c6e0b --- /dev/null +++ b/core/modules/system/tests/modules/form_test/lib/Drupal/form_test/Plugin/Block/RedirectFormBlock.php @@ -0,0 +1,79 @@ +formBuilder = $form_builder; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('form_builder') + ); + } + + /** + * {@inheritdoc} + */ + public function access(AccountInterface $account) { + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function build() { + return $this->formBuilder->getForm('Drupal\form_test\Form\RedirectBlockForm'); + } +} diff --git a/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php index 4dd180f5702..58e0ba25e55 100644 --- a/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php +++ b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php @@ -116,10 +116,17 @@ class UserLoginForm extends FormBase { */ public function submitForm(array &$form, array &$form_state) { $account = $this->userStorage->load($form_state['uid']); - $form_state['redirect_route'] = array( - 'route_name' => 'user.view', - 'route_parameters' => array('user' => $account->id()), - ); + + // A destination was set, probably on an exception controller, + if (!$this->request->request->has('destination')) { + $form_state['redirect_route'] = array( + 'route_name' => 'user.view', + 'route_parameters' => array('user' => $account->id()), + ); + } + else { + $this->request->query->set('destination', $this->request->request->get('destination')); + } user_login_finalize($account); } diff --git a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php index 33ab74c7a6c..8016987f38d 100644 --- a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php +++ b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php @@ -22,6 +22,18 @@ class UserLoginTest extends WebTestBase { ); } + /** + * Tests login with destination. + */ + function testLoginDestination() { + $user = $this->drupalCreateUser(array()); + $this->drupalGet('user', array('query' => array('destination' => 'foo'))); + $edit = array('name' => $user->getUserName(), 'pass' => $user->pass_raw); + $this->drupalPostForm(NULL, $edit, t('Log in')); + $expected = url('foo', array('absolute' => TRUE)); + $this->assertEqual($this->getUrl(), $expected, 'Redirected to the correct URL'); + } + /** * Test the global login flood control. */