Unverified Commit 361ae1cb authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3109109 by andypost, Hardik_Patel_12, vijaycs85, kkalashnikov,...

Issue #3109109 by andypost, Hardik_Patel_12, vijaycs85, kkalashnikov, alexpott: AccountForm should read pass-reset-token only from query string
parent 0f0ebbec
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ public function form(array $form, FormStateInterface $form_state) {
      // To skip the current password field, the user must have logged in via a
      // one-time link and have the token in the URL. Store this in $form_state
      // so it persists even on subsequent Ajax requests.
      if (!$form_state->get('user_pass_reset') && ($token = $this->getRequest()->get('pass-reset-token'))) {
      if (!$form_state->get('user_pass_reset') && ($token = $this->getRequest()->query->get('pass-reset-token'))) {
        $session_key = 'pass_reset_' . $account->id();
        $user_pass_reset = isset($_SESSION[$session_key]) && hash_equals($_SESSION[$session_key], $token);
        $form_state->set('user_pass_reset', $user_pass_reset);
+94 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\user\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\user\Entity\User;

/**
 * Verifies that the password reset behaves as expected with form elements.
 *
 * @group user
 */
class UserAccountFormPasswordResetTest extends KernelTestBase {

  /**
   * Modules to enable.
   *
   * @var array
   */
  protected static $modules = ['system', 'user'];

  /**
   * User object.
   *
   * @var \Drupal\user\UserInterface
   */
  protected $user;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    // Install default configuration; required for AccountFormController.
    $this->installConfig(['user']);
    $this->installSchema('system', ['sequences']);
    $this->installEntitySchema('user');

    // Create an user to login.
    $this->user = User::create(['name' => 'test']);
    $this->user->save();

    // Set current user.
    $this->container->set('current_user', $this->user);
    // Install the router table and then rebuild.
    \Drupal::service('router.builder')->rebuild();
  }

  /**
   * Tests the reset token used only from query string.
   */
  public function testPasswordResetToken() {
    $token = 'VALID_TOKEN';
    $_SESSION['pass_reset_1'] = $token;
    /** @var \Symfony\Component\HttpFoundation\Request $request */
    $request = $this->container->get('request_stack')->getCurrentRequest();

    // Set token in query string.
    $request->query->set('pass-reset-token', $token);
    $form = $this->buildAccountForm('default');
    // User shouldn't see current password field.
    $this->assertFalse($form['account']['current_pass']['#access']);

    $request->query->set('pass-reset-token', NULL);
    $request->attributes->set('pass-reset-token', $token);
    $form = $this->buildAccountForm('default');
    $this->assertTrue($form['account']['current_pass']['#access']);
  }

  /**
   * Builds the user account form for a given operation.
   *
   * @param string $operation
   *   The entity operation; one of 'register' or 'default'.
   *
   * @return array
   *   The form array.
   */
  protected function buildAccountForm($operation) {
    // @see HtmlEntityFormController::getFormObject()
    $entity_type = 'user';
    $fields = [];
    if ($operation != 'register') {
      $fields['uid'] = $this->user->id();
    }
    $entity = $this->container->get('entity_type.manager')
      ->getStorage($entity_type)
      ->create($fields);

    // @see EntityFormBuilder::getForm()
    return $this->container->get('entity.form_builder')->getForm($entity, $operation);
  }

}