Allow changing a user's password

Created on 20 January 2020, over 4 years ago
Updated 7 December 2023, 7 months ago

We allow resetting a user's password through #3106890: Password reset β†’ . However, I am not sure if the JSON:API user resource allows modifying that user's password.

The user module provides the ProtectedUserFieldConstraint constraint. Fields with this constraint require the user object to have the password set on it for comparison.

      // Special case for the password, it being empty means that the existing
      // password should not be changed, ignore empty password fields.
      $value = $items->value;
      if ($field->getName() != 'pass' || !empty($value)) {
        // Compare the values of the field this is being validated on.
        $changed = $items->getValue() != $account_unchanged->get($field->getName())->getValue();
      }
      if ($changed && (!$account->checkExistingPassword($account_unchanged))) {
        $this->context->addViolation($constraint->message, ['%name' => $field->getLabel()]);
      }
    }

The logic is a bit hard to grok. But it is skipped if the following flag is set $account->_skipProtectedUserFieldConstraint. The user reset form turns on this flag by setting a form state storage value.

    // Skip the protected user field constraint if the user came from the
    // password recovery page.
    $account->_skipProtectedUserFieldConstraint = $form_state->get('user_pass_reset');

I have a feeling this means we will need to develop some method of setting the _skipProtectedUserFieldConstraint flag to allow decoupled frontends to change user passwords in a secure matter after they've been reset. We should be able to leverage the same timestamp and hash checking.

✨ Feature request
Status

Closed: works as designed

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States mglaman WI, USA

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

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    This is supported by JSON:API in core natively. See \Drupal\Tests\jsonapi\Functional\UserTest::testPatchDxForSecuritySensitiveBaseFields().

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί
  • Status changed to Needs review 7 months ago
  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    Let's wait for @mglaman to confirm πŸ˜‡

  • Status changed to Closed: works as designed 7 months ago
  • πŸ‡ΊπŸ‡ΈUnited States mglaman WI, USA

    Yes this does seem to already work

        // Test case 2: changing password.
        $normalization = Json::decode((string) $response->getBody());
        $normalization['data']['attributes']['mail'] = 'new-email@example.com';
        $new_password = $this->randomString();
        $normalization['data']['attributes']['pass']['value'] = $new_password;
        $request_options[RequestOptions::BODY] = Json::encode($normalization);
    
        // DX: 422 when changing password without providing the current password.
        $response = $this->request('PATCH', $url, $request_options);
        $this->assertResourceErrorResponse(422, 'pass: Your current password is missing or incorrect; it\'s required to change the Password.', NULL, $response, '/data/attributes/pass');
    
        $normalization['data']['attributes']['pass']['existing'] = $this->account->passRaw;
        $request_options[RequestOptions::BODY] = Json::encode($normalization);
    
        // 200 for well-formed request.
        $response = $this->request('PATCH', $url, $request_options);
        $this->assertResourceResponse(200, FALSE, $response);
    
    
    
  • πŸ‡ΊπŸ‡ΈUnited States mglaman WI, USA
Production build 0.69.0 2024