farm-2.x-dev/modules/core/api/tests/src/Functional/CorsResponseEventSubscriberTest.php
modules/core/api/tests/src/Functional/CorsResponseEventSubscriberTest.php
<?php
namespace Drupal\Tests\farm_api\Functional;
use Drupal\consumers\Entity\Consumer;
use Drupal\Core\Url;
use Drupal\Tests\farm_test\Functional\FarmBrowserTestBase;
use Drupal\Tests\jsonapi\Functional\JsonApiRequestTestTrait;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface;
/**
* Tests that CORS headers are properly added.
*
* @group farm
*/
class CorsResponseEventSubscriberTest extends FarmBrowserTestBase {
use JsonApiRequestTestTrait;
/**
* Test consumer entity.
*
* @var \Drupal\consumers\Entity\Consumer
*/
protected $consumer;
/**
* {@inheritdoc}
*/
protected static $modules = [
'farm_api',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Create a consumer for testing.
$this->consumer = Consumer::create([
'label' => $this->getRandomGenerator()->name(),
]);
$this->consumer->save();
}
/**
* Test CORS response headers are correctly added.
*/
public function testCorsResponseHeaders() {
// A request with no Origin should not have CORS headers on the response.
$request_options[RequestOptions::HEADERS]['Accept'] = 'application/vnd.api+json';
$uri = "base://api";
$response = $this->request('OPTIONS', Url::fromUri($uri), $request_options);
$this->assertSame(200, $response->getStatusCode());
$this->assertValidCorsHeaders($response);
// Try an invalid origin.
$farmos_app_origin = 'https://farmOS.app';
$request_options[RequestOptions::HEADERS]['Origin'] = $farmos_app_origin;
$response = $this->request('OPTIONS', Url::fromUri($uri), $request_options);
$this->assertSame(200, $response->getStatusCode());
$this->assertValidCorsHeaders($response);
// Configure an allowed origin on the consumer.
$this->consumer->set('allowed_origins', [$farmos_app_origin]);
$this->consumer->save();
// Make a request with the allowed origin configured.
$response = $this->request('OPTIONS', Url::fromUri($uri), $request_options);
$this->assertSame(200, $response->getStatusCode());
$this->assertValidCorsHeaders($response, $farmos_app_origin);
// Add another allowed_origin and test that multiple allowed origins work.
$custom_app_origin = 'https://customApp.com';
$this->consumer->set('allowed_origins', [$farmos_app_origin, $custom_app_origin]);
$this->consumer->save();
// Make a request from the first allowed origin.
$request_options[RequestOptions::HEADERS]['Origin'] = $farmos_app_origin;
$response = $this->request('OPTIONS', Url::fromUri($uri), $request_options);
$this->assertSame(200, $response->getStatusCode());
$this->assertValidCorsHeaders($response, $farmos_app_origin);
// Make a request from the second allowed origin.
$request_options[RequestOptions::HEADERS]['Origin'] = $custom_app_origin;
$response = $this->request('OPTIONS', Url::fromUri($uri), $request_options);
$this->assertSame(200, $response->getStatusCode());
$this->assertValidCorsHeaders($response, $custom_app_origin);
}
/**
* Helper method to test valid CORS headers.
*
* @param \Psr\Http\Message\ResponseInterface $response
* The response to check.
* @param string|null $origin
* An optional origin to check. If NULL, then the request should have no
* CORS headers.
*/
protected function assertValidCorsHeaders(ResponseInterface $response, string $origin = NULL) {
// Cors headers to test.
$cors_headers = [
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Allow-Headers' => 'Content-Type,Content-Disposition,Authorization,X-CSRF-Token',
'Access-Control-Allow-Methods' => 'GET,POST,PUT,DELETE,HEAD,OPTIONS',
];
// Check if the response should contain headers.
$needs_cors = !empty($origin);
foreach ($cors_headers as $header => $value) {
$this->assertEquals($needs_cors, $response->hasHeader($header), 'Response has correct CORS headers.');
if ($needs_cors) {
$this->assertEquals($value, $response->getHeader($header)[0], 'Response has correct header value.');
}
}
// Confirm that the "Vary" header contains "Origin" when CORS is in use.
if ($needs_cors) {
$this->assertTrue(str_contains($response->getHeader('Vary')[0], 'Origin'), 'Response Vary header contains Origin.');
}
}
}
