CsrfComponentTest.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Controller\Component;
  16. use Cake\Controller\ComponentRegistry;
  17. use Cake\Controller\Component\CsrfComponent;
  18. use Cake\Event\Event;
  19. use Cake\Network\Request;
  20. use Cake\Network\Response;
  21. use Cake\TestSuite\TestCase;
  22. /**
  23. * CsrfComponent test.
  24. */
  25. class CsrfComponentTest extends TestCase {
  26. /**
  27. * setup
  28. *
  29. * @return void
  30. */
  31. public function setUp() {
  32. parent::setUp();
  33. $controller = $this->getMock('Cake\Controller\Controller');
  34. $this->registry = new ComponentRegistry($controller);
  35. $this->component = new CsrfComponent($this->registry);
  36. }
  37. /**
  38. * teardown
  39. *
  40. * @return void
  41. */
  42. public function tearDown() {
  43. parent::tearDown();
  44. unset($this->component);
  45. }
  46. /**
  47. * Test setting the cookie value
  48. *
  49. * @return void
  50. */
  51. public function testSettingCookie() {
  52. $_SERVER['REQUEST_METHOD'] = 'GET';
  53. $controller = $this->getMock('Cake\Controller\Controller');
  54. $controller->request = new Request(['base' => '/dir']);
  55. $controller->response = new Response();
  56. $event = new Event('Controller.startup', $controller);
  57. $this->component->startUp($event);
  58. $cookie = $controller->response->cookie('csrfToken');
  59. $this->assertNotEmpty($cookie, 'Should set a token.');
  60. $this->assertRegExp('/^[a-f0-9]+$/', $cookie['value'], 'Should look like a hash.');
  61. $this->assertEquals(0, $cookie['expiry'], 'session duration.');
  62. $this->assertEquals('/dir', $cookie['path'], 'session path.');
  63. $this->assertEquals($cookie['value'], $controller->request->params['_csrfToken']);
  64. }
  65. /**
  66. * Data provider for HTTP method tests.
  67. *
  68. * @return void
  69. */
  70. public static function httpMethodProvider() {
  71. return [
  72. ['PATCH'], ['PUT'], ['POST'], ['DELETE']
  73. ];
  74. }
  75. /**
  76. * Test that the X-CSRF-Token works with the various http methods.
  77. *
  78. * @dataProvider httpMethodProvider
  79. * @return void
  80. */
  81. public function testValidTokenInHeader($method) {
  82. $_SERVER['REQUEST_METHOD'] = $method;
  83. $_SERVER['HTTP_X_CSRF_TOKEN'] = 'testing123';
  84. $controller = $this->getMock('Cake\Controller\Controller');
  85. $controller->request = new Request(['cookies' => ['csrfToken' => 'testing123']]);
  86. $controller->response = new Response();
  87. $event = new Event('Controller.startup', $controller);
  88. $result = $this->component->startUp($event);
  89. $this->assertNull($result, 'No exception means valid.');
  90. }
  91. /**
  92. * Test that the X-CSRF-Token works with the various http methods.
  93. *
  94. * @dataProvider httpMethodProvider
  95. * @expectedException \Cake\Error\ForbiddenException
  96. * @return void
  97. */
  98. public function testInvalidTokenInHeader($method) {
  99. $_SERVER['REQUEST_METHOD'] = $method;
  100. $_SERVER['HTTP_X_CSRF_TOKEN'] = 'nope';
  101. $controller = $this->getMock('Cake\Controller\Controller');
  102. $controller->request = new Request([
  103. 'cookies' => ['csrfToken' => 'testing123']
  104. ]);
  105. $controller->response = new Response();
  106. $event = new Event('Controller.startup', $controller);
  107. $this->component->startUp($event);
  108. }
  109. /**
  110. * Test that request data works with the various http methods.
  111. *
  112. * @dataProvider httpMethodProvider
  113. * @return void
  114. */
  115. public function testValidTokenRequestData($method) {
  116. $_SERVER['REQUEST_METHOD'] = $method;
  117. $controller = $this->getMock('Cake\Controller\Controller');
  118. $controller->request = new Request([
  119. 'post' => ['_csrfToken' => 'testing123'],
  120. 'cookies' => ['csrfToken' => 'testing123']
  121. ]);
  122. $controller->response = new Response();
  123. $event = new Event('Controller.startup', $controller);
  124. $result = $this->component->startUp($event);
  125. $this->assertNull($result, 'No exception means valid.');
  126. }
  127. /**
  128. * Test that request data works with the various http methods.
  129. *
  130. * @dataProvider httpMethodProvider
  131. * @expectedException \Cake\Error\ForbiddenException
  132. * @return void
  133. */
  134. public function testInvalidTokenRequestData($method) {
  135. $_SERVER['REQUEST_METHOD'] = $method;
  136. $controller = $this->getMock('Cake\Controller\Controller');
  137. $controller->request = new Request([
  138. 'post' => ['_csrfToken' => 'nope'],
  139. 'cookies' => ['csrfToken' => 'testing123']
  140. ]);
  141. $controller->response = new Response();
  142. $event = new Event('Controller.startup', $controller);
  143. $this->component->startUp($event);
  144. }
  145. /**
  146. * Test that CSRF checks are not applied to request action requests.
  147. *
  148. * @return void
  149. */
  150. public function testCsrfValidationSkipsRequestAction() {
  151. $_SERVER['REQUEST_METHOD'] = 'POST';
  152. $controller = $this->getMock('Cake\Controller\Controller');
  153. $controller->request = new Request([
  154. 'params' => ['requested' => 1],
  155. 'post' => ['_csrfToken' => 'nope'],
  156. 'cookies' => ['csrfToken' => 'testing123']
  157. ]);
  158. $controller->response = new Response();
  159. $event = new Event('Controller.startup', $controller);
  160. $result = $this->component->startUp($event);
  161. $this->assertNull($result, 'No error.');
  162. $this->assertEquals('testing123', $controller->request->params['_csrfToken']);
  163. }
  164. /**
  165. * Test that the configuration options work.
  166. *
  167. * @return void
  168. */
  169. public function testConfigurationCookieCreate() {
  170. $_SERVER['REQUEST_METHOD'] = 'GET';
  171. $controller = $this->getMock('Cake\Controller\Controller');
  172. $controller->request = new Request(['base' => '/dir']);
  173. $controller->response = new Response();
  174. $component = new CsrfComponent($this->registry, [
  175. 'cookieName' => 'token',
  176. 'expiry' => 90,
  177. 'secure' => true
  178. ]);
  179. $event = new Event('Controller.startup', $controller);
  180. $component->startUp($event);
  181. $this->assertEmpty($controller->response->cookie('csrfToken'));
  182. $cookie = $controller->response->cookie('token');
  183. $this->assertNotEmpty($cookie, 'Should set a token.');
  184. $this->assertRegExp('/^[a-f0-9]+$/', $cookie['value'], 'Should look like a hash.');
  185. $this->assertEquals(90, $cookie['expiry'], 'session duration.');
  186. $this->assertEquals('/dir', $cookie['path'], 'session path.');
  187. $this->assertTrue($cookie['secure'], 'cookie security flag missing');
  188. }
  189. /**
  190. * Test that the configuration options work.
  191. *
  192. * @return void
  193. */
  194. public function testConfigurationValidate() {
  195. $_SERVER['REQUEST_METHOD'] = 'POST';
  196. $controller = $this->getMock('Cake\Controller\Controller');
  197. $controller->request = new Request([
  198. 'cookies' => ['csrfToken' => 'nope', 'token' => 'yes'],
  199. 'post' => ['_csrfToken' => 'no match', 'token' => 'yes'],
  200. ]);
  201. $controller->response = new Response();
  202. $component = new CsrfComponent($this->registry, [
  203. 'cookieName' => 'token',
  204. 'field' => 'token',
  205. 'expiry' => 90,
  206. ]);
  207. $event = new Event('Controller.startup', $controller);
  208. $result = $component->startUp($event);
  209. $this->assertNull($result, 'Config settings should work.');
  210. }
  211. }