diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php index 2ad8dc5..d8845d5 100644 --- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php +++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php @@ -253,6 +253,9 @@ public function validateForm(array &$form, FormStateInterface $form_state) { if ($error = user_validate_name($form_state->getValue(array('account', 'name')))) { $form_state->setErrorByName('account][name', $error); } + if (strlen($form_state->getValue(array('account', 'pass'))) < \Drupal::config('user.settings')->get('minimum_password_length')) { + $form_state->setErrorByName('account][pass', $this->t('Password must be at least @minimum_password_length characters long.', array('@minimum_password_length' => \Drupal::config('user.settings')->get('minimum_password_length')))); + } } /** diff --git a/core/modules/comment/src/Tests/CommentPreviewTest.php b/core/modules/comment/src/Tests/CommentPreviewTest.php index 75aca4d..175313b 100644 --- a/core/modules/comment/src/Tests/CommentPreviewTest.php +++ b/core/modules/comment/src/Tests/CommentPreviewTest.php @@ -40,9 +40,13 @@ function testCommentPreview() { $this->drupalLogout(); // Login as web user and add a user picture. + $password = $this->randomMachineName(); $this->drupalLogin($this->webUser); $image = current($this->drupalGetTestFiles('image')); $edit['files[user_picture_0]'] = drupal_realpath($image->uri); + $edit['current_pass'] = $this->webUser->pass_raw; + $edit['pass[pass1]'] = $password; + $edit['pass[pass2]'] = $password; $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Save')); // As the web user, fill in the comment form and preview the comment. diff --git a/core/modules/contact/src/Tests/ContactPersonalTest.php b/core/modules/contact/src/Tests/ContactPersonalTest.php index a586580..931d58e 100644 --- a/core/modules/contact/src/Tests/ContactPersonalTest.php +++ b/core/modules/contact/src/Tests/ContactPersonalTest.php @@ -202,7 +202,14 @@ function testPersonalContactAccess() { $this->drupalGet('user/' . $this->webUser->id() . '/edit'); $this->assertNoFieldChecked('edit-contact--2'); $this->assertFalse(\Drupal::service('user.data')->get('contact', $this->webUser->id(), 'enabled'), 'Personal contact form disabled'); - $this->drupalPostForm(NULL, array('contact' => TRUE), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + 'contact' => TRUE, + 'current_pass' => $this->webUser->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); + $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Save')); $this->assertFieldChecked('edit-contact--2'); $this->assertTrue(\Drupal::service('user.data')->get('contact', $this->webUser->id(), 'enabled'), 'Personal contact form enabled'); diff --git a/core/modules/path/src/Tests/PathLanguageTest.php b/core/modules/path/src/Tests/PathLanguageTest.php index e14042b..721feab 100644 --- a/core/modules/path/src/Tests/PathLanguageTest.php +++ b/core/modules/path/src/Tests/PathLanguageTest.php @@ -138,7 +138,13 @@ function testAliasTranslation() { $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings')); // Change user language preference. - $edit = array('preferred_langcode' => 'fr'); + $password = $this->randomMachineName(); + $edit = array( + 'preferred_langcode' => 'fr', + 'current_pass' => $this->webUser->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); $this->drupalPostForm("user/" . $this->webUser->id() . "/edit", $edit, t('Save')); // Check that the English alias works. In this situation French is the diff --git a/core/modules/system/src/Tests/Datetime/DrupalDateTimeTest.php b/core/modules/system/src/Tests/Datetime/DrupalDateTimeTest.php index 85ad109..da1dac2 100644 --- a/core/modules/system/src/Tests/Datetime/DrupalDateTimeTest.php +++ b/core/modules/system/src/Tests/Datetime/DrupalDateTimeTest.php @@ -89,7 +89,14 @@ public function testDateTimezone() { $this->drupalLogin($test_user); // Set up the user with a different timezone than the site. - $edit = array('mail' => $test_user->getEmail(), 'timezone' => 'Asia/Manila'); + $password = $this->randomMachineName(); + $edit = array( + 'mail' => $test_user->getEmail(), + 'timezone' => 'Asia/Manila', + 'current_pass' => $test_user->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); $this->drupalPostForm('user/' . $test_user->id() . '/edit', $edit, t('Save')); // Reload the user and reset the timezone in AccountProxy::setAccount(). diff --git a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php index 6fbce81..f69576b 100644 --- a/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php +++ b/core/modules/toolbar/src/Tests/ToolbarAdminMenuTest.php @@ -187,7 +187,14 @@ function testUserRoleUpdateSubtreesHashCacheClear() { $rid = $this->drupalCreateRole(array('administer content types',)); // Assign the role to the user. - $this->drupalPostForm('user/' . $this->adminUser->id() . '/edit', array("roles[$rid]" => $rid), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + "roles[$rid]" => $rid, + "current_pass" => $this->adminUser->pass_raw, + "pass[pass1]" => $password, + "pass[pass2]" => $password, + ); + $this->drupalPostForm('user/' . $this->adminUser->id() . '/edit', $edit, t('Save')); $this->assertText(t('The changes have been saved.')); // Assert that the subtrees hash has been altered because the subtrees @@ -316,7 +323,14 @@ function testNonCurrentUserAccountUpdates() { $admin_user_2_hash = $this->getSubtreesHash(); // Assign the role to the user. - $this->drupalPostForm('user/' . $admin_user_id . '/edit', array("roles[$rid]" => $rid), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + "roles[$rid]" => $rid, + "current_pass" => $this->adminUser->pass_raw, + "pass[pass1]" => $password, + "pass[pass2]" => $password, + ); + $this->drupalPostForm('user/' . $admin_user_id . '/edit', $edit, t('Save')); $this->assertText(t('The changes have been saved.')); // Log in adminUser and assert that the subtrees hash has changed. diff --git a/core/modules/user/config/install/user.settings.yml b/core/modules/user/config/install/user.settings.yml index 8372ccd..89de501 100644 --- a/core/modules/user/config/install/user.settings.yml +++ b/core/modules/user/config/install/user.settings.yml @@ -1,5 +1,6 @@ anonymous: Anonymous verify_mail: true +minimum_password_length: 6 notify: cancel_confirm: true password_reset: true diff --git a/core/modules/user/config/schema/user.schema.yml b/core/modules/user/config/schema/user.schema.yml index 627d8a6..f492b01 100644 --- a/core/modules/user/config/schema/user.schema.yml +++ b/core/modules/user/config/schema/user.schema.yml @@ -10,6 +10,9 @@ user.settings: verify_mail: type: boolean label: 'Require email verification when a visitor creates an account' + minimum_password_length: + type: integer + label: 'The minimum password length required for registration.' notify: type: mapping label: 'Notify user' diff --git a/core/modules/user/src/AccountSettingsForm.php b/core/modules/user/src/AccountSettingsForm.php index df65cb8..da03e53 100644 --- a/core/modules/user/src/AccountSettingsForm.php +++ b/core/modules/user/src/AccountSettingsForm.php @@ -159,6 +159,13 @@ public function buildForm(array $form, FormStateInterface $form_state) { USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL => $this->t('Visitors, but administrator approval is required'), ) ); + $form['registration_cancellation']['minimum_password_length'] = array( + '#type' => 'number', + '#title' => $this->t('Minimum password length'), + '#default_value' => $config->get('minimum_password_length'), + '#description' => $this->t("The minimum password length required for registration."), + '#min' => '1', + ); $form['registration_cancellation']['user_email_verification'] = array( '#type' => 'checkbox', '#title' => $this->t('Require email verification when a visitor creates an account'), @@ -442,6 +449,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $this->config('user.settings') ->set('anonymous', $form_state->getValue('anonymous')) ->set('register', $form_state->getValue('user_register')) + ->set('minimum_password_length', $form_state->getValue('minimum_password_length')) ->set('password_strength', $form_state->getValue('user_password_strength')) ->set('verify_mail', $form_state->getValue('user_email_verification')) ->set('cancel_method', $form_state->getValue('user_cancel_method')) diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php index fa4db6f..3f8b484 100644 --- a/core/modules/user/src/Entity/User.php +++ b/core/modules/user/src/Entity/User.php @@ -471,7 +471,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['pass'] = BaseFieldDefinition::create('password') ->setLabel(t('Password')) ->setDescription(t('The password of this user (hashed).')) - ->addConstraint('ProtectedUserField'); + ->addConstraint('ProtectedUserField') + ->addConstraint('UserPasswordLength'); $fields['mail'] = BaseFieldDefinition::create('email') ->setLabel(t('Email')) diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserPasswordLength.php b/core/modules/user/src/Plugin/Validation/Constraint/UserPasswordLength.php new file mode 100644 index 0000000..1180cfe --- /dev/null +++ b/core/modules/user/src/Plugin/Validation/Constraint/UserPasswordLength.php @@ -0,0 +1,28 @@ +config = $config_factory->get('user.settings'); + } + + /** + * {@inheritdoc} + */ + public function validate($items, Constraint $constraint) { + if (!$items) { + // If no entity is present, we cannot validate. + // @todo Remove once we can access the raw password on user-edits when + // https://www.drupal.org/node/2418119 is resolved. + return; + } + + /* @var \Drupal\Core\Field\FieldItemListInterface $items */ + $password = $items->value; + $entity = $items->getEntity(); + // @todo Revisit user edit password validation when blocker + // https://www.drupal.org/node/2418119 is resolved. + $password_length = Unicode::strlen($password); + $minimum_password_length = $this->config->get('minimum_password_length'); + + if ($password_length < $minimum_password_length) { + $this->context->addViolation($constraint->message, array('@minimum_password_length' => $minimum_password_length)); + } + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static($container->get('config.factory')); + } +} diff --git a/core/modules/user/src/Tests/UserAdminTest.php b/core/modules/user/src/Tests/UserAdminTest.php index 691839d..2dcc819 100644 --- a/core/modules/user/src/Tests/UserAdminTest.php +++ b/core/modules/user/src/Tests/UserAdminTest.php @@ -134,11 +134,22 @@ function testUserAdmin() { $user_d = $this->drupalCreateUser(array()); $user_storage->resetCache(array($user_d->id())); $account1 = $user_storage->load($user_d->id()); - $this->drupalPostForm('user/' . $account1->id() . '/edit', array('status' => 0), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + 'status' => 0, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); + $this->drupalPostForm('user/' . $account1->id() . '/edit', $edit, t('Save')); $user_storage->resetCache(array($user_d->id())); $account1 = $user_storage->load($user_d->id()); $this->assertTrue($account1->isBlocked(), 'User D blocked'); - $this->drupalPostForm('user/' . $account1->id() . '/edit', array('status' => TRUE), t('Save')); + $edit = array( + 'status' => TRUE, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); + $this->drupalPostForm('user/' . $account1->id() . '/edit', $edit, t('Save')); $user_storage->resetCache(array($user_d->id())); $account1 = $user_storage->load($user_d->id()); $this->assertTrue($account1->isActive(), 'User D unblocked'); diff --git a/core/modules/user/src/Tests/UserEditTest.php b/core/modules/user/src/Tests/UserEditTest.php index 46502f4..adba7a6 100644 --- a/core/modules/user/src/Tests/UserEditTest.php +++ b/core/modules/user/src/Tests/UserEditTest.php @@ -49,7 +49,12 @@ function testUserEdit() { $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Email')))); - $edit['current_pass'] = $user1->pass_raw; + $password = $this->randomMachineName(); + $edit = array( + 'current_pass' => $user1->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t("The changes have been saved.")); @@ -61,7 +66,8 @@ function testUserEdit() { $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password')))); // Try again with the current password. - $edit['current_pass'] = $user1->pass_raw; + $edit['current_pass'] = $password; + $this->verbose(serialize($edit)); $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t("The changes have been saved.")); @@ -79,6 +85,7 @@ function testUserEdit() { $this->drupalLogin($user1); $config->set('password_strength', TRUE)->save(); + $edit['current_pass'] = $user1->pass_raw; $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t('Password strength:'), 'The password strength indicator is displayed.'); @@ -99,7 +106,13 @@ function testUserWithoutEmailEdit() { // This user has no email address. $user1->mail = ''; $user1->save(); - $this->drupalPostForm("user/" . $user1->id() . "/edit", array('mail' => ''), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + 'mail' => '', + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); + $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t("The changes have been saved.")); } } diff --git a/core/modules/user/src/Tests/UserEditedOwnAccountTest.php b/core/modules/user/src/Tests/UserEditedOwnAccountTest.php index bee1a9b..266419b 100644 --- a/core/modules/user/src/Tests/UserEditedOwnAccountTest.php +++ b/core/modules/user/src/Tests/UserEditedOwnAccountTest.php @@ -26,14 +26,20 @@ function testUserEditedOwnAccount() { $this->drupalLogin($account); // Change own username. - $edit = array(); - $edit['name'] = $this->randomMachineName(); + $password = $this->randomMachineName(); + $edit = array( + 'name' => $this->randomMachineName(), + 'current_pass' => $account->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); // Log out. $this->drupalLogout(); // Set the new name on the user account and attempt to log back in. + $this->verbose($edit['name']); $account->name = $edit['name']; $this->drupalLogin($account); } diff --git a/core/modules/user/src/Tests/UserLanguageTest.php b/core/modules/user/src/Tests/UserLanguageTest.php index 550aeff..6cda010 100644 --- a/core/modules/user/src/Tests/UserLanguageTest.php +++ b/core/modules/user/src/Tests/UserLanguageTest.php @@ -57,8 +57,12 @@ function testUserLanguageConfiguration() { // Ensure custom language is present. $this->assertText($name, 'Language present on form.'); // Switch to our custom language. + $password = $this->randomMachineName(); $edit = array( 'preferred_langcode' => $langcode, + 'current_pass' => $web_user->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, ); $this->drupalPostForm($path, $edit, t('Save')); // Ensure form was submitted successfully. diff --git a/core/modules/user/src/Tests/UserPictureTest.php b/core/modules/user/src/Tests/UserPictureTest.php index 4f70d44..62ffb5d 100644 --- a/core/modules/user/src/Tests/UserPictureTest.php +++ b/core/modules/user/src/Tests/UserPictureTest.php @@ -59,9 +59,14 @@ function testCreateDeletePicture() { $this->assertRaw(file_uri_target($file->getFileUri()), 'User picture found on user account page.'); // Delete the picture. - $edit = array(); - $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Remove')); - $this->drupalPostForm(NULL, array(), t('Save')); + $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', array(), t('Remove')); + $password = $this->randomMachineName(); + $edit = array( + 'current_pass' => $this->webUser->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); + $this->drupalPostForm(NULL, $edit, t('Save')); // Call file_cron() to clean up the file. Make sure the timestamp // of the file is older than the system.file.temporary_maximum_age @@ -126,7 +131,13 @@ function testPictureOnNodeComment() { * Edits the user picture for the test user. */ function saveUserPicture($image) { - $edit = array('files[user_picture_0]' => drupal_realpath($image->uri)); + $password = $this->randomMachineName(); + $edit = array( + 'files[user_picture_0]' => drupal_realpath($image->uri), + 'current_pass' => $this->webUser->pass_raw, + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + ); $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Save')); // Load actual user data from database. diff --git a/core/modules/user/src/Tests/UserRolesAssignmentTest.php b/core/modules/user/src/Tests/UserRolesAssignmentTest.php index 8e164f5..b713772 100644 --- a/core/modules/user/src/Tests/UserRolesAssignmentTest.php +++ b/core/modules/user/src/Tests/UserRolesAssignmentTest.php @@ -31,13 +31,24 @@ function testAssignAndRemoveRole() { $account = $this->drupalCreateUser(); // Assign the role to the user. - $this->drupalPostForm('user/' . $account->id() . '/edit', array("roles[$rid]" => $rid), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + "roles[$rid]" => $rid, + ); + $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); $this->assertText(t('The changes have been saved.')); $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.'); $this->userLoadAndCheckRoleAssigned($account, $rid); // Remove the role from the user. - $this->drupalPostForm('user/' . $account->id() . '/edit', array("roles[$rid]" => FALSE), t('Save')); + $edit = array( + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + "roles[$rid]" => FALSE, + ); + $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); $this->assertText(t('The changes have been saved.')); $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.'); $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE); @@ -67,7 +78,13 @@ function testCreateUserWithRole() { $this->userLoadAndCheckRoleAssigned($account, $rid); // Remove the role again. - $this->drupalPostForm('user/' . $account->id() . '/edit', array("roles[$rid]" => FALSE), t('Save')); + $password = $this->randomMachineName(); + $edit = array( + 'pass[pass1]' => $password, + 'pass[pass2]' => $password, + "roles[$rid]" => FALSE, + ); + $this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save')); $this->assertText(t('The changes have been saved.')); $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.'); $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE); diff --git a/core/modules/user/src/Tests/UserTimeZoneTest.php b/core/modules/user/src/Tests/UserTimeZoneTest.php index 4a75381..076d05b 100644 --- a/core/modules/user/src/Tests/UserTimeZoneTest.php +++ b/core/modules/user/src/Tests/UserTimeZoneTest.php @@ -61,8 +61,12 @@ function testUserTimeZone() { // Change user time zone to Santiago time. $edit = array(); + $password = $this->randomMachineName(); $edit['mail'] = $web_user->getEmail(); $edit['timezone'] = 'America/Santiago'; + $edit['current_pass'] = $web_user->pass_raw; + $edit['pass[pass1]'] = $password; + $edit['pass[pass2]'] = $password; $this->drupalPostForm("user/" . $web_user->id() . "/edit", $edit, t('Save')); $this->assertText(t('The changes have been saved.'), 'Time zone changed to Santiago time.'); diff --git a/core/modules/user/src/Tests/UserValidationTest.php b/core/modules/user/src/Tests/UserValidationTest.php index ec44a79..7d761f8 100644 --- a/core/modules/user/src/Tests/UserValidationTest.php +++ b/core/modules/user/src/Tests/UserValidationTest.php @@ -180,6 +180,34 @@ function testValidation() { $this->assertEqual(count($violations), 1); $this->assertEqual($violations[0]->getPropertyPath(), 'roles.1'); $this->assertEqual($violations[0]->getMessage(), t('The referenced entity (%entity_type: %name) does not exist.', array('%entity_type' => 'user_role', '%name' => 'unknown_role'))); + + // Test minimium password length validation. + // Default minimum length is 6 characters. + $passwords = [ + // More than 6 characters. + 'valid_pw' => TRUE, + // Less than 6 characters. + 'wrong' => FALSE, + // Check UTF-8 validation: less than 6 characters, but more than 6 bytes. + 'þòøÇß' => FALSE, + ]; + foreach ($passwords as $password => $valid) { + // Test cardinality of user roles. + $user = entity_create('user', array( + 'name' => 'role_test', + 'mail' => 'test@example.com', + 'pass' => $password, + )); + $violations = $user->validate(); + if ($valid) { + $this->assertEqual(count($violations), 0); + } + else { + $this->assertEqual(count($violations), 1); + $this->assertEqual($violations[0]->getPropertyPath(), 'pass'); + $this->assertEqual($violations[0]->getMessage(), t('Password must be at least @minimum_password_length characters long.', ['@minimum_password_length' => 6])); + } + } } /** diff --git a/core/modules/user/user.js b/core/modules/user/user.js index 98d1d0e..4315f3d 100644 --- a/core/modules/user/user.js +++ b/core/modules/user/user.js @@ -105,10 +105,11 @@ var usernameBox = $('input.username'); var username = (usernameBox.length > 0) ? usernameBox.val() : translate.username; - // Lose 5 points for every character less than 6, plus a 30 point penalty. - if (password.length < 6) { + // Lose 5 points for every character less than translate.numCharacters + // plus a 30 point penalty. + if (password.length < translate.minPasswordLength) { msg.push(translate.tooShort); - strength -= ((6 - password.length) * 5) + 30; + strength -= ((translate.minPasswordLength - password.length) * 5) + 30; } // Count weaknesses. diff --git a/core/modules/user/user.module b/core/modules/user/user.module index d175edf..8275399 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -1256,10 +1256,11 @@ function user_form_process_password_confirm($element) { if (\Drupal::config('user.settings')->get('password_strength')) { $password_settings['showStrengthIndicator'] = TRUE; + $password_settings['minPasswordLength'] = \Drupal::config('user.settings')->get('minimum_password_length'); $password_settings += array( 'strengthTitle' => t('Password strength:'), 'hasWeaknesses' => t('To make your password stronger:'), - 'tooShort' => t('Make it at least 6 characters'), + 'tooShort' => t('Make it at least @minimum_password_length characters', array('@minimum_password_length' => \Drupal::config('user.settings')->get('minimum_password_length'))), 'addLowerCase' => t('Add lowercase letters'), 'addUpperCase' => t('Add uppercase letters'), 'addNumbers' => t('Add numbers'),