Make Automatic User Names compatible with Generate Password module.

Created on 17 October 2023, about 1 year ago
Updated 30 July 2024, 4 months ago

Problem/Motivation

"Error message The username contains an illegal character."

Automatic User Names (auto_username:1.5.0) uses \Drupal::service('password_generator')->generate(); to create a temporary username which is saved, before a new one is generated and updated after the fact in hook_user_insert(). This used to be user_password() which was still problematic because that function could be overridden too, and automatically patched to this state by Project Update Bot.

Generate Password (genpass:2.0.1) provides a replacement password_generator service, which uses more possible characters to generate passwords, guaranteeing that at least one of each type of character is included in the password. @see GenpassPasswordGenerator for default character sets.

Drupal core validates the username before it saves the new account in UserNameConstraintValidator, and by setting the username to a password which is almost guaranteed to have a character in it which trip up that validation, giving the "Error message: The username contains an illegal character."

@see https://git.drupalcode.org/project/auto_username/-/blob/8.x-1.x/auto_use...

NB: Automatic User Names (auto_username:1.5.0) is not compatible with Drupal 8.7.7 through Drupal 9.1. The password_generator service was only introduced in Drupal 9.1.0. @see https://www.drupal.org/node/3153113 By using the uuid service, auto_username can be compatible back to Drupal 8.7.7 again (unless there are others changes which are not compatible of course).

Steps to reproduce

On a D9/10 site:

  • Install:
    • Automatic User Names (auto_username:1.5.0)
    • Generate Password (genpass:2.0.1)
  • Configure auto_username with default settings
  • Configure genpass with default settings
  • Attempt to add a user using admin interface, or visitor registration
  • Submission has a high probability of generating a username in the form with an illegal character, but not always.

Proposed resolution

Use uuid service to generate a temporary name that is guaranteed to pass Drupal core's UserNameConstraintValidator. The password_generator service can be replaced or decorated to make more secure passwords, while a UUID is always generated according to RFC 4122.
eg f42fd056-1b53-431c-b09a-210c6b1fb1b0

Remaining tasks

  • ✅ Patch provided to use uuid service.

User interface changes

  • N/A

API changes

  • N/A

Data model changes

  • N/A

Release notes snippet

*h3* Bugs */h3*

Original post

After upgrade to 2.0.0 from alpha1 I cannot create a new user.
It fails with the message: The username contains an illegal character.

This is what ran.

 --------- ----------- --------------- ----------------------------------------
  Module    Update ID   Type            Description
 --------- ----------- --------------- ----------------------------------------
  genpass   8002        hook_update_n   8002 - Enable
                                        "genpass_set_random_password" action.
  genpass   8003        hook_update_n   8003 - Add default setting for
                                        "genpass_admin_mode" to configuration.
  genpass   8004        hook_update_n   8004 - Set "genpass_override_core"
                                        based on "genpass_algorithm" value,
                                        and remove.
 --------- ----------- --------------- ----------------------------------------


 Do you wish to run the specified pending updates? (yes/no) [yes]:
 > yes

>  [notice] Update started: genpass_update_8002
>  [notice] Update completed: genpass_update_8002
>  [notice] Update started: genpass_update_8003
>  [notice] Update completed: genpass_update_8003
>  [notice] Update started: genpass_update_8004
>  [notice] Update completed: genpass_update_8004

See my settings in the screenshot.

There are no other errors logged.
D10.1 seems to have changed the pwd hash.

Can it be connected with D10.1 and the password compatibilty module.
https://www.drupal.org/docs/core-modules-and-themes/core-modules/passwor...

🐛 Bug report
Status

Fixed

Version

1.0

Component

Code

Created by

🇦🇹Austria maxilein

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @maxilein
  • 🇦🇹Austria maxilein

    Maybe I have to add: I did not change the configuration. Everything worked fine in alpha version.
    The username does not contain illeagal characters!

  • Status changed to Postponed: needs info about 1 year ago
  • 🇦🇺Australia elc

    Hi @maxilein,

    I haven't been unable to reproduce this issue so I'm not sure what is causing this for you.

    I can't see how it would be the Password Compatibility module as this works on users with existing users when the log in to replace any old password hashes stored in the database. This is after genpass involvement as the user already exists.

    Steps, all of which worked without error:

    • Install fresh 10.1 site
    • Install genpass:2.0.0-alpha1 (manually; composer jumps to next version)
    • Create user via admin
    • Create user via visitor registration
    • Upgrade to genpass:2.0.0
    • Create user via admin
    • Create user via visitor registration

    Have you implemented hook_genpass_user_forms and told genpass to push a password into the username field? This would end up with password characters in the username alright, but it would be a mis-configuration rather than a bug.

    Could you provide any more steps or configuration which would help in reproducing the problem?

    This is the code which is being triggered in UserNameConstraintValidator.php so one of these characters is ending up in the username. None of these should be provided by genpass.

    <?php
    if (preg_match('/[^\x{80}-\x{F7} a-z0-9@+_.\'-]/i', $name)
          || preg_match(
            // Non-printable ISO-8859-1 + NBSP
            '/[\x{80}-\x{A0}' .
            // Soft-hyphen
            '\x{AD}' .
            // Various space characters
            '\x{2000}-\x{200F}' .
            // Bidirectional text overrides
            '\x{2028}-\x{202F}' .
            // Various text hinting characters
            '\x{205F}-\x{206F}' .
            // Byte order mark
            '\x{FEFF}' .
            // Full-width latin
            '\x{FF01}-\x{FF60}' .
            // Replacement characters
            '\x{FFF9}-\x{FFFD}' .
            // NULL byte and control characters
            '\x{0}-\x{1F}]/u',
            $name)
        ) {
          $this->context->addViolation($constraint->illegalMessage);
        }
    ?>
    
  • 🇦🇹Austria maxilein

    Thank you. I will further investigate on the weekend.

  • 🇦🇹Austria maxilein

    I uninstalled genpass alpha1 and installed 2.0.1. Same results.

    Very tricky: Maybe it is a incompatibility with https://www.drupal.org/project/auto_username ?
    If I disable it I have to add the account manually.

    The scenario: I just want to enter the given and family name manually and derive the account name and password automatically.
    (I also use the realname module to display the name with more details sidewide (2.0.0-beta2).)

    Here is what worked:
    I am using the name field module https://www.drupal.org/project/name (current 8.x-1.x-dev). This provides tokens for given and family seperately.
    To automatically create the account name I am using the pattern
    [user:field_name_name:given].[user:field_name_name:family] from https://www.drupal.org/project/auto_username (auto_username
    Version: 8.x-1.5).
    And genpass automatically creates the password.

    I can only think of some changes in the order function calls?
    Does this help you?

    When using genpass alpha1 everything works (Version: 2.0.0. and Version: 2.0.1 don't)

  • 🇦🇹Austria maxilein

    I went back to alpha1.

  • Status changed to Needs work about 1 year ago
  • 🇦🇺Australia elc

    I can confirm that installing and configuring auto_username:1.5.0 with default settings is causing the error! Does not need the name field to be added.

    First inkling of weirdness is that genpass does not even manage to run post-submission before the error has turned up, which is when it actually does the setting of the password value. Before that it's just changing the visibility of a few fields. I've checked that there aren't any clashes in form key names. Tokens are used and genpass adds tokens to the user bag but getting a bad name would mean adding [user:password] as the username!

    Anyway, having a poke around to see what on earth it could be.

    Ah ... ok? This is why
    https://git.drupalcode.org/project/auto_username/-/blob/8.x-1.x/auto_use...

    /**
     * Implements hook_form_FORM_ID_alter().
     */
    function auto_username_form_user_register_form_alter(&$form, &$form_state, $form_id) {
      $form['account']['name']['#type'] = 'hidden';
      $form['account']['name']['#value'] = \Drupal::service('password_generator')->generate();
    }
    

    That's just not going to work with genpass. The bad username is because it is being set to a literal bad username and Drupal core let try to save it before the real username is generated and added during hook_user_insert. None of the sanitation or cleanup is happening, it's just going straight into Drupal username validation.

    That needs to use something else to come up with a random username to handle that part of the process. It's auto_username that's going to need a patch.

  • Status changed to Needs review about 1 year ago
  • 🇦🇺Australia elc

    Moving this over to Automatic User Names as they'll need to patch to not set of the username to a password in the user creation form.

    Attached is a patch to use the uuid service to generate the name instead, which is guaranteed to pass UserNameConstraintValidator as a UUID is always generated according to RFC 4122.

  • 🇦🇹Austria maxilein

    Well,
    but genpass alpha1 is working with this module...
    just saying...

  • 🇦🇺Australia elc

    As per the release notes of genpass:2.0.0 and issue linked below and as part of that note, this is a significant change from the alpha release of genpass.

    Developers note

    And relevant issue: 📌 Add PasswordGeneratorInterface based service. Remove hook_password Fixed

    Given the release note above, you could choose to turn off the enhanced password generation and use Drupal core generation which would mitigate the illegal character issue also.

    If you wish to continue to use the alpha release into the future, please be aware of the bugs listed in the release notes which may or may not be relevant to you. Here's the full release note: https://www.drupal.org/project/genpass/releases/2.0.0

    The patch provided here fixes auto_username so that both modules could continue to kept updated to latest versions and faultlessly use all their features.

  • 🇦🇹Austria maxilein

    Thank you very much!
    I can confirm that this patch works perfectly.

  • Status changed to RTBC about 1 year ago
  • 🇩🇪Germany Anybody Porta Westfalica

    Confirming that #8 is the correct and a simple solution, as using the password generator was also kind of hacky ;)

  • 🇩🇪Germany Anybody Porta Westfalica

    @ELC thank you very much for the patch. Typically MR's are preferred and speed up fixes a lot, as it's easier for the maintainer to review and merge.

  • Pipeline finished with Skipped
    4 months ago
    #225390
  • First commit to issue fork.
    • jlscott committed d8e7ffd4 on 8.x-1.x authored by ELC
      Issue #3394531 by ELC, maxilein, Anybody:  Make Automatic User Names...
  • Status changed to Fixed 4 months ago
  • 🇳🇿New Zealand jlscott

    Thanks for this simple improvement :) Merge request committed.

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

Production build 0.71.5 2024