From 08b493a20287bf8466ccb9288cb17602e6bc7ee9 Mon Sep 17 00:00:00 2001 From: Dave Long <dave@longwaveconsulting.com> Date: Tue, 17 Oct 2023 12:42:37 +0200 Subject: [PATCH] Issue #3205688 by jedihe, mr.baileys, dpagini: Include allowedOriginsPatterns in default.services.yml (regex matching for CORS) --- .../scaffold/files/default.services.yml | 2 + .../HttpKernel/CorsIntegrationTest.php | 47 +++++++++++++++++++ sites/default/default.services.yml | 2 + 3 files changed, 51 insertions(+) diff --git a/core/assets/scaffold/files/default.services.yml b/core/assets/scaffold/files/default.services.yml index 8a6cdf2f77fa..c4b964fc2900 100644 --- a/core/assets/scaffold/files/default.services.yml +++ b/core/assets/scaffold/files/default.services.yml @@ -214,6 +214,8 @@ parameters: # Configure requests allowed from specific origins. Do not include trailing # slashes with URLs. allowedOrigins: ['*'] + # Configure requests allowed from origins, matching against regex patterns. + allowedOriginsPatterns: [] # Sets the Access-Control-Expose-Headers header. exposedHeaders: false # Sets the Access-Control-Max-Age header. diff --git a/core/tests/Drupal/FunctionalTests/HttpKernel/CorsIntegrationTest.php b/core/tests/Drupal/FunctionalTests/HttpKernel/CorsIntegrationTest.php index ac21766b0d2d..99ea4944ea36 100644 --- a/core/tests/Drupal/FunctionalTests/HttpKernel/CorsIntegrationTest.php +++ b/core/tests/Drupal/FunctionalTests/HttpKernel/CorsIntegrationTest.php @@ -65,8 +65,55 @@ public function testCrossSiteRequest() { $this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', '*'); $this->assertSession()->responseHeaderNotContains('Vary', 'Origin'); + // Configure the CORS stack to match allowed origins using regex patterns. + $cors_config['allowedOrigins'] = []; + $cors_config['allowedOriginsPatterns'] = ['#^http://[a-z-]*\.valid.com$#']; + + $this->setContainerParameter('cors.config', $cors_config); + $this->rebuildContainer(); + + // Fire a request from an origin that isn't allowed. + /** @var \Symfony\Component\HttpFoundation\Response $response */ + $this->drupalGet('/test-page', [], ['Origin' => 'http://non-valid.com']); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseHeaderDoesNotExist('Access-Control-Allow-Origin'); + $this->assertSession()->responseHeaderContains('Vary', 'Origin'); + + // Specify a valid origin. + $this->drupalGet('/test-page', [], ['Origin' => 'http://sub-domain.valid.com']); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://sub-domain.valid.com'); + $this->assertSession()->responseHeaderContains('Vary', 'Origin'); + + // Test combining allowedOrigins and allowedOriginsPatterns. + $cors_config['allowedOrigins'] = ['http://domainA.com']; + $cors_config['allowedOriginsPatterns'] = ['#^http://domain[B-Z-]*\.com$#']; + + $this->setContainerParameter('cors.config', $cors_config); + $this->rebuildContainer(); + + // Specify an origin that does not match allowedOrigins nor + // allowedOriginsPattern. + $this->drupalGet('/test-page', [], ['Origin' => 'http://non-valid.com']); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseHeaderDoesNotExist('Access-Control-Allow-Origin'); + $this->assertSession()->responseHeaderContains('Vary', 'Origin'); + + // Specify a valid origin that matches allowedOrigins. + $this->drupalGet('/test-page', [], ['Origin' => 'http://domainA.com']); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://domainA.com'); + $this->assertSession()->responseHeaderContains('Vary', 'Origin'); + + // Specify a valid origin that matches allowedOriginsPatterns. + $this->drupalGet('/test-page', [], ['Origin' => 'http://domainX.com']); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseHeaderEquals('Access-Control-Allow-Origin', 'http://domainX.com'); + $this->assertSession()->responseHeaderContains('Vary', 'Origin'); + // Configure the CORS stack to allow a specific origin. $cors_config['allowedOrigins'] = ['http://example.com']; + $cors_config['allowedOriginsPatterns'] = []; $this->setContainerParameter('cors.config', $cors_config); $this->rebuildContainer(); diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml index 8a6cdf2f77fa..c4b964fc2900 100644 --- a/sites/default/default.services.yml +++ b/sites/default/default.services.yml @@ -214,6 +214,8 @@ parameters: # Configure requests allowed from specific origins. Do not include trailing # slashes with URLs. allowedOrigins: ['*'] + # Configure requests allowed from origins, matching against regex patterns. + allowedOriginsPatterns: [] # Sets the Access-Control-Expose-Headers header. exposedHeaders: false # Sets the Access-Control-Max-Age header. -- GitLab