Problem/Motivation

Elements of #type => password_confirm do not respect t#maxlength attribute. The user can enter more than the specified length and no validation errors are thrown.

In 10.2.4
If #maxlength is specified there is an additional crash in validate handler

The website encountered an unexpected error. Try again later.

TypeError: mb_strlen(): Argument #1 ($string) must be of type string, array given in mb_strlen() (line 333 of core/lib/Drupal/Core/Form/FormValidator.php).
Drupal\Core\Form\FormValidator->performRequiredValidation(Array, Object) (Line: 246)
Drupal\Core\Form\FormValidator->doValidateForm(Array, Object) (Line: 238)
Drupal\Core\Form\FormValidator->doValidateForm(Array, Object, 'FlowerAjaxBugForm') (Line: 118)
Drupal\Core\Form\FormValidator->validateForm('FlowerAjaxBugForm', Array, Object) (Line: 593)
Drupal\Core\Form\FormBuilder->processForm('FlowerAjaxBugForm', Array, Object) (Line: 325)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 627)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 704)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Steps to reproduce

1. Create a custom form with an element of type password_confirm
2. Set #maxlength attribute for the element to 10
3. In the UI enter a value more than 10 characters, it's accepted
4. Submit the form, it crashes with the above error

Proposed resolution

Element of type password_confirm should support #maxlength attribute. Validation error must be thrown if the user enters value more than the specified characters.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

CommentFileSizeAuthor
#85 confirm_password maxlength 15.png121.33 KBsukr_s
#73 interdiff_71_73.txt3.91 KBEduardo Morales Alberti
#73 core-password_confirm_support_maxlength-1344552-73.patch8.64 KBEduardo Morales Alberti
#71 interdiff_66_71.txt2.29 KBEduardo Morales Alberti
#71 core-password_confirm_support_maxlength-1344552-71.patch4.89 KBEduardo Morales Alberti
#68 core-password_confirm_support_maxlength-1344552-66-11x.patch5.62 KBEduardo Morales Alberti
#66 interdiff_47_66.txt4.31 KBEduardo Morales Alberti
#66 core-password_confirm_support_maxlength-1344552-66.patch6.06 KBEduardo Morales Alberti
#55 password_worksfine.png114.04 KBsonam.chaturvedi
#52 Before Patch 1344552.png586.13 KBchetanbharambe
#51 Screenshot from 2021-05-26 10-42-40.png47.62 KBvikashsoni
#49 beforePatch.png100.65 KBRuchi Joshi
#47 interdiff_40-47.txt1.27 KBraman.b
#47 1344552-47.patch3.29 KBraman.b
#40 1344552-40.patch3.3 KBzahord
#36 password-confirm-maxlength-1344552-36.patch3.32 KBaleevas
#16 1344552-password-confirm-maxlength-16-combined.patch5.46 KBmarcingy
#15 1344552-password-confirm-maxlength-15-combined.patch5.46 KBmarcingy
#14 1344552-password-confirm-maxlength-14-combined.patch5.46 KBmarcingy
#10 1344552-password-confirm-maxlength-10-tests.patch3.25 KBNiklas Fiekas
#10 1344552-password-confirm-maxlength-10-combined.patch3.72 KBNiklas Fiekas
#1 password_confirm_support_maxlength-1344552-1.patch478 bytesRavi.J

Issue fork drupal-1344552

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Ravi.J’s picture

Patch attached

Ravi.J’s picture

Status: Active » Needs review
Ravi.J’s picture

Issue summary: View changes

rephrased some of the lines in issue body text to make it easier for reader to understand

Everett Zufelt’s picture

I haven't tested, but the use case and the code seem good to me.

I don't know what the API backport policy is, but I see no reasons for this not to be backported to D7.

Ravi.J’s picture

Category: feature » bug
Priority: Normal » Major

I am changing this one to Major bug as the issue results is password_confirm field type not being usable.
Since opening this ticket, i have had two different projects on which i had to use different password fields instead of password_confirm

xjm’s picture

Category: bug » task
Priority: Major » Normal

I may be missing something, but how does missing #maxlength make the field unusable?

Ravi.J’s picture

As password_confirm field does not support #maxlength property, There is no way to restrict how many characters users can input in the field. Even in situation where the underlying database field only accepts a limited number of characters, it cannot be enforced within form.

The result of this is
1. Developers needs to enforce maximum characters limit in
_validate hook.

2. User's are still allowed to enter unlimited number of characters and get error message back only after form is submitted. This makes for such a bad user interface , they should not have been allowed to enter more than allowed number of characters in first place.

The only option to solve above issue to use two separate password fields (As posted above in original usecase) which makes password_confirm field type unusable and redundant.

Also password_confirm field is rendered as HTML password element, and should support maxlength prooperty as per guidelines http://www.w3.org/TR/html4/interact/forms.html#adef-maxlength

Looking through core code, i see that password_confirm field is suppose to work exactly like password field, and all it should do is to make a copy of password field and apply additional validation rule, At the moment this is not the case and needs to be fixed.

cweagans’s picture

Category: task » bug
Priority: Normal » Major
Status: Needs review » Reviewed & tested by the community

Talked to RaviJ in IRC, and this is indeed a pretty big Drupal WTF.

The problem is that a password field on it's own DOES support maxlength, while the password_confirm field type (which renders as two password inputs) does NOT.

That's the problem to solve here, and RaviJ's patch fixes the problem well.

cweagans’s picture

This should be backported to 7.x, and potentially 6.x, but I'm not sure.

xjm’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs tests

Okay, we need an automated test then. Thanks @cweagans and @Ravi.J!

Niklas Fiekas’s picture

Here is a testcase verifying the problem.

Note that even with the patch the full-length value is passed to the submit handler and some notices occur - at least locally.

 

Edit: When doing a reroll, note this typo:

+++ b/core/modules/simpletest/tests/form.testundefined
@@ -1628,3 +1628,43 @@ class FormCheckboxTestCase extends DrupalWebTestCase {
+    // Ensure validation fields if the input is too long.

Should be: Validation fails.

xjm’s picture

Excellent. Pending testbot, I think the tests look great, aside from the comment typo @Niklas Fiekas points out. Edit: and "secound."

Edit 2: Sorry, misread the comment above. This is the error message:
Warning: mb_strlen() expects parameter 1 to be string, array given in drupal_strlen() (line 444 of /home/niklas/Projekte/drupal-8/core/includes/unicode.inc).

So presumably we'll see that fail on the combined patch.

Status: Needs review » Needs work

The last submitted patch, 1344552-password-confirm-maxlength-10-combined.patch, failed testing.

marcingy’s picture

Status: Needs review » Needs work

The exceptions are generated because in _form_validate the password field is an single element with multiple #values in the form of an array so we need to some how make an exception. The obvious option is add additional logic to see if #value is an array and if so we then do the max length check on each element within the array when submitting.

marcingy’s picture

Status: Needs work » Needs review
FileSize
5.46 KB

Lets see how this goes

marcingy’s picture

Missed the comment above first time round this patch just fixes the comment

marcingy’s picture

Status: Needs work » Needs review
FileSize
5.46 KB

meh

xjm’s picture

Status: Needs review » Needs work

Thanks @marcingy, and thanks @Niklas Fiekas for providing a complete test so we can make sure we get the right solution. Looks like it should pass based on #14.

Meanwhile, one suggestion:

+++ b/core/includes/form.incundefined
@@ -1290,8 +1290,17 @@ function _form_validate(&$elements, &$form_state, $form_id = NULL) {
+      if (isset($elements['#maxlength'])) {
+        if (!is_array($elements['#value']) && drupal_strlen($elements['#value']) > $elements['#maxlength']) {
+          form_error($elements, $t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => drupal_strlen($elements['#value']))));
+        }
+        else if (is_array($elements['#value'])) {
+          foreach ($elements['#value'] as $element_key => $element_value) {
+            if (drupal_strlen($element_value) > $elements[$element_key]['#maxlength']) {
+              form_error($elements, $t('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements[$element_key]['#maxlength'], '%length' => $element_value)));
+            }
+          }
+        }

Rather than duplicating the code here, I think it would be better to do something like:

$foo = is_array($elements['#value']) ? $elements['#value'] : array($elements['#value']);

and then foreach $foo.

(Edited to correct the pseudocode.)

Edit 2: Wait, do we really want to set an error for every item? Wouldn't one error be sufficient? Maybe we should break;?

xjm’s picture

Tagging for UX sanity check once we have a working solution. :)

David_Rothstein’s picture

Priority: Major » Normal

Per the definitions at http://drupal.org/node/45111 this is not a major bug. It's arguably not a bug at all (since it's documented behavior), although for consistency it definitely makes sense to change.

Couple issues:

  1. I agree with xjm that it should be possible to simplify/combine the code.
  2. In addition, the code makes the assumption that when $elements['#maxlength'] is set, each $elements[$element_key]['#maxlength'] will be set also, but nowhere is that enforced. Perhaps as part of fixing #1 this would just wind up using $elements['#maxlength'] in all cases anyway? Or is there actually a use case where we need to support different maxlengths for different sub-elements of the array?
  3. '%length' => $element_value should be '%length' => drupal_strlen($element_value) so that the correct thing is printed.
  4. +        else if (is_array($elements['#value'])) {
    

    Note sure if it's an official coding standard, but I think we usually use "elseif" in PHP code?

  5. Edit 2: Wait, do we really want to set an error for every item? Wouldn't one error be sufficient? Maybe we should break;?

    I think we do want the red border around each item, although it looks like the code will probably do that even if only one error is set... When I tested the patch, I also expected to see a problem where two error messages were displayed. For some reason, though, only one error message is displayed (even though two errors are set); I didn't track down why. We definitely only want one error message. I think this ties into my comment #2 above; are we actually validating them separately or really just validating the whole thing as a group?

David_Rothstein’s picture

To partially answer my question in #2, I guess the deal is that each sub-element has to have its own #maxlength in order for it to actually be printed in the HTML...

Still seems odd at least in the password confirm use case, since you'd never want the two elements to have different #maxlengths there.

xjm’s picture

Note sure if it's an official coding standard, but I think we usually use "elseif" in PHP code?

Yep: http://drupal.org/coding-standards#controlstruct

And regarding #2, changing all of _form_validate() for this does seem a bit odd, and there's certainly no reason you'd have a different maxlength for the confirm password field vs. the password. I don't even know what it would mean outside this context.

Edit: xpost.

marcingy’s picture

As I got into this to be honest I agree it seems much more like a task/feature request than a bug, and if you need to validate field length in password hook validate can be utilised. And after the comments above it seems like we really need to refractor how the password element works.

cweagans’s picture

Issue tags: +Needs backport to D7
pjcdawkins’s picture

YesCT’s picture

I think we need to look at this to see if things have changed in 8.x
And we need to decide on an approach to take.
Updating the issue summary to reflect that needs screenshots is waiting on a new patch.

Issue summary also needs updating to summarize different possible approaches to take.

YesCT’s picture

Issue summary: View changes

Reformatted body text to make the issue easier to understand

YesCT’s picture

Actually, screenshot could be made of the page that will change. We can get the *before* screenshot to show what it looks like right now. That would also be a good chance to document the steps to reproduce of how to get to that page.

YesCT’s picture

Issue summary: View changes

clarified nothing right now to do screenshots of

Ravi.J’s picture

Screenshots of they look at the moment already attached in the original issue post.
The fundmental problem is that, when a password confirm field is used in form API, two separate text field are rendered with different max length properties.
This is a bug. It doesn't seem logical to write form validators for the problem and agree with #21 that it does seem odd to write all the validators.

Ravi.J’s picture

Issue summary: View changes

before screenshot can be made

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.

andypost’s picture

aleevas’s picture

Status: Needs work » Needs review

Looks like we need to redo this whole patch, cuz we don't have these test files and the function "_form_validate" in the core/includes/form.inc

aleevas’s picture

Status: Needs review » Needs work

The last submitted patch, 36: password-confirm-maxlength-1344552-36.patch, failed testing. View results

andypost’s picture

Status: Needs work » Needs review

@aleevas patch should be applicable with `patch -p1`! your one is `-p0`

andypost’s picture

Status: Needs review » Needs work
zahord’s picture

zahord’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 40: 1344552-40.patch, failed testing. View results

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.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.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). 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.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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.

tanubansal’s picture

Patch is not working on 9.1
Please check

raman.b’s picture

Status: Needs work » Needs review
FileSize
3.29 KB
1.27 KB

Resolving failed test cases from #40

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

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Ruchi Joshi’s picture

FileSize
100.65 KB

This issue doesn't exists for drupal 9.1. Max limit for Confirm Password and Password field is set to 128 characters and it automatically crops character to it.
Screenshot is attached

Steps:
1. Visit /admin/people/create
2. Enter a long text of 200 characters on Password field.
3. When cursor is out from Password field, it will automatically crop the text by 128 characters.
4. Enter a long text of 200 characters on Confirm Password field.
5. Again cursor is out from Confirm Password field, it will automatically crop the text by 128 characters.
6. Similarly, we can try with User profile update form- /user/4/edit, but result will be same as in pt. 3 & 4

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

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

vikashsoni’s picture

Issue summary: View changes
FileSize
47.62 KB

there is no issue exists for drupal 9.3. Max limit for Confirm Password and Password field is set to 128 characters and it automatically crops character to it.
Screenshot is attached .................

chetanbharambe’s picture

FileSize
586.13 KB

Verified and tested this issue on the 9.3.x-dev version.
Working as Expected.

Testing Steps:
# Goto: Appearance -> Apply Seven Theme
# Goto: /admin/people/create
# Enter a long text of 200 characters on the Password field.
# When the cursor is out from the Password field, it will automatically crop the text by 128 characters.
# Enter a long text of 200 characters on Confirm Password field, it will automatically crop the text by 128 characters.
# Observe the results

Expected Results:
# Verified that Max limit for Confirm Password and Password field is set to 128 characters and it will automatically crop characters to it.

Note: This issue is already FIXED on this (9.3.x-dev) version, So we can close this issue.

Please refer attached screenshots for the same.
Looks good to me.
Can be a move to RTBC.

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

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.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.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now 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.

sonam.chaturvedi’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
114.04 KB

This issue doesn't exists for drupal 9.5.x-dev.
1. Password confirm field type now have support for #maxlength attribute
2. Max limit for Confirm Password and Password field is set to 128 characters and it automatically crops character to it.
3. User is able to login using 128 character password (even when 200 is entered while creating user account)

no patch

No patch required, moving to RTBC

rkoller’s picture

Status: Reviewed & tested by the community » Needs work

I've taken a look in 9.5.0-dev and I can confirm that the password fields have a maxlength attribute of 128. In contrast the latest patch in this issue added a maxlengh of 12 only? In regards of the issue status I wouldn't set it to RTBC but Closed (Outdated).

But in regards of the observations @sonam.chaturvedi made in #55.2 & #55.3. I have manually tested and have a few differing observations:

  • I've copy and pasted a password with a length of 138 to the password and confirm password field. None of the two fields notified me that I've exceeded the maximum password length. I was able to successfully save the password changes afterwards. I've then logged out and tried to relogin. First with the first 128 characters of the 138 character password, that failed so the password isn't cropped. I was able to login using the 138 characters password. That is a consider a good thing. Cropping a password without any notification at all silently i would consider a ux no-go. but still the maxlength attribute has no effect at all and should be fixed.
  • I've then went again to the user edit page and copy and pasted the 138 characters password in the current password, password and confirm password field. I've then added one or two extra characters to the confirm password field. The password match remained to yes. Same when I've then added extra characters to the password field. It looks like as soon as the password length exceeds 128 characters the password match check isn't applied anymore and remains to yes all the time?

i've tested in the latest safari, firefox and edge - all behave the same. I am setting the issue to needs work to get feedback on #55 and my comment. Uncertain what the best approach would be. Closing this issue as outdated and opening a new one or repurposing it by updating the issue summary and deal with described issues in here?

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

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now 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.

Version: 10.1.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, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Eduardo Morales Alberti’s picture

In our case, we use client side validation that has its own maxlength validation and we need the patch to override the maxlength on the confirm password element.

Examples:

    $form['current_password'] = [
      '#title' => $this->t('Current Password'),
      '#title_display' => 'none',
      '#type' => 'password',
      '#size' => 64,
      '#maxlength' => 64,
      '#required' => TRUE,
    ];

    $form['password'] = [
      '#title' => $this->t('New Password'),
      '#title_display' => 'none',
      '#size' => 64,
      '#maxlength' => 64,
      '#type' => 'password_confirm',
      '#required' => TRUE,
    ];
Eduardo Morales Alberti’s picture

After applying the patch I got the error:

mb_strlen(): Argument #1 ($string) must be of type string, array given in mb_strlen() (line 334 of /var/www/html/docroot/core/lib/Drupal/Core/Form/FormValidator.php) 

Because the confirm password element has two values, and the Form validator expects to validate an int.

The single value is set on Password Confirm Validation, but after the maxlength validation (FormValidator).

  public static function processPasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
    $element['#element_validate'] = [[static::class, 'validatePasswordConfirm']];
.....

  public static function validatePasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
    $pass1 = trim($element['pass1']['#value']);
    $pass2 = trim($element['pass2']['#value']);
    if (strlen($pass1) > 0 || strlen($pass2) > 0) {
      if (strcmp($pass1, $pass2)) {
        $form_state->setError($element, t('The specified passwords do not match.'));
      }
    }
    elseif ($element['#required'] && $form_state->getUserInput()) {
      $form_state->setError($element, t('Password field is required.'));
    }

    // Password field must be converted from a two-element array into a single
    // string regardless of validation results.
    $form_state->setValueForElement($element['pass1'], NULL);
    $form_state->setValueForElement($element['pass2'], NULL);
    $form_state->setValueForElement($element, $pass1);

    return $element;
  }

Form validator.php

  protected function doValidateForm(&$elements, FormStateInterface &$form_state, $form_id = NULL) {
....
    if (!isset($elements['#validated']) || !$elements['#validated']) {
      // The following errors are always shown.
      if (isset($elements['#needs_validation'])) {
        $this->performRequiredValidation($elements, $form_state);
      }
....
      elseif (isset($elements['#element_validate'])) {
        foreach ($elements['#element_validate'] as $callback) {
          $complete_form = &$form_state->getCompleteForm();
          call_user_func_array($form_state->prepareCallback($callback), [&$elements, &$form_state, &$complete_form]);
        }
      }
  protected function performRequiredValidation(&$elements, FormStateInterface &$form_state) {
    // Verify that the value is not longer than #maxlength.
    if (isset($elements['#maxlength']) && mb_strlen($elements['#value']) > $elements['#maxlength']) {
      $form_state->setError($elements, $this->t('@name cannot be longer than %max characters but is currently %length characters long.', ['@name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $elements['#maxlength'], '%length' => mb_strlen($elements['#value'])]));
    }
Eduardo Morales Alberti’s picture

Version: 11.x-dev » 9.5.x-dev
Eduardo Morales Alberti’s picture

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

Eduardo Morales Alberti’s picture

Changed the value callback to get the right validation on maxlength.

Eduardo Morales Alberti’s picture

Status: Needs work » Needs review
FileSize
6.06 KB
4.31 KB

Patch from MR.

Eduardo Morales Alberti’s picture

Status: Needs review » Needs work

Still working on the patch because of the error on install:

 [warning] Trying to access array offset on value of type null PasswordConfirm.php:106
 [warning] Trying to access array offset on value of type null PasswordConfirm.php:107

In install.core.inc line 971:
                               
  Password field is required.  
Eduardo Morales Alberti’s picture

Eduardo Morales Alberti’s picture

Eduardo Morales Alberti’s picture

Eduardo Morales Alberti’s picture

Reviewing tests failed:

Testing Drupal\Tests\user\Functional\UserLoginTest
....E.                                                              6 / 6 (100%)

Time: 00:30.595, Memory: 4.00 MB

There was 1 error:

1) Drupal\Tests\user\Functional\UserLoginTest::testPasswordLengthLogin
Behat\Mink\Exception\ResponseTextException: The text "The changes have been saved." was not found anywhere in the text of the current page.


Drupal\Tests\Core\Render\Element\PasswordConfirmTest
fail: [Other] Line 0 of sites/default/files/simpletest/phpunit-557.xml:
PHPUnit Test failed to complete; Error: PHPUnit 9.6.8 by Sebastian Bergmann and contributors.

Testing Drupal\Tests\Core\Render\Element\PasswordConfirmTest
FFFFFF                                                              6 / 6 (100%)

Time: 00:00.054, Memory: 6.00 MB

There were 6 failures:

1) Drupal\Tests\Core\Render\Element\PasswordConfirmTest::testValueCallback with data set #0 (array('', ''), array(), null)
Failed asserting that '' is identical to Array &0 (
    'pass1' => ''
    'pass2' => ''
).

/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:122
/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php:79
/var/www/html/core/tests/Drupal/Tests/Core/Render/Element/PasswordConfirmTest.php:22
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:144
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:97

2) Drupal\Tests\Core\Render\Element\PasswordConfirmTest::testValueCallback with data set #1 (array('', ''), array(array('value')), null)
Failed asserting that '' is identical to Array &0 (
    'pass1' => ''
    'pass2' => ''
).

/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:122
/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php:79
/var/www/html/core/tests/Drupal/Tests/Core/Render/Element/PasswordConfirmTest.php:22
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:144
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:97

3) Drupal\Tests\Core\Render\Element\PasswordConfirmTest::testValueCallback with data set #2 (array('value', ''), array(array('value')), false)
Failed asserting that '' is identical to Array &0 (
    'pass2' => 'value'
    'pass1' => ''
).

/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:122
/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php:79
/var/www/html/core/tests/Drupal/Tests/Core/Render/Element/PasswordConfirmTest.php:22
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:144
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:97

4) Drupal\Tests\Core\Render\Element\PasswordConfirmTest::testValueCallback with data set #3 (array('123456', 'qwerty'), array(), array('123456', 'qwerty'))
Failed asserting that '123456' is identical to Array &0 (
    'pass1' => '123456'
    'pass2' => 'qwerty'
).

/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:122
/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php:79
/var/www/html/core/tests/Drupal/Tests/Core/Render/Element/PasswordConfirmTest.php:22
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:144
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:97

5) Drupal\Tests\Core\Render\Element\PasswordConfirmTest::testValueCallback with data set #4 (array('123', '234'), array(), array(123, 234))
Failed asserting that '123' is identical to Array &0 (
    'pass1' => '123'
    'pass2' => '234'
).

/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:122
/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php:79
/var/www/html/core/tests/Drupal/Tests/Core/Render/Element/PasswordConfirmTest.php:22
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:144
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:97

6) Drupal\Tests\Core\Render\Element\PasswordConfirmTest::testValueCallback with data set #5 (array('', '234'), array(), array(array('array'), 234))
Failed asserting that '' is identical to Array &0 (
    'pass1' => ''
    'pass2' => '234'
).

/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php:122
/var/www/html/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php:79
/var/www/html/core/tests/Drupal/Tests/Core/Render/Element/PasswordConfirmTest.php:22
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
/var/www/html/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:144
/var/www/html/vendor/phpunit/phpunit/src/TextUI/Command.php:97

FAILURES!
Tests: 6, Assertions: 6, Failures: 6.
Eduardo Morales Alberti’s picture

Fixing tests, value callback now returns only the password 1 because the second password is only for validation, and the password confirm already validates it, and also it makes the max length validation from the core fail because it expects a string but the value callback returned an array with both values.

Eduardo Morales Alberti’s picture

Status: Needs work » Needs review
sahil.goyal’s picture

Status: Needs review » Reviewed & tested by the community

Hi @Eduardo Morales Alberti, thanx for the patch

I Reviewed and tested the patch. Confirmed that the following changes have been made and works as expected as:
In the valueCallback() method, returns an empty string instead of an array with empty values if no input is provided.
In the processPasswordConfirm() method, the explicit setting of for element pass1 and pass2 has been removed to depends on the value callback. Additionally, the '#maxlength' attribute is now correctly set for both fields when the attribute is specified on the PasswordConfirm element.
After thorough testing, all changes are working as expected and the functionality working fine. Moving to RTBC

Eduardo Morales Alberti’s picture

Eduardo Morales Alberti’s picture

Not the same issue, but could be related because are altering the same field.

quietone’s picture

Title: Password confirm field type should have support for #maxlength attribute » Password confirm field type should have support for #maxlength attribute
Issue summary: View changes
Status: Reviewed & tested by the community » Needs work

I am doing triage on the core RTBC queue.

Thanks for working on this old issue!

This issue has no issue summary! The issue summary is the first thing a reviewer or committer will see as they start their work. In #5, xjm asks the question I am asking as well, why is this needed. That information should be in the issue summary. Issue summaries matter.

And I see that this is tagged for "Needs issue summary update" and "Needs screenshots". I am setting this o needs work for the issue summary update and screenshots.

I see that there is a recent MR and a patch. Which one is to be reviewed?

sukr_s’s picture

Issue summary: View changes
sukr_s’s picture

Issue summary: View changes

sukr_s’s picture

Status: Needs work » Needs review

- I've updated the issue summary
- fixed the issue
- added test

smustgrave’s picture

Status: Needs review » Needs work

Seems to be multiple MRs and patches these need to be cleaned up for clarity.

Was previously tagged for screenshots but the User interface changes section is empty.

Have not reviewed.

sukr_s changed the visibility of the branch 1344552-password-confirm-field-11x to hidden.

sukr_s’s picture

Status: Needs work » Needs review
FileSize
121.33 KB

Adding screenshot #maxlength set to 15. UI doesn't allow more than 15 characters.

hidden older MR !4290

Pipeline has not run for MR !7188. How can I trigger this?