Issue #2206909 by jhodgdon, dawehner: Regression: Form submit redirects from 403/404 pages are no longer possible.

8.0.x
Alex Pott 2014-04-12 14:23:29 -04:00
parent bf61ca134d
commit 455840f75d
6 changed files with 175 additions and 19 deletions

View File

@ -141,14 +141,8 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn
$system_config = $this->container->get('config.factory')->get('system.site'); $system_config = $this->container->get('config.factory')->get('system.site');
$path = $this->container->get('path.alias_manager')->getSystemPath($system_config->get('page.403')); $path = $this->container->get('path.alias_manager')->getSystemPath($system_config->get('page.403'));
if ($path && $path != $system_path) { 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') { 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 = 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 { else {
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 403), $request->cookies->all(), array(), $request->server->all()); $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'); $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')); $path = $this->container->get('path.alias_manager')->getSystemPath(\Drupal::config('system.site')->get('page.404'));
if ($path && $path != $system_path) { if ($path && $path != $system_path) {
// @todo Um, how do I specify an override URL again? Totally not clear. Do // @todo Um, how do I specify an override URL again? Totally not clear. Do
// that and sub-call the kernel rather than using meah(). // that and sub-call the kernel rather than using meah().
// @todo The create() method expects a slash-prefixed path, but we store a // @todo The create() method expects a slash-prefixed path, but we store a
// normal system path in the site_404 variable. // normal system path in the site_404 variable.
if ($request->getMethod() === 'POST') { 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 = 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 { else {
$subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 404), $request->cookies->all(), array(), $request->server->all()); $subrequest = Request::create($request->getBaseUrl() . '/' . $path, 'GET', array('destination' => $system_path, '_exception_statuscode' => 404), $request->cookies->all(), array(), $request->server->all());

View File

@ -19,12 +19,12 @@ class RedirectTest extends WebTestBase {
* *
* @var array * @var array
*/ */
public static $modules = array('form_test'); public static $modules = array('form_test', 'block');
public static function getInfo() { public static function getInfo() {
return array( return array(
'name' => 'Form redirecting', 'name' => 'Form redirecting',
'description' => 'Tests functionality of drupal_redirect_form().', 'description' => 'Tests form redirection functionality.',
'group' => 'Form API', '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.'); $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.');
}
} }

View File

@ -0,0 +1,43 @@
<?php
/**
* @file
* Contains \Drupal\form_test\Form\RedirectBlockForm.
*/
namespace Drupal\form_test\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Url;
/**
* Builds a simple form that redirects on submit.
*
* @see \Drupal\form_test\Plugin\Block\RedirectFormBlock
*/
class RedirectBlockForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'redirect_block_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$form['actions'] = array('#type' => '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')));
}
}

View File

@ -0,0 +1,79 @@
<?php
/**
* @file
* Contains \Drupal\form_test\Plugin\Block\RedirectFormBlock.
*/
namespace Drupal\form_test\Plugin\Block;
use Drupal\block\BlockBase;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a block containing a simple redirect form.
*
* @see \Drupal\form_test\Form\RedirectBlockForm
*
* @Block(
* id = "redirect_form_block",
* admin_label = @Translation("Redirecting form"),
* category = @Translation("Forms")
* )
*/
class RedirectFormBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The form builder.
*
* @var \Drupal\Core\Form\FormBuilderInterface
*/
protected $formBuilder;
/**
* Constructs a new RedirectFormBlock.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
* The form builder.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, FormBuilderInterface $form_builder) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->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');
}
}

View File

@ -116,10 +116,17 @@ class UserLoginForm extends FormBase {
*/ */
public function submitForm(array &$form, array &$form_state) { public function submitForm(array &$form, array &$form_state) {
$account = $this->userStorage->load($form_state['uid']); $account = $this->userStorage->load($form_state['uid']);
$form_state['redirect_route'] = array(
'route_name' => 'user.view', // A destination was set, probably on an exception controller,
'route_parameters' => array('user' => $account->id()), 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); user_login_finalize($account);
} }

View File

@ -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. * Test the global login flood control.
*/ */