Problem/Motivation

RegisterForm::submitForm is doing changes in the form state and building the entity again, but those changes were not present in the validation phase so the built user entity has not been completely validated and as a result we are saving not completely validated user entity.

Proposed resolution

Move the changes we are doing in RegisterForm::submitForm to RegisterForm::buildEntity to ensure we are always saving a completely validated user entity.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Comments

hchonov created an issue. See original summary.

hchonov’s picture

Component: entity system » user system
hchonov’s picture

StatusFileSize
new4.99 KB
new5.91 KB

Providing a test proving that the user entity is not currently correctly validated on the user registration form.

hchonov’s picture

StatusFileSize
new5.02 KB
new5.95 KB
new3.5 KB

Better documentation.

The last submitted patch, 3: 2834030-3-test-only.patch, failed testing.

The last submitted patch, 3: 2834030-3-test-with-fix.patch, failed testing.

hchonov’s picture

I've created the constraint on the pass field, as the violations on the init field are filtered out because it is not part of of the list of editable fields.
@see \Drupal\user\AccountForm::getEditedFieldNames().

hchonov’s picture

This bug exists since Drupal 8.0.x.

hchonov’s picture

StatusFileSize
new4.94 KB
new5.86 KB
new712 bytes
hchonov’s picture

StatusFileSize
new5.13 KB
new6.06 KB
new1.62 KB

Activate the constraint only when required so.

The last submitted patch, 4: 2834030-4-test-only.patch, failed testing.

The last submitted patch, 4: 2834030-4-test-with-fix.patch, failed testing.

The last submitted patch, 9: 2834030-9-test-only.patch, failed testing.

The last submitted patch, 9: 2834030-9-test-with-fix.patch, failed testing.

The last submitted patch, 10: 2834030-10-test-only.patch, failed testing.

berdir’s picture

  1. +++ b/core/modules/user/src/Tests/UserRegistrationTest.php
    @@ -393,4 +393,32 @@ protected function assertRegistrationFormCacheTagsWithUserFields() {
    +    // Require email verification and allow registration by site visitors
    +    // without administrator approval in order to generate an automated
    +    // password which has to be validated by the constraint
    +    // "InitialPassConstraint".
    

    Hm, this is a bit weird, though. We're validating something that we generated, that the user actually can't see or do anything about?

    Also the class name here is wrong.

    I understand the problem here and agree with the fix, but it would help to provide realistic test/example that actually makes sense. Can we have a constraint on it and disallow a certain e-mail there?

  2. +++ b/core/modules/user/src/Tests/UserRegistrationTest.php
    @@ -393,4 +393,32 @@ protected function assertRegistrationFormCacheTagsWithUserFields() {
    +    $this->drupalPostForm(NULL, $edit, t('Create new account'));
    

    Can we add some asserts here to see what is happening on the form in this case?

    Also, AFAIK we don't prevent validation errors to fields that are not visible.. or just fields that the user can't see? which might include init... mh...

  3. +++ b/core/modules/user/tests/modules/user_constraint_test/user_constraint_test.module
    @@ -0,0 +1,15 @@
    +function user_constraint_test_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
    +  if ($entity_type->id() == 'user' && !empty($fields['init'])) {
    +    $fields['pass']->addConstraint('AutomaticPassConstraint');
    +  }
    

    How can the init field not exist?

hchonov’s picture

I think I should not write patches when I am tired :). Most of the things are left overs from my initial approach of having a constraint on the "init" field in order to disallow certain email domains. The constraint on the "init" field worked and the constraint failed but the violation was filtered out as the "init" field is not amongst the editable fields in the form - the editable fields for which only the violations are shown are listed under AccountForm::getEditableFields and the "init" field is not amongst them. This is why I switched to a constraint on the "pass" field with an automatically generated password as this appears to be the only one testable approach. I agree that the current test is probably not realistic enough but at least it shows the problem of updating the entity in submit after it has passed the validation instead of validating the entity with the updated values. I will clean up the code tomorrow and will add an assertion that the validation error is shown after submitting the form.

However I think that the test here should be more for demonstrating the problem and probably only the fix should be committed.

hchonov’s picture

StatusFileSize
new5.56 KB
new6.49 KB
new947 bytes
new2.31 KB

The last submitted patch, 18: 2834030-18-test-only.patch, failed testing.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now 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.

berdir’s picture

+++ b/core/modules/user/src/RegisterForm.php
@@ -59,7 +59,7 @@ protected function actions(array $form, FormStateInterface $form_state) {
    */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
+  public function buildEntity(array $form, FormStateInterface $form_state) {

Hm. Technically, this slightly changes the behavior of this a bit without #2833682: In submit use the entity built during the validation instead of building it again - for performance and consistency ensuring we are saving the entity that has been validated, we call this multiple times and generate multiple passwords.

What if we change the code to set the values directly on the entity after building *and* only set it if they are not set yet, at least for the password?

Just thinking out loud, some more opinions from e.g. @tstoeckler would be great here.

hchonov’s picture

I don't think that this is a "behavior change", it just shows that we need the other issue in as well :).

We could change the code but what is the point of reverting it in the other issue?

And also we cannot set and check an entity field as the entity is being built twice and in the second call of the entity builders we do not have the entity object generated from the first run, but a different one - so the field will not be set and we could use only the form state to temporarily store the password, which I would not do, as I don't see any reasons making it that complex.

hchonov’s picture

Issue tags: +DevDaysSeville

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now 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.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now 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.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now 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.

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.

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.

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.

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.

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.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update

This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

Is this postponed on #2833682: In submit use the entity built during the validation instead of building it again - for performance and consistency ensuring we are saving the entity that has been validated?
Tagging for IS for remaining tasks after 6 years.

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.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.