lupus_decoupled-1.x-dev/modules/lupus_decoupled_user_form/tests/src/Functional/LupusSessionDomainFunctionalTest.php

modules/lupus_decoupled_user_form/tests/src/Functional/LupusSessionDomainFunctionalTest.php
<?php

namespace Drupal\Tests\lupus_decoupled_user_form\Functional;

use Drupal\Component\Serialization\Json;
use Drupal\Core\Url;
use Drupal\lupus_decoupled_ce_api\BaseUrlProviderTrait;
use Drupal\Tests\BrowserTestBase;
use GuzzleHttp\Psr7\Response;

/**
 * Tests the session cookie domain configuration and user form api response.
 *
 * @group lupus_decoupled_user_form
 */
class LupusSessionDomainFunctionalTest extends BrowserTestBase {

  use BaseUrlProviderTrait;

  /**
   * The default theme.
   *
   * @var string
   */
  protected $defaultTheme = 'claro';

  /**
   * Modules to enable.
   *
   * @var string[]
   */
  protected static $modules = [
    'system',
    'user',
    'node',
    'field',
    'text',
    'filter',
    'path_alias',
    'schema_metatag',
    'metatag',
    'token',
    'custom_elements',
    'lupus_ce_renderer',
    'lupus_decoupled',
    'lupus_decoupled_ce_api',
    'lupus_decoupled_form',
    'lupus_decoupled_user_form',
    'menu_link_content',
    'rest_menu_items',
  ];

  /**
   * Tests that no custom domain is set by default.
   */
  public function testNoDomainSetByDefault(): void {
    $this->setContainerParameter('session.storage.options', ['cookie_domain' => FALSE]);
    $this->rebuildContainer();
    $account = $this->createUser();
    $this->assertIsObject($account);
    // The 'passRaw' property is intentionally not defined, but is set by
    // UserCreationTrait::createUser() in test environments. Since passwords are
    // only needed for testing, we can safely ignore the PHPStan error.
    /* @phpstan-ignore property.notFound */
    $response = $this->loginRequest($account->getAccountName(), $account->passRaw);
    $this->assertSessionCookie($response, FALSE);
  }

  /**
   * Tests that a custom domain is set when configured.
   */
  public function testCustomDomainSet(): void {
    $this->setContainerParameter('session.storage.options', ['cookie_domain' => '.example.com']);
    $this->rebuildContainer();
    $account = $this->createUser();
    $this->assertIsObject($account);
    // The 'passRaw' property is intentionally not defined, but is set by
    // UserCreationTrait::createUser() in test environments. Since passwords are
    // only needed for testing, we can safely ignore the PHPStan error.
    /* @phpstan-ignore property.notFound */
    $response = $this->loginRequest($account->getAccountName(), $account->passRaw);
    $this->assertSessionCookie($response, TRUE, '.example.com');
  }

  /**
   * Executes a login HTTP request for a given serialization format.
   *
   * @param string $name
   *   The username.
   * @param string $pass
   *   The user password.
   *
   * @return \Psr\Http\Message\ResponseInterface
   *   The HTTP response.
   */
  protected function loginRequest($name, $pass) {
    $user_login_url = Url::fromRoute('user.login.http')
      ->setRouteParameter('_format', 'json')
      ->setAbsolute();
    $request_body = [];
    $request_body['name'] = $name;
    $request_body['pass'] = $pass;

    return \Drupal::httpClient()->post($user_login_url->toString(), [
      'body' => Json::encode($request_body),
      'headers' => [
        'Accept' => "application/json",
      ],
      'http_errors' => FALSE,
    ]);
  }

  /**
   * Asserts the presence or absence of the domain in the session cookie.
   *
   * @param \GuzzleHttp\Psr7\Response $response
   *   The login request response.
   * @param bool $hasDomain
   *   Whether the cookie should have a domain set.
   * @param string|null $expectedDomain
   *   The expected domain value, if $hasDomain is TRUE.
   */
  protected function assertSessionCookie(Response $response, bool $hasDomain, ?string $expectedDomain = NULL): void {
    $session_cookie = $this->getSessionCookie($response);
    $this->assertNotNull($session_cookie, 'Session cookie should be present in Set-Cookie header.');

    if ($hasDomain) {
      $this->assertStringContainsString('domain=' . $expectedDomain, $session_cookie, 'Session cookie should have the correct domain.');
    }
    else {
      $this->assertStringNotContainsString('domain=', $session_cookie, 'Session cookie should not have a domain set.');
    }
  }

  /**
   * Get session cookie.
   *
   * @param \GuzzleHttp\Psr7\Response $response
   *   The login request response.
   *
   * @return string|null
   *   The session cookie header.
   */
  public function getSessionCookie(Response $response): mixed {
    $headers = $response->getHeaders();
    $set_cookie_headers = $headers['Set-Cookie'] ?? [];
    $session_cookie = NULL;
    foreach ($set_cookie_headers as $header) {
      if (strpos($header, 'SESS') === 0) {
        $session_cookie = $header;
        break;
      }
    }
    return $session_cookie;
  }

  /**
   * Assert the session cookie is not set.
   *
   * @param \GuzzleHttp\Psr7\Response $response
   *   The login request response.
   */
  protected function assertNoSessionCookie(Response $response): void {
    $session_cookie = $this->getSessionCookie($response);
    $this->assertNull($session_cookie, 'Session cookie should not be present.');
  }

  /**
   * Test user log in api endpoint.
   */
  public function testUserLoginApi() {
    $response = json_decode($this->drupalGet('ce-api/user/login'), TRUE);
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSame('Log in', $response['title'] ?? []);
    $this->assertSame('user_login_form', $response['content']['props']['formId'] ?? []);
    $this->assertSame('post', $response['content']['props']['method'] ?? []);
    $form_content = $response['content']['slots']['default'] ?? '';
    $this->assertStringContainsString('name="pass"', $form_content);
    $this->assertStringContainsString('User', $form_content);
    $this->assertStringContainsString('Password', $form_content);
    // For logged-in user form is not accessible.
    $user = $this->drupalCreateUser([
      'access content',
      'access content overview',
      'use api operation link',
    ]);
    $this->drupalLogin($user);
    $logged_in_response = json_decode($this->drupalGet('ce-api/user/login'), TRUE);
    $this->assertSession()->statusCodeEquals(403);
    $this->assertSame('Access denied', $logged_in_response['title'] ?? []);
  }

  /**
   * Test logging in through login form.
   */
  public function testLoginFormSubmission() {
    $account = $this->createUser(admin: TRUE);
    $response = json_decode($this->drupalGet('ce-api/user/login'), TRUE);
    $this->assertSession()->statusCodeEquals(200);
    $form_build_id = $this->getFormBuildId($response['content']['slots']['default'] ?? '');
    $multipart = [];
    $multipart[] = [
      'name' => 'name',
      'contents' => $account->getAccountName(),
    ];
    $multipart[] = [
      'name' => 'pass',
      /* @phpstan-ignore property.nonObject */
      'contents' => $account->passRaw,
    ];
    $multipart[] = [
      'name' => 'form_build_id',
      'contents' => $form_build_id,
    ];
    $multipart[] = [
      'name' => 'form_id',
      'contents' => 'user_login_form',
    ];
    $multipart[] = [
      'name' => 'op',
      'contents' => 'Submit',
    ];
    $post = \Drupal::httpClient()->post($this->getBaseUrlProvider()->getAdminBaseUrl() . '/ce-api/user/login', [
      'multipart' => $multipart,
      'headers' => [
        'Accept' => "application/json",
      ],
      'http_errors' => FALSE,
    ]);
    $post->getBody()->rewind();
    $redirect = json_decode($post->getBody()->getContents(), TRUE);
    $this->assertSessionCookie($post, FALSE);
    $this->assertArrayHasKey('redirect', $redirect);
    $this->assertStringContainsString('user', $redirect['redirect']['url']);
    $this->assertSame(303, $redirect['redirect']['statusCode']);
    $multipart[1]['contents'] = 'TestWrongPass';
    $false_pass_post = \Drupal::httpClient()->post($this->getBaseUrlProvider()->getAdminBaseUrl() . '/ce-api/user/login', [
      'multipart' => $multipart,
      'headers' => [
        'Accept' => "application/json",
      ],
      'http_errors' => FALSE,
    ]);
    $this->assertNoSessionCookie($false_pass_post);
    $false_pass_post->getBody()->rewind();
    $false_pass_body = json_decode($false_pass_post->getBody()->getContents(), TRUE);
    // With wrong password get Log In page back again.
    $this->assertStringContainsString('Unrecognized username or password', $false_pass_body['messages']['error'][0]);
    $this->assertSame('Log in', $false_pass_body['title']);
  }

  /**
   * Get form_build_id needed to submit the form.
   *
   * @param string $form_html
   *   Markup of form.
   *
   * @return string|null
   *   Form build id.
   */
  protected function getFormBuildId(string $form_html) {
    $pattern = '/<input[^>]*name=[\\"]+form_build_id[\\"]+[^>]*value=[\\"]+([^\\"]+)[\\"]+/';
    if (preg_match($pattern, $form_html, $matches)) {
      return $matches[1];
    }
    return NULL;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc