diff --git a/core/lib/Drupal/Core/Access/CsrfAccessCheck.php b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php index d6ba3a846e22cf62492241f3c5348dbdc8b6f4ce..98be68cc317e2fc2eda7e68b5156d9f3eed78829 100644 --- a/core/lib/Drupal/Core/Access/CsrfAccessCheck.php +++ b/core/lib/Drupal/Core/Access/CsrfAccessCheck.php @@ -51,7 +51,7 @@ public function appliesTo() { public function access(Route $route, Request $request, AccountInterface $account) { // If this is the controller request, check CSRF access as normal. if ($request->attributes->get('_controller_request')) { - return $this->csrfToken->validate($request->query->get('token'), $route->getRequirement('_csrf_token')) ? static::ALLOW : static::KILL; + return $this->csrfToken->validate($request->query->get('token'), $request->attributes->get('_system_path')) ? static::ALLOW : static::KILL; } // Otherwise, this could be another requested access check that we don't diff --git a/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php b/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php index 0fb075cedfd9cc0dc5c30fde2149576178fbd934..f9c12d89efeefccdf9dc5b769d9be3f606d31880 100644 --- a/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php +++ b/core/lib/Drupal/Core/Access/RouteProcessorCsrf.php @@ -39,9 +39,14 @@ function __construct(CsrfTokenGenerator $csrf_token) { */ public function processOutbound(Route $route, array &$parameters) { if ($route->hasRequirement('_csrf_token')) { + $path = $route->getPath(); + // Replace the path parameters with values from the parameters array. + foreach ($parameters as $param => $value) { + $path = str_replace("{{$param}}", $value, $path); + } // Adding this to the parameters means it will get merged into the query // string when the route is compiled. - $parameters['token'] = $this->csrfToken->get($route->getRequirement('_csrf_token')); + $parameters['token'] = $this->csrfToken->get($path); } } diff --git a/core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php index 8c1066944b04265cab65ca73ade9da89fd9ffa59..cbe3951f9038549961cd898367b5b051b822ec2f 100644 --- a/core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php +++ b/core/tests/Drupal/Tests/Core/Access/CsrfAccessCheckTest.php @@ -14,7 +14,7 @@ use Drupal\Tests\UnitTestCase; /** - * Tests the CSRF access checker.. + * Tests the CSRF access checker. * * @group Drupal * @group Access @@ -75,13 +75,12 @@ public function testAppliesTo() { public function testAccessTokenPass() { $this->csrfToken->expects($this->once()) ->method('validate') - ->with('test_query', 'test') + ->with('test_query', '/test-path') ->will($this->returnValue(TRUE)); - $route = new Route('', array(), array('_csrf_token' => 'test')); - $request = new Request(array( - 'token' => 'test_query', - )); + $route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE')); + $request = Request::create('/test-path?token=test_query'); + $request->attributes->set('_system_path', '/test-path'); // Set the _controller_request flag so tokens are validated. $request->attributes->set('_controller_request', TRUE); @@ -94,13 +93,12 @@ public function testAccessTokenPass() { public function testAccessTokenFail() { $this->csrfToken->expects($this->once()) ->method('validate') - ->with('test_query', 'test') + ->with('test_query', '/test-path') ->will($this->returnValue(FALSE)); - $route = new Route('', array(), array('_csrf_token' => 'test')); - $request = new Request(array( - 'token' => 'test_query', - )); + $route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE')); + $request = Request::create('/test-path?token=test_query'); + $request->attributes->set('_system_path', '/test-path'); // Set the _controller_request flag so tokens are validated. $request->attributes->set('_controller_request', TRUE); @@ -116,7 +114,7 @@ public function testAccessTokenMissAny() { $this->csrfToken->expects($this->never()) ->method('validate'); - $route = new Route('', array(), array('_csrf_token' => 'test')); + $route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE')); $request = new Request(array( 'token' => 'test_query', )); @@ -133,7 +131,7 @@ public function testAccessTokenMissAll() { $this->csrfToken->expects($this->never()) ->method('validate'); - $route = new Route('', array(), array('_csrf_token' => 'test'), array('_access_mode' => 'ALL')); + $route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE'), array('_access_mode' => 'ALL')); $request = new Request(array( 'token' => 'test_query', )); diff --git a/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php b/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php index 37eec23ab95d94c92e4f09047e4b41a420956ee5..b57d74b69962cb32c6ff301bfcb61fceb0d788e3 100644 --- a/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php +++ b/core/tests/Drupal/Tests/Core/Access/RouteProcessorCsrfTest.php @@ -58,7 +58,7 @@ public function testProcessOutboundNoRequirement() { $this->csrfToken->expects($this->never()) ->method('get'); - $route = new Route(''); + $route = new Route('/test-path'); $parameters = array(); $this->processor->processOutbound($route, $parameters); @@ -72,10 +72,10 @@ public function testProcessOutboundNoRequirement() { public function testProcessOutbound() { $this->csrfToken->expects($this->once()) ->method('get') - ->with('test') + ->with('/test-path') ->will($this->returnValue('test_token')); - $route = new Route('', array(), array('_csrf_token' => 'test')); + $route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE')); $parameters = array(); $this->processor->processOutbound($route, $parameters); @@ -84,4 +84,34 @@ public function testProcessOutbound() { $this->assertSame($parameters['token'], 'test_token'); } + /** + * Tests the processOutbound() method with a dynamic path and one replacement. + */ + public function testProcessOutboundDynamicOne() { + $this->csrfToken->expects($this->once()) + ->method('get') + ->with('/test-path/100') + ->will($this->returnValue('test_token')); + + $route = new Route('/test-path/{slug}', array(), array('_csrf_token' => 'TRUE')); + $parameters = array('slug' => 100); + + $this->assertNull($this->processor->processOutbound($route, $parameters)); + } + + /** + * Tests the processOutbound() method with two parameter replacements. + */ + public function testProcessOutboundDynamicTwo() { + $this->csrfToken->expects($this->once()) + ->method('get') + ->with('/100/test-path/test') + ->will($this->returnValue('test_token')); + + $route = new Route('{slug_1}/test-path/{slug_2}', array(), array('_csrf_token' => 'TRUE')); + $parameters = array('slug_1' => 100, 'slug_2' => 'test'); + + $this->assertNull($this->processor->processOutbound($route, $parameters)); + } + }