erm, first attempt - sounded easy, but apparently, form rebuilding, caching, re-using, restoring, and alteration after #process on $complete_form doesn't work out (and I had to code to find this out :P )

Don't try this at home.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sun’s picture

Issue tags: +API clean-up
FileSize
49.55 KB

To provide some clues:

The idea was to rebuild the user account (and user cancellation form) in case the user tries to change the e-mail or password, or wants to kill his account.

The screenshot shows the form after submission. Actually, only the current password field should have been there, but apparently, #process can't alter the complete form during processing of child elements.

sun’s picture

This should give you some more clues:

current-password-2a.png

current-password-2b.png

current-password-2c.png

Almost done.

sun’s picture

Status: Needs work » Needs review
FileSize
7.45 KB

well, "almost". ;)

I hope chx, eaton, and/or frando are able to kick in.

sun’s picture

Solving this === killing confirm_form(), btw.

Status: Needs review » Needs work

The last submitted patch failed testing.

RobLoach’s picture

Issue tags: +form API

Die confirm_form(), DIE! +1 Subscribe!... Love that paranoia patch.

sun’s picture

Concept.

Problem

  1. Users can change their password and e-mail address without any confirmation. The expected confirmation for both would be to provide the current password.
  2. Users have to go through heaps to cancel their account, wait for an e-mail, click on a specially crafted link in that e-mail to get back to the site, and on there, click another confirmation form button to confirm the action. Providing the current password would be sufficient to confirm the action.
  3. Confirmation forms, in general, are a very ugly construct,

Details

  • My primary interest is to kill the ugly user account cancellation process. If that means that we can kill the ugly confirm_form() construct (which dates back to Drupal 4.x or even earlier), awesome. (And it's very likely that it will.)
  • There are 2 ways to let a user enter/confirm an action by entering his current password:
    1. Just squeeze a damn 'password' field into the form, using a #element_validate handler that checks against the user's current password.

      This, however, doesn't really work out. On the user account form, we have two form elements (e-mail and password) that should require the current password to confirm. So we'd need either a separate "Current password" field for each of those, or we'd move both fields into a new fieldset, which also contains a new "Current password" field to confirm one of both or both changes. To do that, we'd probably use a custom #confirm_elements property on that "Current password" form element, which references to the other elements in the form that need the advanced validation/confirmation in case their value has been changed.

      However, that sounds a bit awkward.

    2. Use a #process or #element_validate form element handler on form elements that need confirmation. Whenever the user submits a value for that element that differs from the #default_value, display a confirmation form that replaces the original form. The confirmation form may additionally contain a "Current password" form element that requires the user to type in his current password to confirm the action (or any other form elements). When the confirmation form is submitted, take the submitted values, merge the originally submitted form values on top of it, and execute form submit handlers.

      This would be the very first multi-step form implementation in core, AFAICS. So, ++DX.

  • On the UX-side, both approaches are seen on the net. For Drupal, the second one seems a lot more suitable, because we already have that confirmation form construct.

Problems (current patch)

  1. All top-level form elements are set to #access = FALSE in case a form element value requiring the current password is altered, because the idea was to just hide them, but keep their submitted values. However, when the confirmation form containing the current password is submitted, I'm trying to merge back the original form values from $form_state['storage'] in a #element_validate handler of the "Current password" element.

    That would work, if there were not elements like #type = 'password_confirm', which apparently seem to be processed somewhere from their original array-based values in POST into $form_state['input']. "somewhere" means I have no clue where that happens.

  2. Not sure whether it's a good idea to set #access = FALSE for all original form elements (only regarding hook_form_alter(), not UX). I tried to think of alternative ways, but did not have a better idea.

Amendments

  • Current confirm_form() signature:
    function confirm_form($form, $question, $path, $description = NULL, $yes = NULL, $no = NULL, $name = 'confirm') {
    
  • Current example of confirmation form usage:
    function node_form($form, &$form_state, $node) {
      if (!empty($node->nid) && node_access('delete', $node)) {
        $form['buttons']['delete'] = array(
          '#type' => 'submit',
          '#value' => t('Delete'),
          '#weight' => 15,
          '#submit' => array('node_form_delete_submit'),
        );
      }
    }
    
    function node_form_delete_submit($form, &$form_state) {
      $destination = '';
      if (isset($_GET['destination'])) {
        $destination = drupal_get_destination();
        unset($_GET['destination']);
      }
      $node = $form['#node'];
      $form_state['redirect'] = array('node/' . $node->nid . '/delete', $destination);
    }
    
    function node_delete_confirm($form, &$form_state, $node) {
      $form['nid'] = array(
        '#type' => 'value',
        '#value' => $node->nid,
      );
    
      return confirm_form($form,
        t('Are you sure you want to delete %title?', array('%title' => $node->title)),
        isset($_GET['destination']) ? $_GET['destination'] : 'node/' . $node->nid,
        t('This action cannot be undone.'),
        t('Delete'),
        t('Cancel')
      );
    }
    
    function node_delete_confirm_submit($form, &$form_state) {
      if ($form_state['values']['confirm']) {
        $node = node_load($form_state['values']['nid']);
        node_delete($form_state['values']['nid']);
        watchdog('content', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->title));
        drupal_set_message(t('@type %title has been deleted.', array('@type' => node_type_get_name($node), '%title' => $node->title)));
      }
    
      $form_state['redirect'] = '<front>';
    }
    
  • Possible scenario:
    function node_form($form, &$form_state, $node) {
      $form['buttons']['delete'] = array(
        '#type' => 'submit',
        '#value' => t('Delete'),
        '#weight' => 15,
        '#access' => !empty($node->nid) && node_access('delete', $node),
        '#process' => array('form_process_confirm'),
        '#confirm_title' => t('Are you sure you want to delete %title?', array('%title' => $node->title)),
        '#confirm_description' => t('This action cannot be undone.'),
        '#confirm_submit' => t('Delete'),
        '#submit' => array('node_form_delete_submit'),
      );
    }
    
    function node_delete_confirm_submit($form, &$form_state) {
      if ($form_state['values']['confirm']) {
        $node = node_load($form_state['values']['nid']);
        node_delete($form_state['values']['nid']);
        watchdog('content', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->title));
        drupal_set_message(t('@type %title has been deleted.', array('@type' => node_type_get_name($node), '%title' => $node->title)));
      }
    
      $form_state['redirect'] = '<front>';
    }
    
sun’s picture

This is an advanced use-case: A #process and/or #element_validate form handler (not sure yet) tries to turn a form into a multi-step form.

alexanderpas’s picture

how about we create seperate pages for changing password (user/edit/password) and email-address (user/edit/email)?

on the password page, we request the current password, along with the new password. (MENU_LOCAL_ACTION?)
on the email page we request the new email along with the current password. (again MENU_LOCAL_ACTION?)

on user/edit we show the current values of those fields (or ******** in case of the password.)

sun’s picture

Thanks, Alex! But if you want that, you can subscribe to a flood of other issues - just search for "user password" (and similar) in Drupal core. ;)

This issue is, indeed, about bringing Form API from Drupal 4 to Drupal 7 regarding confirmation forms. The [theme_]confirm_form() construct using a separate page callback actually dates back to pre-form-API, i.e. before Drupal 4.7.

mattyoung’s picture

.

pwolanin’s picture

Version: 7.x-dev » 8.x-dev
sun’s picture

Version: 8.x-dev » 7.x-dev

Sure, you can try to handle all of these...

#86299: Add "current password" field to "change password form"
#75924: Include fields for resetting password on the one-time password reset page
#486544: system_settings_form does not support password / password_confirm fields well
#430780: User account hijack prevention
#85494: Use email verification when changing user email addresses
#64483: permissions & variable for disallowing editing of user variables

They all share the same common denominator if you start to think about it, and especially if you start to think about usability.

This one is in my top 10 of API clean-up issues. Because, as mentioned before, we're carrying forward this crappy construct of confirm_form() since years, instead of implementing our existing APIs properly.

sime’s picture

I'd suggest updating the title cos this is hard to follow. Is the issue "remove the confirm form foo"? (Which in turn is a pre-requisite for fixing password confirm?)

sun’s picture

Version: 7.x-dev » 8.x-dev
sun’s picture

FileSize
4.33 KB

Re-rolled against HEAD. Due to other Form API fixes, this should be easier now, but I couldn't make it work yet though.

catch’s picture

Priority: Critical » Major

Downgrading all D8 criticals to major per http://drupal.org/node/45111

quicksketch’s picture

Status: Needs work » Closed (duplicate)
FileSize
57.21 KB

This sure seems like it was fixed already as part of #86299: Add "current password" field to "change password form" (see screenshot of D7's account form).

The major part of this issue was certainly corrected (a password confirmation). In any case, this issue is very hard to follow (considering the summary was finally added in #7). If we want to make a new task for removing confirmation forms, it should be in a dedicated issue.

sun’s picture

Priority: Major » Normal
Status: Closed (duplicate) » Needs work
quicksketch’s picture

@sun: So what's the goal of this issue now? Remove confirmation forms? We've already added the field for password confirmation, which I assume is why this issue is titled "Drupal paranoia"?

David_Rothstein’s picture

Title: Drupal paranoia » Allow the user edit form to only ask for the current password when necessary (in a followup confirmation step)

I think the goal here is to improve the user experience (by not showing a confusing "Current password" field on the user edit form every time, but rather only showing it on a followup confirmation screen when it's actually needed).

And potentially to do it via the same form (in a built-in multi-step fashion), rather than resorting to confirm_form().

Attempting to give it a more descriptive title :)

quicksketch’s picture

And potentially to do it via the same form (in a built-in multi-step fashion), rather than resorting to confirm_form().

A potential concern with this approach is that any form that uses $form_state['storage'] or is multiple steps will make an entry in the cache_form table, potentially *with* the users plain-text password stored in the database. Actually now that I think about it, if you add a FileField to the user form, this could already be the case. These "cache" entries are both insecure and long-lived (for at least 6 hours).

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Issue summary: View changes
Status: Needs work » Postponed (maintainer needs more info)

Wonder after 12 years if this is still a needed task?

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.