Problem/Motivation

Drupal Core define username max length to 60 characters.

When setting the username in OpenIdConnect::generateUsername(), there is no check on the length of the retrieved value.
I propose to force a truncate to avoid errors when inserting into the database.

Proposed resolution

The original problem is outdated. Since 3.0.0-alpha7, the createUser() method logs an error message and throws a \RuntimeException if the user name or the email address is invalid. The code that calls createUser() catches the exception, shows an error message to the user, and cancels the login attempt.

For this issue, add test coverage for the createUser() method.

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:

Comments

S3b0uN3t created an issue. See original summary.

s3b0un3t’s picture

s3b0un3t’s picture

Title: OpenId Connect don't check username not exceeded max length » OpenId Connect don't check username when exceeded max length
s3b0un3t’s picture

Status: Active » Needs review
jcnventura’s picture

Status: Needs review » Needs work
+++ src/OpenIDConnect.php
@@ -538,14 +538,16 @@
+      $name = mb_substr($original . '_' . $i, 0, UserInterface::USERNAME_MAX_LENGTH - 2);

Seems like a bug here. You need to shorten to max and 2/3 chars less and then append the _i to the username. Instead, you are effectively removing the _i suffix for the case where name length is max.

Also, don't just do "- 2". Instead, do -(number of digits + 1).

s3b0un3t’s picture

Status: Needs work » Needs review
StatusFileSize
new904 bytes

You are right ! I adjusted the patch accordingly.

jcnventura’s picture

Status: Needs review » Needs work

I think the bug is still there.. Imagine there's 1000 'o' in the example below

If original is "really_looooong_string", you're then making it "really_looooong_string_1", and truncating it to be "really_looooo". You first need to truncate it to max - strlen - 1, and only then can you add the suffix.

Also, can you move $original = $name to the line before the for cycle. It's functionally the same, but I don't really think it is readable to instanciate multiple variables in the for like that.

s3b0un3t’s picture

Status: Needs work » Needs review
StatusFileSize
new904 bytes

Indeed ... thoughtlessness from me.
It's time to take holiday!

sanduhrs’s picture

Version: 8.x-1.1 » 8.x-1.x-dev
Status: Needs review » Needs work

It's not only length, but also other characters.
Could we port this from 7.x and also check whether it's still the same in D9/10?
#2872912: Username too long during creation

siliconmeadow’s picture

Title: OpenId Connect don't check username when exceeded max length » Truncate username if it is greater than 60 characters
ajaypratapsingh’s picture

StatusFileSize
new1.14 KB

After suggestions created a patch please review

tuutti made their first commit to this issue’s fork.

tuutti’s picture

Version: 8.x-1.x-dev » 3.x-dev
Assigned: s3b0un3t » Unassigned
tuutti’s picture

Status: Needs work » Needs review
StatusFileSize
new2.83 KB

I've ported the Drupal 7 version of this as suggested in #9. We should probably add a proper test coverage for this tho.

bkosborne’s picture

Wouldn't it be safer to refuse to log the user in rather than manipulate the username like this?

j-lee’s picture

Wouldn't it be safer to refuse to log the user in rather than manipulate the username like this?

We did that. But I think it's a decision that has to be made individually for each project/website. This module must prevent Drupal errors, but should add a hook to change the behavior.

j-lee’s picture

Patch from #14 looks ok for me. But it should add a hook to change the behavior.

steinmb’s picture

Tried to take a step back here as it felt like we tried to invent something that might already be invented, and looked at what core, example: class UserNameValidator and its use of https://symfony.com/doc/current/components/validator.html - Would what be more standardized way to going. I think the migration modules use it as it generate user names during a user migration from example uknown systems that is not Drupal.

tuutti’s picture

But it should add a hook to change the behavior.

What behaviour?

The current implementation attempts to use user's preferred_name, so you can already alter the username by modifying the $userinfo['preferred_username'] in hook_openid_connect_userinfo_alter.

Would what be more standardized way to going. I think the migration modules use it as it generate user names during a user migration from example uknown systems that is not Drupal

The UserNameValidator only validates the username, but doesn't allow us to generate a unique name.

I couldn't find any username generation logic or migration examples with unique usernames besides this one: https://git.drupalcode.org/project/drupal/-/blob/main/core/modules/user/..., used in https://git.drupalcode.org/project/drupal/-/blob/main/core/modules/user/..., which isn't very helpful for this case.

j-lee’s picture

What behaviour?

The current implementation attempts to use user's preferred_name, so you can already alter the username by modifying the $userinfo['preferred_username'] in hook_openid_connect_userinfo_alter.

I meant that the username can be changed from ODIC to Drupal.
With hook_openid_connect_userinfo_alter, that's already done.

pfrilling made their first commit to this issue’s fork.

pfrilling’s picture

The entity validation that was introduced in alpha7 is now handling the username length. I added a kernel test in MR 195 validating that the expected exception is thrown when a username is too long.

pfrilling changed the visibility of the branch 3252021-truncate-username-if to hidden.

pfrilling changed the visibility of the branch 3252021-1 to hidden.

benjifisher’s picture

Issue summary: View changes

@pfrilling:

I guess the original report is outdated as of 3.0.0-alpha7 (as you said in Comment #23). There is some discussion on this issue about what to do when the username (or email) does not validate, but the current behavior is to show an error message, log an error with more detail, and not log in the user.

I agree with that decision (also suggested in Comment #15).

The current MR does not change the behavior, but it adds a Kernel test for the validation added in 3.0.0-alpha7. I am updating the issue summary with a "Proposed resolution" section.

Instead of 6 separate test methods, I would prefer

  1. One test for valid credentials, with a data provider
  2. One test for invalid credentials, with a data provider
  3. One test for duplicate credentials.

If you can think of a way to combine (2) and (3), then that would be even better.

If you do not want to rewrite the tests, then I will not insist.

It looks as though there is a merge conflict in .cspell-project-words.txt, so NW for that. If you always add new words to the end of the file, then you pretty much guarantee that there will be add/add conflicts. If you keep the file sorted, then you have a chance of avoiding that. But an even better strategy is to avoid cspell exceptions: I think you can keep cspell happy by using first_user or firstUser instead of firstuser, for example.

benjifisher’s picture

Status: Needs review » Needs work
pfrilling’s picture

Status: Needs work » Needs review

Thanks @benjifisher. I updated the test to utilize data providers instead of the original individual methods.

benjifisher’s picture

Status: Needs review » Reviewed & tested by the community

@pfrilling:

Thanks for the updates. LGTM

pfrilling’s picture

Status: Reviewed & tested by the community » Fixed

I rebased and added to the merge train.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • pfrilling committed 12c00143 on 3.x
    fix: #3252021 Truncate username if it is greater than 60 characters
    
    By...

Status: Fixed » Closed (fixed)

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