The issue was created to allow the use of passwords with length > 60. But that problem was fix somewhere in the development of D8 (see #9) and this issue changed to adding tests for that functionality.
Original Issue Summary
Problem
During the site install, I created an admin account with a 256 char random password. The password was generated in Keepass, and copied/pasted into the form. I was able to log in when the install completed, perhaps with the help of the browsers' autocomplete. I created an author account with another long password the same way. I logged in successfully as the author and posted some dummy content.
However, a day later, I am unable to log in to either account. I notice that the maxlength attribute on the password field is 60, and if I remove that attribute and then submit the form, Drupal gives me an error message:
Password cannot be longer than 60 characters but is currently 256 characters long.
Edit: I just noticed that when changing a password, the maxlength of the password fields are 128. However, when logging in, the maxlength is 60.
Proposed resolution
Update the core user module and the new password form(s).
Remaining tasks
Edit a core module and a core template?
User interface changes
Display all of the password criteria, including maximum length and restricted characters, when a user is setting a password.
API changes
Consider setting the max password length to a larger value, 60 seems arbitrary and small. Maybe 1KB or so?
As a workaround, I changed the admin password directly in the database using user_hash_password().
For the record, this install is running in WAMP on Windows 7, and I believe that drush is unavailable.
Comment | File | Size | Author |
---|---|---|---|
#83 | interdiff_73_82.txt | 2.32 KB | joshua1234511 |
#82 | 1777270_82.patch | 3.42 KB | joshua1234511 |
#73 | interdiff_71-73.txt | 2.09 KB | shetpooja04 |
#73 | 1777270-73.patch | 2.32 KB | shetpooja04 |
#71 | interdiff_69-71.txt | 612 bytes | shetpooja04 |
Comments
Comment #1
danjro CreditAttribution: danjro commentedI found one of the problems.
On line 1310 of modules/user/user.module:
should probably be
in order to match line 380 of modules/system/system.module:
Or maybe one of these values should refer to the other, I'm new here.
Comment #2
danjro CreditAttribution: danjro commentedComment #3
danjro CreditAttribution: danjro commentedI would like to learn how to fix this myself, properly, so I am assigning this to myself. However, this will be my first patch, and it may take me a day to figure it all out. I will ask for help on the #drupal irc channel if I need it. If someone beats me to the punch, that's totally cool too.
Comment #4
Devin Carlson CreditAttribution: Devin Carlson commentedAwesome ross9885, the more core developers the merrier!
Some notes from my inital look at the issue (repeating some of your observations):
install_configure_form_validate()
(install.core.inc)user_validate_current_pass()
(user.module) which is called by AccountFormController (AccountFormController.php)Also, patches are made against Drupal 8 and then backported to Drupal 7 in order to prevent regressions.
Comment #5
tim.plunkettThis is a nasty bug, but I don't think it should be blocking other development.
Really nice find, @ross9885! And great issue summary.
Comment #6
ssm2017 Binder CreditAttribution: ssm2017 Binder commentedwhy not remove the size and maxlength because they are already defined in the default password form element declaration ?
this is ok to define a custom value for custom modules but i think that drupal should have the same value everywhere.
i m telling this because i'm building a custom module and i have overrided the form element maxlenght but this is still forced in some drupal's forms like the login form so i need to also use a form alter or preprocess instead of just altering the default form element.
Comment #7
Devin Carlson CreditAttribution: Devin Carlson commentedA patch to implement ssm2017 Binder's suggestion.
The login block's password form item doesn't need to declare a maxlength since all password elements have an appropriate default maxlength of 128.
Comment #8
caelon CreditAttribution: caelon commentedI have tested the patch and confirmed that it does not enforce 60 characters max on the login form.
Because this pointed out a larger problem that all password fields should be consistent, I did a grep to find all '#type' => 'password' instances assuming they would be the only ones that would have max sizes:
grep -r "'#type' => 'password'" *
I reviewed all nine core files found by that grep and none of them, post-patch, has a maxlength attribute so all are now consistently coded.
Comment #9
webchickLooks like this already got committed at some point down the line to 8.x. Moving down to 7.x, which should have that same test by caelon in #8 to ensure that there's only one instance.
Comment #10
Devin Carlson CreditAttribution: Devin Carlson commentedThe patch from #1772584: Get rid of user_login_block() & user_login() in favour of user_login_form() fixed the issue and was committed three days ago by yourself. :P
See http://drupalcode.org/project/drupal.git/commit/b38996475dd09e5c3709397c...
A patch against D7, since the issue which fixed this in D8 will not be backported.
Comment #11
barraponto CreditAttribution: barraponto commentedJust ran
ack --type-add php=.inc password -A 10 . --php | grep maxlength
to doublecheck if we were missing anything, seems ok.Comment #12
David_Rothstein CreditAttribution: David_Rothstein commentedLooks good to me, but shouldn't we have an automated test here too?
This issue has the "Novice" tag, and it might actually be a good test for someone who is looking to get started with simpletests to work on. Basically, the goal would be to create a user with a password equal to the maximum allowed length and then make sure that user can log in (via both the user login block and the regular /user/login page) without any errors.
This test could go into Drupal 8 too, actually...
Comment #13
David_Rothstein CreditAttribution: David_Rothstein commentedActually, come to think of it, since this is already fixed in Drupal 8 it will be a lot simpler if we just commit it to Drupal 7 now and do the tests as a followup.
So... committed to 7.x - thanks! http://drupalcode.org/project/drupal.git/commit/dafe7ae
Comment #14
David_Rothstein CreditAttribution: David_Rothstein commented@Devin Carlson, feel free to unassign yourself if you don't want to write those tests, by the way :)
Comment #15
nagwani CreditAttribution: nagwani commented@David Carlson, anything I can help with. Happy to help. Thanks
Comment #16
aries CreditAttribution: aries commentedHere is patch for the test case.
Comment #17
aries CreditAttribution: aries commentedI've left a mistake, the length of the valid and invalid case were the same. Apologies.
Comment #18
David_Rothstein CreditAttribution: David_Rothstein commentedThanks! Setting to "needs review" so that the testbot will run it.
Comment #19
balintk CreditAttribution: balintk commentedWhy does the assertion message say 127 characters here when the password was generated with 128 characters?
Similarly, I don't understand the assertion message. Why does it contain 255 characters? I could totally miss something here with those characters, but if that's the case maybe documenting the reason in a comment would be a good idea.
Also, it's just a small thing, but using single quotes and an escaped apostrophe in the string should be avoided (even though this is not inside of
t()
). I did a quick grep and I learned that it's more common to avoid this situation by using the non-shortened form "could not". Additionally, a super-minor remark: I would also make sure that the two assertion messages have nearly the same wording (i.e.: "length" vs. "long").Comment #20
aries CreditAttribution: aries commentedThanks Bálint, I've accidentally left those numbers in. I've updated the test according your recommendations.
Comment #21
balintk CreditAttribution: balintk commentedI was focusing on those assertion messages, but now I've given more thoughts to the approach of the patch.
Use
assertFailedLogin()
There is already a method in the same class for making an unsuccessful login attempt, it would be better to use that.
Consider implementing
setUp()
methodSince almost all methods in this class need at least one user account to perform tests it would be interesting to consider implementing the
setUp()
method, creating user accounts there and making them accessible via class properties so that each test method in the class can utilize them.One of the user accounts could be created with the maximum allowed numbers of characters in the password (other tests will pass just fine), so in the test method introduced by the patch this password could be simply changed when we want to test the login failure scenario.
If the
setUp()
method is a good idea, maybe refactoring the other methods to use the user object created by that could be a follow-up issue.Test user login block as well
As @David_Rothstein said the test should cover the login attempts from a login block as well, not only logins from the regular user login page.
Comment #22
aries CreditAttribution: aries commentedCheers Bálint for the review. This patch contains number of improvements what Bálint suggested:
Use of assertFailedLogin(). assertFailedLogin() expects wrong user credentials, where Drupal returns with Sorry, unrecognized username or password. Have you forgotten your password?' instead of Password cannot be longer than... which means the credentials were correct but the password has invalid length. That's why I handled this in different way.
Comment #24
aries CreditAttribution: aries commentedNow only I fail left which looks like because a bug in the Blocks module. The
testPasswordLengthBlock()
should be fine, but the issue is a bit weird.The login fails because the invalid password length, but in the block header instead
t('User login')
I get the username. With same block the error message and the form appears as it should. Check the raw response here: http://pastebin.com/97nAzeqW . With cURL the login via the UI works fine.Comment #25
aries CreditAttribution: aries commentedComment #27
smiletrl CreditAttribution: smiletrl commentedI'm a little confused that have we committed the code to fix the problem described here?
If the answere is yes, so what we need to do now is to write tests for this scenario?
Comment #28
aries CreditAttribution: aries commented@smiletrl: I noticed the issue I described in #21 while I was writing tests for log in. I need confirmation, is this a real issue?
To replicate it all you need is to apply the patch I attached and run the test via either Drush (drush test-run UserLoginTest) or UI.
Comment #29
smiletrl CreditAttribution: smiletrl commented@aries, yeah, this is an interesting problem as in #24. I get the same issue too.
I suggest do this test manually. Create such user in code directly and login via UI. I agree that there could be some problem with user-login form. Or I'm thinking because the length has been designed in db for 128, this new created user in code could lead to unexpected result from db.
Maybe we could change the way we are testing? Try to create a user with 129 length pass, and get some error? But this page test returns right result:(
Maybe there's problem with drupalPost, like what you assumed. Anyway, let's test this manually, and see what happens:)
Comment #30
aries CreditAttribution: aries commented@smiletrl: I've tested manually, I saved and put the response to pastebin.com. The link is in #24.
Comment #31
smiletrl CreditAttribution: smiletrl commenteda)
returns nothing. I'm not sure where does this scentence come from.
b) my manual test returns 'Sorry, unrecognized username or password. Have you forgotten your password?' when I try to log in with 129 length password.
c)I think we could add something like this in user.module
and do this for user_login_form and user_register_form
This should solve our problem.
We may add some password validate process, like username does
But this validate looks redundant to me, since $form['name'] ['#maxlength'] has already defined the max length.
d) I think we need so something like this to place user_login_block.
But it seems this block is there without such an admin-user. Anyway, just a suggestion.
e) I can't explain why this test returns this wierd result. Perhaps it needs deep exploring code effort:(
Comment #32
aries CreditAttribution: aries commented@smiletrl: your suggestions are already implemented.
Comment #32.0
aries CreditAttribution: aries commentedAdded info about maxlength attribute.
Comment #33
smokrisThis issue also affects Drupal 6.x (and is becoming more noticeable as more of our users are adopting xkcd-style password novellas).
Could we apply the attached backport to Drupal 6.x, then resume work on tests for 8.x?
Comment #35
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedThere are still Drupal 8 patches to review above which add automated tests for this.
Comment #36
dermarioI took the patch from aries in #24 and refactored it a little to make the tests pass against the latest HEAD. Any improvement suggestions are welcome.
Comment #37
dermarioOoops ... sorry something went wrong with my last patch. Please review this one.
Comment #38
dermarioComment #40
nicrodgers@aries are you still working on this, or can it be unassigned?
Comment #41
mparker17Going to assume yes, at least in part because it's been 3 years since @aries worked on it and 3 months since the last patch by @dermario. Plus, it looks like it might be good for someone to review at the Drupal North 2016 code sprint tomorrow.
@aries or @dermario, if you are still working on this, please re-assign it to yourself!
Comment #43
quietone CreditAttribution: quietone as a volunteer commentedPatch applies to 8.2.x and tests pass, assertion messages are fine.
Added interdiff between the latest two patches, #24 and #37. And retesting latest patch with 8.2.x.
Comment #44
quietone CreditAttribution: quietone as a volunteer commentedReviewed the patch in #37. All looks good, at least to me, but I don't know if the changes made in response to #21 are out of scope. Otherwise, I'd RTBC. Anyone care to comment?
Added a summary to the IS.
Comment #46
ZeiP CreditAttribution: ZeiP at Citrus Solutions Oy commentedI re-rolled the patch against 8.3.x. Additionally I changed the last assert calls on both testGlobalLoginFloodControl() and testPerUserLoginFloodControl() to use a valid user, not the invalid one, since that's what the code originally does and it seems to have been changed in error in patch #37.
Comment #47
naveenvalechaComment #49
ZeiP CreditAttribution: ZeiP at Citrus Solutions Oy commentedI ran the tests again against 8.4.x, and it still seems to apply. Hopefully someone finds time to review this.
Comment #51
borisson_I found a couple of things in this patch that should be updated to our new standards. I like the idea of the additional coverage!
Should be {@inheritdoc}
Short array syntax should be used instead.
This is an array of users,
@var \Drupal\user\UserInterface[]
^
We shouldn't use
entity_create
here, we can use thecreateUser
method and pass just the pass to it. That should be sufficient for this.This line can be removed, if we correctly document the $this->userCases parameter.
Should be short array syntax.
No need for the
t
here, as this page is not translated.^
Comment #54
quietone CreditAttribution: quietone as a volunteer commentedAs part of the Bug smash initiative, we are triaging issues that are marked 'Postponed (maintainer needs more info)'. I started with the referenced issue, #2851784: Long passwords allowed when creating account, but logging in fails and continued on to here.
The tests in the latest patch here specifically test long passwords in the user form and in the user login block. There are are also changes to testLoginCacheTagsAndDestination() and testGlobalLoginFloodControl() but these are variable name changes and do not alter the functionality of those tests. Tests of long passwords were added to core in #2378703: Port denial of service fixes from SA-CORE-2014-006 to Drupal 8 in \Drupal\Tests\Core\Password\PasswordHashingTest and there is a test of user login, \Drupal\Tests\user\Functional\UserLoginTest but that doesn't specifically test long passwords and there isn't a test of logging in from the user login block. So, I reckon the work to do here is to add functional tests for logging in on the user page and via the user login block that specifically test long passwords.
Comment #55
quietone CreditAttribution: quietone as a volunteer commentedFollowing on I added a test to UserLoginTest to test the use of long passwords, using PasswordInterface::PASSWORD_MAX_LENGTH for the length, which is 512. Unfortunately the test fails and looking at the html output it reports
Password: may not be longer than 255 characters.
Curious I ran some more tests and found that only passwords with length of < 128 will pass. And further the error message displayed changes depending on the length of the password.
129: Password cannot be longer than 128 characters but is currently 129 characters long.
254: Password cannot be longer than 128 characters but is currently 254 characters long.
512: Password: may not be longer than 255 characters.
Then I went back to review the manual testing I did earlier. I created a password of 521 characters and entered that at user/1/edit and it saved successfully and I could login with that password. I logged out and removed characters from the end of the password to make the password 511 characters long. I could successfully login with that as well. Further testing and found that the max length in 127. At least that agrees with testing results.
The next steps are to understand why the password length is 127 despite what PassowrdInterface states and why the test produces error messages not seen during manual testing (standard profile).
Comment #57
quietone CreditAttribution: quietone as a volunteer commentedSpoke with larowlan on #bugsmash who lead me to \Drupal\Core\Render\Element\Password::getInfo where the field length is set to 128.
So, I have updated the test to verify that passwords of length 128 pass but 129 fail. The IS refers to the login block, but that just uses the accountform anyway, so all should be good here. I don't think an interdiff is needed here.
I intend to make a followup to change the length to 255.
Comment #58
quietone CreditAttribution: quietone as a volunteer commentedDarn, coding standard errors. And I named the patch in comment #57 with '58' instead of '57. Therefor the new patch is name '58a', couldn't think of a better option right now.
Comment #59
larowlanis the . here giving false positives?
Comment #60
quietone CreditAttribution: quietone as a volunteer commentedYes, it was giving false positives. Fixed now.
Comment #61
longwavegetInfo should end with ().
Should we just inject $length and $length + 1 in the string, so when we update $length in the future we only have to do it in one place?
Comment #62
AkashKumar07 CreditAttribution: AkashKumar07 at OpenSense Labs commentedComment #63
AkashKumar07 CreditAttribution: AkashKumar07 at OpenSense Labs commentedMade suggested changes. Please review.
Comment #64
longwaveUsually we don't extract the session to a variable and always call assertSession() each time, sorry for not spotting this before.
This won't work, you just need to put $length and $length + 1 directly into the string.
Comment #66
AkashKumar07 CreditAttribution: AkashKumar07 at OpenSense Labs commentedComment #67
AkashKumar07 CreditAttribution: AkashKumar07 at OpenSense Labs commentedComment #69
AkashKumar07 CreditAttribution: AkashKumar07 at OpenSense Labs commentedComment #71
shetpooja04 CreditAttribution: shetpooja04 at QED42 commentedComment #72
longwaveI still think we don't need a separate variable for $session, we usually just call
$this->assertSession()->...
each time.There are some coding standards issues on this line, . and + operators need spaces either side.
Comment #73
shetpooja04 CreditAttribution: shetpooja04 at QED42 commentedAdded changes and applied patch according to the comment in #72
Please review
Comment #74
samiullah CreditAttribution: samiullah at Salsa Digital commentedPatch is applying correctly.
If code review is fine, this could be moved to RTBCa
Comment #76
shetpooja04 CreditAttribution: shetpooja04 at QED42 commentedIt was a random test failure, setting it to needs review
Comment #80
Kristen PolThanks for the updated patch. I've reviewed the issue summary, patch, and recent comments. Based on the following, I'm marking RTBC.
1. Patch handles the issue noted in the issue summary and nothing else.
2. Code is clear and has been updated to address the most recent comments in #72.
3. Patch applies cleanly to 9.3.x and 9.4.x branches.
4. Test passes.
Comment #81
alexpottThis method could do with some typehints and return typehints and docs.
Also I'm pretty sure the test is using deprecated methods. I.e drupalPostForm()
I think this should use pageTextContains().
Comment #82
joshua1234511Tested the patch from #73 does not apply with 9.4.x-dev.
Updated the patch to work with 9.4.x-dev
Replaced the deprecated functions and added type hints to functions.
Comment #83
joshua1234511Missed adding the Interdiff
Comment #84
Kristen PolThanks for the updated patch. Back to RTBC based on:
1. Reviewed the interdiff for the feedback from #81 and everything appears to be addressed along with adding documentation and fixing coding standards.
2. Patch applies cleanly to 9.3.x (with fuzz) and 9.4.x branches.
3. Test passes.
Comment #85
alexpottCommitted and pushed 34bccfc8138 to 10.0.x and a0ffc4bba21 to 9.4.x. Thanks!
Drupal 7 backports require there own issues as per policy now.