Problem/Motivation

Logged in Uses get the "The form has become outdated. Copy any unsaved work in the form below and then reload this page." message, when the search block is submitted.

The validation drupal_valid_token() failed because the form is chached per role (default).

Proposed resolution

Set the block cache to DRUPAL_NO_CACHE. See attached patch.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

elliotttf’s picture

Priority: Normal » Major
Status: Active » Needs review
FileSize
1.01 KB

+1 to the issue.

DRUPAL_NO_CACHE will definitely fix the problem, but it might be worth using DRUPAL_CACHE_PER_USER here. I suspect the overhead of creating more cache entries is less than the overhead associated with rebuilding the form on every page load, but either way I'd like to get some feedback on this issue since it renders the module's blocks useless for sites with block caching enabled.

cangeceiro’s picture

Status: Needs review » Reviewed & tested by the community

patch worked for me as well

drunken monkey’s picture

Title: Search form block - invalid token: "The form has become outdated. ..." » Fix search form block for anonymous users
Status: Reviewed & tested by the community » Fixed

Thanks a lot, committed.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

jamesfk’s picture

Version: 7.x-1.0-beta2 » 7.x-1.0
Issue summary: View changes
Status: Closed (fixed) » Active

I'm still experiencing this problem with 7.x-1.0 with more than one person logged in as the same user. Would NO CACHE be better again?

drunken monkey’s picture

I'm still experiencing this problem with 7.x-1.0 with more than one person logged in as the same user. Would NO CACHE be better again?

Is it possible that's actually the bug reported in #774876: Form cache entries can expire before their host page's cache entry, resulting in all AJAX failing (and in many other locations around the web)? Did you set your cache lifetime to more than six hours?
I'm not sure whether we should work around this by using DRUPAL_NO_CACHE in that case. Or maybe we can circumvent token validation, somehow, since that's not really necessary for a search form anyways?

Jieyyal’s picture

Any updateds for this issue?

I saw this issue was two years ago. But I still experienceing this problem on my D7 site.

So I have to use Block Cache Alter module,
to set the searchapi pages block to DRUPAL_NO_CACHE to work around it.

If the issue won't fix, why we still need this ?

  foreach (search_api_page_load_multiple(FALSE, array('enabled' => TRUE)) as $page) {
    $blocks[$page->machine_name] = array(
      'info' => t('Search block: !name', array('!name' => $page->name)),
      'cache' => DRUPAL_CACHE_PER_ROLE | DRUPAL_CACHE_PER_PAGE,
    );
  }
drunken monkey’s picture

Version: 7.x-1.0 » 7.x-1.x-dev
Status: Active » Needs review
FileSize
374 bytes

It seems the current cache setting was a combination of #2345601: Block caching causes unexpected redirects when submitting empty search form and #2358735: Add access check when viewing the search block, not taking this issue into account. However, I guess the proper fix would in any case be to disable token validation for search forms. I just checked how to do that, and in the code comment explaining it (who needs proper documentation, right?) they actually mention search forms as the prime example of forms that don't need token validation.

So, proposing the attached patch, please test!

drunken monkey’s picture

Could someone please verify that this patch solves the problem?

Jieyyal’s picture

The patch works for me.

Thx.

  • drunken monkey committed a2c6f65 on 7.x-1.x
    Issue #1377292 by drunken monkey: Fixed search form block for anonymous...
drunken monkey’s picture

Status: Needs review » Fixed

Good to hear, thanks a lot for testing!
Committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

jansete’s picture

Hi guys,

Sorry but the patch don't fix the problem.

Token element and token validation is only for forms used by logged users (you can see documentation or view the HTML in your proyects).
With the last patch anonymous has token item and they mustn't have it and produce token_validation outdated error (you can debug drupal_validate_form).

You can see drupal_prepare_form https://api.drupal.org/api/drupal/includes%21form.inc/function/drupal_pr...

Put token as FALSE only avoid token validation if the user is logged.

// Add a token, based on either #token or form_id, to any form displayed to
  // authenticated users. This ensures that any submitted form was actually
  // requested previously by the user and protects against cross site request
  // forgeries.
  // This does not apply to programmatically submitted forms. Furthermore, since
  // tokens are session-bound and forms displayed to anonymous users are very
  // likely cached, we cannot assign a token for them.
  // During installation, there is no $user yet.
  if (!empty($user->uid) && !$form_state['programmed']) {
    // Form constructors may explicitly set #token to FALSE when cross site
    // request forgery is irrelevant to the form, such as search forms.
    if (isset($form['#token']) && $form['#token'] === FALSE) {
      unset($form['#token']);
    }
    // Otherwise, generate a public token based on the form id.
    else {
      $form['#token'] = $form_id;
      $form['form_token'] = array(
        '#id' => drupal_html_id('edit-' . $form_id . '-form-token'),
        '#type' => 'token',
        '#default_value' => drupal_get_token($form['#token']),
        // Form processing and validation requires this value, so ensure the
        // submitted form value appears literally, regardless of custom #tree
        // and #parents being set elsewhere.
        '#parents' => array('form_token'),
      );
    }
  }

So, if we add token = FALSE only for logged users we fixed the problem :)

Attached the patch.

Best regards!

jansete’s picture

Status: Closed (fixed) » Needs review
DamienMcKenna’s picture

Status: Needs review » Reviewed & tested by the community

The patch in #15 fixes the problem, thanks for the patch!

drunken monkey’s picture

I'm sorry, but please could you explain that again? It seems to me what you are saying is that there won't ever be a token for anonymous users. But why would adding $form['#token'] = FALSE; break anything, then? It seems that would just be ignored.
Please explain how adding this could break the form for anonymous users.

jansete’s picture

Hi drunken,

By default Form API don't add $form['#token'] in forms for anonymous users.

If you see the code from drupal_prepare_form, when user is logged in and $form['#token'] === FALSE, then unset($form['#token']) for avoid validation. So for anonymous user if they have $form['#token'] = FALSE, this token will pass to the next step and then in drupal_validate_form (https://api.drupal.org/api/drupal/includes%21form.inc/function/drupal_va...)

// If the session token was set by drupal_prepare_form(), ensure that it
  // matches the current user's session. This is duplicate to code in
  // form_builder() but left to protect any custom form handling code.
  if (isset($form['#token'])) {
    if (!drupal_valid_token($form_state['values']['form_token'], $form['#token']) || !empty($form_state['invalid_token'])) {
      _drupal_invalid_token_set_form_error();
      // Stop here and don't run any further validation handlers, because they
      // could invoke non-safe operations which opens the door for CSRF
      // vulnerabilities.
      $validated_forms[$form_id] = TRUE;
      return;
    }
  }

So for anonymous users when render the form $form['#token'] it's false and don't generate html but $form['#token'] still be in the next steps in $form variable: validation, submission etc.
That's produce try to validate this in drupal_validate_form:
drupal_valid_token($form_state['values']['form_token'], $form['#token']

$form_state['values']['form_token'] don't exist because it was FALSE and didn't render HTML and don't send any value, it's produce outdated error validation.

Use $form['#token']=FALSE only is done for avoid token validation for logged users because in drupal_prepare_form only for logged users unset this variable.

I hope that my explanation was better that the previous, I have tried with my english level :D

Any doubt you can debug with xdebug the following functions when submit the form:
search_api_page_search_form
drupal_prepare_form
drupal_validate_form
drupal_valid_token

Best regards!

zeezhao’s picture

Hi. Also seeing this issue i.e. anonymous search giving the "The form has become outdated. Copy any unsaved work in the form below and then reload this page." error after upgrading search_api & search_api_page to latest.

Please confirm that patch will be committed. Thanks for your help.

  • drunken monkey committed 9ae931f on 7.x-1.x authored by jansete
    Follow-up to #1377292 by jansete, drunken monkey: Fixed search form for...
drunken monkey’s picture

Status: Reviewed & tested by the community » Fixed

Ah, I see. Thanks for explaining again! Seems like a Form API bug to me, then, but I guess we'll just have to work around it.
Committed your patch (with a slight change to the comment).
Thanks again!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.