PageRenderTime 64ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php

https://bitbucket.org/canes/cakephp-skeleton-some-examples
PHP | 1399 lines | 845 code | 166 blank | 388 comment | 1 complexity | f0ea21b86cbe191617835957dda2d0fb MD5 | raw file
  1. <?php
  2. /**
  3. * SecurityComponentTest file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  8. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * For full copyright and license information, please see the LICENSE.txt
  12. * Redistributions of files must retain the above copyright notice
  13. *
  14. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  15. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  16. * @package Cake.Test.Case.Controller.Component
  17. * @since CakePHP(tm) v 1.2.0.5435
  18. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  19. */
  20. App::uses('SecurityComponent', 'Controller/Component');
  21. App::uses('Controller', 'Controller');
  22. /**
  23. * TestSecurityComponent
  24. *
  25. * @package Cake.Test.Case.Controller.Component
  26. */
  27. class TestSecurityComponent extends SecurityComponent {
  28. /**
  29. * validatePost method
  30. *
  31. * @param Controller $controller
  32. * @return boolean
  33. */
  34. public function validatePost(Controller $controller) {
  35. return $this->_validatePost($controller);
  36. }
  37. }
  38. /**
  39. * SecurityTestController
  40. *
  41. * @package Cake.Test.Case.Controller.Component
  42. */
  43. class SecurityTestController extends Controller {
  44. /**
  45. * components property
  46. *
  47. * @var array
  48. */
  49. public $components = array('Session', 'TestSecurity');
  50. /**
  51. * failed property
  52. *
  53. * @var boolean false
  54. */
  55. public $failed = false;
  56. /**
  57. * Used for keeping track of headers in test
  58. *
  59. * @var array
  60. */
  61. public $testHeaders = array();
  62. /**
  63. * fail method
  64. *
  65. * @return void
  66. */
  67. public function fail() {
  68. $this->failed = true;
  69. }
  70. /**
  71. * redirect method
  72. *
  73. * @param string|array $url
  74. * @param mixed $code
  75. * @param mixed $exit
  76. * @return void
  77. */
  78. public function redirect($url, $status = null, $exit = true) {
  79. return $status;
  80. }
  81. /**
  82. * Convenience method for header()
  83. *
  84. * @param string $status
  85. * @return void
  86. */
  87. public function header($status) {
  88. $this->testHeaders[] = $status;
  89. }
  90. }
  91. class BrokenCallbackController extends Controller {
  92. public $name = 'UncallableCallback';
  93. public $components = array('Session', 'TestSecurity');
  94. public function index() {
  95. }
  96. protected function _fail() {
  97. }
  98. }
  99. /**
  100. * SecurityComponentTest class
  101. *
  102. * @package Cake.Test.Case.Controller.Component
  103. */
  104. class SecurityComponentTest extends CakeTestCase {
  105. /**
  106. * Controller property
  107. *
  108. * @var SecurityTestController
  109. */
  110. public $Controller;
  111. /**
  112. * oldSalt property
  113. *
  114. * @var string
  115. */
  116. public $oldSalt;
  117. /**
  118. * setUp method
  119. *
  120. * @return void
  121. */
  122. public function setUp() {
  123. parent::setUp();
  124. $request = new CakeRequest('posts/index', false);
  125. $request->addParams(array('controller' => 'posts', 'action' => 'index'));
  126. $this->Controller = new SecurityTestController($request);
  127. $this->Controller->Components->init($this->Controller);
  128. $this->Controller->Security = $this->Controller->TestSecurity;
  129. $this->Controller->Security->blackHoleCallback = 'fail';
  130. $this->Security = $this->Controller->Security;
  131. $this->Security->csrfCheck = false;
  132. Configure::write('Security.salt', 'foo!');
  133. }
  134. /**
  135. * Tear-down method. Resets environment state.
  136. *
  137. * @return void
  138. */
  139. public function tearDown() {
  140. parent::tearDown();
  141. $this->Controller->Session->delete('_Token');
  142. unset($this->Controller->Security);
  143. unset($this->Controller->Component);
  144. unset($this->Controller);
  145. }
  146. /**
  147. * Test that requests are still blackholed when controller has incorrect
  148. * visibility keyword in the blackhole callback
  149. *
  150. * @expectedException BadRequestException
  151. */
  152. public function testBlackholeWithBrokenCallback() {
  153. $request = new CakeRequest('posts/index', false);
  154. $request->addParams(array(
  155. 'controller' => 'posts', 'action' => 'index')
  156. );
  157. $this->Controller = new BrokenCallbackController($request);
  158. $this->Controller->Components->init($this->Controller);
  159. $this->Controller->Security = $this->Controller->TestSecurity;
  160. $this->Controller->Security->blackHoleCallback = '_fail';
  161. $this->Controller->Security->startup($this->Controller);
  162. $this->Controller->Security->blackHole($this->Controller, 'csrf');
  163. }
  164. /**
  165. * Ensure that directly requesting the blackholeCallback as the controller
  166. * action results in an exception.
  167. *
  168. * @return void
  169. */
  170. public function testExceptionWhenActionIsBlackholeCallback() {
  171. $this->Controller->request->addParams(array(
  172. 'controller' => 'posts',
  173. 'action' => 'fail'
  174. ));
  175. $this->assertFalse($this->Controller->failed);
  176. $this->Controller->Security->startup($this->Controller);
  177. $this->assertTrue($this->Controller->failed, 'Request was blackholed.');
  178. }
  179. /**
  180. * test that initialize can set properties.
  181. *
  182. * @return void
  183. */
  184. public function testConstructorSettingProperties() {
  185. $settings = array(
  186. 'requirePost' => array('edit', 'update'),
  187. 'requireSecure' => array('update_account'),
  188. 'requireGet' => array('index'),
  189. 'validatePost' => false,
  190. );
  191. $Security = new SecurityComponent($this->Controller->Components, $settings);
  192. $this->Controller->Security->initialize($this->Controller, $settings);
  193. $this->assertEquals($Security->requirePost, $settings['requirePost']);
  194. $this->assertEquals($Security->requireSecure, $settings['requireSecure']);
  195. $this->assertEquals($Security->requireGet, $settings['requireGet']);
  196. $this->assertEquals($Security->validatePost, $settings['validatePost']);
  197. }
  198. /**
  199. * testStartup method
  200. *
  201. * @return void
  202. */
  203. public function testStartup() {
  204. $this->Controller->Security->startup($this->Controller);
  205. $result = $this->Controller->params['_Token']['key'];
  206. $this->assertNotNull($result);
  207. $this->assertTrue($this->Controller->Session->check('_Token'));
  208. }
  209. /**
  210. * testRequirePostFail method
  211. *
  212. * @return void
  213. */
  214. public function testRequirePostFail() {
  215. $_SERVER['REQUEST_METHOD'] = 'GET';
  216. $this->Controller->request['action'] = 'posted';
  217. $this->Controller->Security->requirePost(array('posted'));
  218. $this->Controller->Security->startup($this->Controller);
  219. $this->assertTrue($this->Controller->failed);
  220. }
  221. /**
  222. * testRequirePostSucceed method
  223. *
  224. * @return void
  225. */
  226. public function testRequirePostSucceed() {
  227. $_SERVER['REQUEST_METHOD'] = 'POST';
  228. $this->Controller->request['action'] = 'posted';
  229. $this->Controller->Security->requirePost('posted');
  230. $this->Security->startup($this->Controller);
  231. $this->assertFalse($this->Controller->failed);
  232. }
  233. /**
  234. * testRequireSecureFail method
  235. *
  236. * @return void
  237. */
  238. public function testRequireSecureFail() {
  239. $_SERVER['HTTPS'] = 'off';
  240. $_SERVER['REQUEST_METHOD'] = 'POST';
  241. $this->Controller->request['action'] = 'posted';
  242. $this->Controller->Security->requireSecure(array('posted'));
  243. $this->Controller->Security->startup($this->Controller);
  244. $this->assertTrue($this->Controller->failed);
  245. }
  246. /**
  247. * testRequireSecureSucceed method
  248. *
  249. * @return void
  250. */
  251. public function testRequireSecureSucceed() {
  252. $_SERVER['REQUEST_METHOD'] = 'Secure';
  253. $this->Controller->request['action'] = 'posted';
  254. $_SERVER['HTTPS'] = 'on';
  255. $this->Controller->Security->requireSecure('posted');
  256. $this->Controller->Security->startup($this->Controller);
  257. $this->assertFalse($this->Controller->failed);
  258. }
  259. /**
  260. * testRequireAuthFail method
  261. *
  262. * @return void
  263. */
  264. public function testRequireAuthFail() {
  265. $_SERVER['REQUEST_METHOD'] = 'AUTH';
  266. $this->Controller->request['action'] = 'posted';
  267. $this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
  268. $this->Controller->Security->requireAuth(array('posted'));
  269. $this->Controller->Security->startup($this->Controller);
  270. $this->assertTrue($this->Controller->failed);
  271. $this->Controller->Session->write('_Token', array('allowedControllers' => array()));
  272. $this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
  273. $this->Controller->request['action'] = 'posted';
  274. $this->Controller->Security->requireAuth('posted');
  275. $this->Controller->Security->startup($this->Controller);
  276. $this->assertTrue($this->Controller->failed);
  277. $this->Controller->Session->write('_Token', array(
  278. 'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted2')
  279. ));
  280. $this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
  281. $this->Controller->request['action'] = 'posted';
  282. $this->Controller->Security->requireAuth('posted');
  283. $this->Controller->Security->startup($this->Controller);
  284. $this->assertTrue($this->Controller->failed);
  285. }
  286. /**
  287. * testRequireAuthSucceed method
  288. *
  289. * @return void
  290. */
  291. public function testRequireAuthSucceed() {
  292. $_SERVER['REQUEST_METHOD'] = 'AUTH';
  293. $this->Controller->request['action'] = 'posted';
  294. $this->Controller->Security->requireAuth('posted');
  295. $this->Controller->Security->startup($this->Controller);
  296. $this->assertFalse($this->Controller->failed);
  297. $this->Controller->Security->Session->write('_Token', array(
  298. 'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted')
  299. ));
  300. $this->Controller->request['controller'] = 'SecurityTest';
  301. $this->Controller->request['action'] = 'posted';
  302. $this->Controller->request->data = array(
  303. 'username' => 'willy', 'password' => 'somePass', '_Token' => ''
  304. );
  305. $this->Controller->action = 'posted';
  306. $this->Controller->Security->requireAuth('posted');
  307. $this->Controller->Security->startup($this->Controller);
  308. $this->assertFalse($this->Controller->failed);
  309. }
  310. /**
  311. * testRequirePostSucceedWrongMethod method
  312. *
  313. * @return void
  314. */
  315. public function testRequirePostSucceedWrongMethod() {
  316. $_SERVER['REQUEST_METHOD'] = 'GET';
  317. $this->Controller->request['action'] = 'getted';
  318. $this->Controller->Security->requirePost('posted');
  319. $this->Controller->Security->startup($this->Controller);
  320. $this->assertFalse($this->Controller->failed);
  321. }
  322. /**
  323. * testRequireGetFail method
  324. *
  325. * @return void
  326. */
  327. public function testRequireGetFail() {
  328. $_SERVER['REQUEST_METHOD'] = 'POST';
  329. $this->Controller->request['action'] = 'getted';
  330. $this->Controller->Security->requireGet(array('getted'));
  331. $this->Controller->Security->startup($this->Controller);
  332. $this->assertTrue($this->Controller->failed);
  333. }
  334. /**
  335. * testRequireGetSucceed method
  336. *
  337. * @return void
  338. */
  339. public function testRequireGetSucceed() {
  340. $_SERVER['REQUEST_METHOD'] = 'GET';
  341. $this->Controller->request['action'] = 'getted';
  342. $this->Controller->Security->requireGet('getted');
  343. $this->Controller->Security->startup($this->Controller);
  344. $this->assertFalse($this->Controller->failed);
  345. }
  346. /**
  347. * testRequireGetSucceedWrongMethod method
  348. *
  349. * @return void
  350. */
  351. public function testRequireGetSucceedWrongMethod() {
  352. $_SERVER['REQUEST_METHOD'] = 'POST';
  353. $this->Controller->request['action'] = 'posted';
  354. $this->Security->requireGet('getted');
  355. $this->Security->startup($this->Controller);
  356. $this->assertFalse($this->Controller->failed);
  357. }
  358. /**
  359. * testRequirePutFail method
  360. *
  361. * @return void
  362. */
  363. public function testRequirePutFail() {
  364. $_SERVER['REQUEST_METHOD'] = 'POST';
  365. $this->Controller->request['action'] = 'putted';
  366. $this->Controller->Security->requirePut(array('putted'));
  367. $this->Controller->Security->startup($this->Controller);
  368. $this->assertTrue($this->Controller->failed);
  369. }
  370. /**
  371. * testRequirePutSucceed method
  372. *
  373. * @return void
  374. */
  375. public function testRequirePutSucceed() {
  376. $_SERVER['REQUEST_METHOD'] = 'PUT';
  377. $this->Controller->request['action'] = 'putted';
  378. $this->Controller->Security->requirePut('putted');
  379. $this->Controller->Security->startup($this->Controller);
  380. $this->assertFalse($this->Controller->failed);
  381. }
  382. /**
  383. * testRequirePutSucceedWrongMethod method
  384. *
  385. * @return void
  386. */
  387. public function testRequirePutSucceedWrongMethod() {
  388. $_SERVER['REQUEST_METHOD'] = 'POST';
  389. $this->Controller->request['action'] = 'posted';
  390. $this->Controller->Security->requirePut('putted');
  391. $this->Controller->Security->startup($this->Controller);
  392. $this->assertFalse($this->Controller->failed);
  393. }
  394. /**
  395. * testRequireDeleteFail method
  396. *
  397. * @return void
  398. */
  399. public function testRequireDeleteFail() {
  400. $_SERVER['REQUEST_METHOD'] = 'POST';
  401. $this->Controller->request['action'] = 'deleted';
  402. $this->Controller->Security->requireDelete(array('deleted', 'other_method'));
  403. $this->Controller->Security->startup($this->Controller);
  404. $this->assertTrue($this->Controller->failed);
  405. }
  406. /**
  407. * testRequireDeleteSucceed method
  408. *
  409. * @return void
  410. */
  411. public function testRequireDeleteSucceed() {
  412. $_SERVER['REQUEST_METHOD'] = 'DELETE';
  413. $this->Controller->request['action'] = 'deleted';
  414. $this->Controller->Security->requireDelete('deleted');
  415. $this->Controller->Security->startup($this->Controller);
  416. $this->assertFalse($this->Controller->failed);
  417. }
  418. /**
  419. * testRequireDeleteSucceedWrongMethod method
  420. *
  421. * @return void
  422. */
  423. public function testRequireDeleteSucceedWrongMethod() {
  424. $_SERVER['REQUEST_METHOD'] = 'POST';
  425. $this->Controller->request['action'] = 'posted';
  426. $this->Controller->Security->requireDelete('deleted');
  427. $this->Controller->Security->startup($this->Controller);
  428. $this->assertFalse($this->Controller->failed);
  429. }
  430. /**
  431. * Simple hash validation test
  432. *
  433. * @return void
  434. */
  435. public function testValidatePost() {
  436. $this->Controller->Security->startup($this->Controller);
  437. $key = $this->Controller->request->params['_Token']['key'];
  438. $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
  439. $unlocked = '';
  440. $this->Controller->request->data = array(
  441. 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
  442. '_Token' => compact('key', 'fields', 'unlocked')
  443. );
  444. $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
  445. }
  446. /**
  447. * Test that validatePost fails if you are missing the session information.
  448. *
  449. * @return void
  450. */
  451. public function testValidatePostNoSession() {
  452. $this->Controller->Security->startup($this->Controller);
  453. $this->Controller->Session->delete('_Token');
  454. $key = $this->Controller->params['_Token']['key'];
  455. $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
  456. $this->Controller->data = array(
  457. 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
  458. '_Token' => compact('key', 'fields')
  459. );
  460. $this->assertFalse($this->Controller->Security->validatePost($this->Controller));
  461. }
  462. /**
  463. * test that validatePost fails if any of its required fields are missing.
  464. *
  465. * @return void
  466. */
  467. public function testValidatePostFormHacking() {
  468. $this->Controller->Security->startup($this->Controller);
  469. $key = $this->Controller->params['_Token']['key'];
  470. $unlocked = '';
  471. $this->Controller->request->data = array(
  472. 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
  473. '_Token' => compact('key', 'unlocked')
  474. );
  475. $result = $this->Controller->Security->validatePost($this->Controller);
  476. $this->assertFalse($result, 'validatePost passed when fields were missing. %s');
  477. }
  478. /**
  479. * Test that objects can't be passed into the serialized string. This was a vector for RFI and LFI
  480. * attacks. Thanks to Felix Wilhelm
  481. *
  482. * @return void
  483. */
  484. public function testValidatePostObjectDeserialize() {
  485. $this->Controller->Security->startup($this->Controller);
  486. $key = $this->Controller->request->params['_Token']['key'];
  487. $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877';
  488. $unlocked = '';
  489. // a corrupted serialized object, so we can see if it ever gets to deserialize
  490. $attack = 'O:3:"App":1:{s:5:"__map";a:1:{s:3:"foo";s:7:"Hacked!";s:1:"fail"}}';
  491. $fields .= urlencode(':' . str_rot13($attack));
  492. $this->Controller->request->data = array(
  493. 'Model' => array('username' => 'mark', 'password' => 'foo', 'valid' => '0'),
  494. '_Token' => compact('key', 'fields', 'unlocked')
  495. );
  496. $result = $this->Controller->Security->validatePost($this->Controller);
  497. $this->assertFalse($result, 'validatePost passed when key was missing. %s');
  498. }
  499. /**
  500. * Tests validation of checkbox arrays
  501. *
  502. * @return void
  503. */
  504. public function testValidatePostArray() {
  505. $this->Controller->Security->startup($this->Controller);
  506. $key = $this->Controller->request->params['_Token']['key'];
  507. $fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A';
  508. $unlocked = '';
  509. $this->Controller->request->data = array(
  510. 'Model' => array('multi_field' => array('1', '3')),
  511. '_Token' => compact('key', 'fields', 'unlocked')
  512. );
  513. $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
  514. }
  515. /**
  516. * testValidatePostNoModel method
  517. *
  518. * @return void
  519. */
  520. public function testValidatePostNoModel() {
  521. $this->Controller->Security->startup($this->Controller);
  522. $key = $this->Controller->request->params['_Token']['key'];
  523. $fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A';
  524. $unlocked = '';
  525. $this->Controller->request->data = array(
  526. 'anything' => 'some_data',
  527. '_Token' => compact('key', 'fields', 'unlocked')
  528. );
  529. $result = $this->Controller->Security->validatePost($this->Controller);
  530. $this->assertTrue($result);
  531. }
  532. /**
  533. * testValidatePostSimple method
  534. *
  535. * @return void
  536. */
  537. public function testValidatePostSimple() {
  538. $this->Controller->Security->startup($this->Controller);
  539. $key = $this->Controller->request->params['_Token']['key'];
  540. $fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A';
  541. $unlocked = '';
  542. $this->Controller->request->data = $data = array(
  543. 'Model' => array('username' => '', 'password' => ''),
  544. '_Token' => compact('key', 'fields', 'unlocked')
  545. );
  546. $result = $this->Controller->Security->validatePost($this->Controller);
  547. $this->assertTrue($result);
  548. }
  549. /**
  550. * Tests hash validation for multiple records, including locked fields
  551. *
  552. * @return void
  553. */
  554. public function testValidatePostComplex() {
  555. $this->Controller->Security->startup($this->Controller);
  556. $key = $this->Controller->request->params['_Token']['key'];
  557. $fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id';
  558. $unlocked = '';
  559. $this->Controller->request->data = array(
  560. 'Addresses' => array(
  561. '0' => array(
  562. 'id' => '123456', 'title' => '', 'first_name' => '', 'last_name' => '',
  563. 'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
  564. ),
  565. '1' => array(
  566. 'id' => '654321', 'title' => '', 'first_name' => '', 'last_name' => '',
  567. 'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
  568. )
  569. ),
  570. '_Token' => compact('key', 'fields', 'unlocked')
  571. );
  572. $result = $this->Controller->Security->validatePost($this->Controller);
  573. $this->assertTrue($result);
  574. }
  575. /**
  576. * test ValidatePost with multiple select elements.
  577. *
  578. * @return void
  579. */
  580. public function testValidatePostMultipleSelect() {
  581. $this->Controller->Security->startup($this->Controller);
  582. $key = $this->Controller->request->params['_Token']['key'];
  583. $fields = '422cde416475abc171568be690a98cad20e66079%3A';
  584. $unlocked = '';
  585. $this->Controller->request->data = array(
  586. 'Tag' => array('Tag' => array(1, 2)),
  587. '_Token' => compact('key', 'fields', 'unlocked'),
  588. );
  589. $result = $this->Controller->Security->validatePost($this->Controller);
  590. $this->assertTrue($result);
  591. $this->Controller->request->data = array(
  592. 'Tag' => array('Tag' => array(1, 2, 3)),
  593. '_Token' => compact('key', 'fields', 'unlocked'),
  594. );
  595. $result = $this->Controller->Security->validatePost($this->Controller);
  596. $this->assertTrue($result);
  597. $this->Controller->request->data = array(
  598. 'Tag' => array('Tag' => array(1, 2, 3, 4)),
  599. '_Token' => compact('key', 'fields', 'unlocked'),
  600. );
  601. $result = $this->Controller->Security->validatePost($this->Controller);
  602. $this->assertTrue($result);
  603. $fields = '19464422eafe977ee729c59222af07f983010c5f%3A';
  604. $this->Controller->request->data = array(
  605. 'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1',
  606. 'Tag' => array('Tag' => array(1)),
  607. '_Token' => compact('key', 'fields', 'unlocked'),
  608. );
  609. $result = $this->Controller->Security->validatePost($this->Controller);
  610. $this->assertTrue($result);
  611. }
  612. /**
  613. * testValidatePostCheckbox method
  614. *
  615. * First block tests un-checked checkbox
  616. * Second block tests checked checkbox
  617. *
  618. * @return void
  619. */
  620. public function testValidatePostCheckbox() {
  621. $this->Controller->Security->startup($this->Controller);
  622. $key = $this->Controller->request->params['_Token']['key'];
  623. $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
  624. $unlocked = '';
  625. $this->Controller->request->data = array(
  626. 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
  627. '_Token' => compact('key', 'fields', 'unlocked')
  628. );
  629. $result = $this->Controller->Security->validatePost($this->Controller);
  630. $this->assertTrue($result);
  631. $fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A';
  632. $this->Controller->request->data = array(
  633. 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
  634. '_Token' => compact('key', 'fields', 'unlocked')
  635. );
  636. $result = $this->Controller->Security->validatePost($this->Controller);
  637. $this->assertTrue($result);
  638. $this->Controller->request->data = array();
  639. $this->Controller->Security->startup($this->Controller);
  640. $key = $this->Controller->request->params['_Token']['key'];
  641. $this->Controller->request->data = array(
  642. 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
  643. '_Token' => compact('key', 'fields', 'unlocked')
  644. );
  645. $result = $this->Controller->Security->validatePost($this->Controller);
  646. $this->assertTrue($result);
  647. }
  648. /**
  649. * testValidatePostHidden method
  650. *
  651. * @return void
  652. */
  653. public function testValidatePostHidden() {
  654. $this->Controller->Security->startup($this->Controller);
  655. $key = $this->Controller->request->params['_Token']['key'];
  656. $fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden';
  657. $unlocked = '';
  658. $this->Controller->request->data = array(
  659. 'Model' => array(
  660. 'username' => '', 'password' => '', 'hidden' => '0',
  661. 'other_hidden' => 'some hidden value'
  662. ),
  663. '_Token' => compact('key', 'fields', 'unlocked')
  664. );
  665. $result = $this->Controller->Security->validatePost($this->Controller);
  666. $this->assertTrue($result);
  667. }
  668. /**
  669. * testValidatePostWithDisabledFields method
  670. *
  671. * @return void
  672. */
  673. public function testValidatePostWithDisabledFields() {
  674. $this->Controller->Security->disabledFields = array('Model.username', 'Model.password');
  675. $this->Controller->Security->startup($this->Controller);
  676. $key = $this->Controller->request->params['_Token']['key'];
  677. $fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden';
  678. $unlocked = '';
  679. $this->Controller->request->data = array(
  680. 'Model' => array(
  681. 'username' => '', 'password' => '', 'hidden' => '0'
  682. ),
  683. '_Token' => compact('fields', 'key', 'unlocked')
  684. );
  685. $result = $this->Controller->Security->validatePost($this->Controller);
  686. $this->assertTrue($result);
  687. }
  688. /**
  689. * test validating post data with posted unlocked fields.
  690. *
  691. * @return void
  692. */
  693. public function testValidatePostDisabledFieldsInData() {
  694. $this->Controller->Security->startup($this->Controller);
  695. $key = $this->Controller->request->params['_Token']['key'];
  696. $unlocked = 'Model.username';
  697. $fields = array('Model.hidden', 'Model.password');
  698. $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
  699. $this->Controller->request->data = array(
  700. 'Model' => array(
  701. 'username' => 'mark',
  702. 'password' => 'sekret',
  703. 'hidden' => '0'
  704. ),
  705. '_Token' => compact('fields', 'key', 'unlocked')
  706. );
  707. $result = $this->Controller->Security->validatePost($this->Controller);
  708. $this->assertTrue($result);
  709. }
  710. /**
  711. * test that missing 'unlocked' input causes failure
  712. *
  713. * @return void
  714. */
  715. public function testValidatePostFailNoDisabled() {
  716. $this->Controller->Security->startup($this->Controller);
  717. $key = $this->Controller->request->params['_Token']['key'];
  718. $fields = array('Model.hidden', 'Model.password', 'Model.username');
  719. $fields = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt')));
  720. $this->Controller->request->data = array(
  721. 'Model' => array(
  722. 'username' => 'mark',
  723. 'password' => 'sekret',
  724. 'hidden' => '0'
  725. ),
  726. '_Token' => compact('fields', 'key')
  727. );
  728. $result = $this->Controller->Security->validatePost($this->Controller);
  729. $this->assertFalse($result);
  730. }
  731. /**
  732. * Test that validatePost fails when unlocked fields are changed.
  733. *
  734. * @return
  735. */
  736. public function testValidatePostFailDisabledFieldTampering() {
  737. $this->Controller->Security->startup($this->Controller);
  738. $key = $this->Controller->request->params['_Token']['key'];
  739. $unlocked = 'Model.username';
  740. $fields = array('Model.hidden', 'Model.password');
  741. $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
  742. // Tamper the values.
  743. $unlocked = 'Model.username|Model.password';
  744. $this->Controller->request->data = array(
  745. 'Model' => array(
  746. 'username' => 'mark',
  747. 'password' => 'sekret',
  748. 'hidden' => '0'
  749. ),
  750. '_Token' => compact('fields', 'key', 'unlocked')
  751. );
  752. $result = $this->Controller->Security->validatePost($this->Controller);
  753. $this->assertFalse($result);
  754. }
  755. /**
  756. * testValidateHiddenMultipleModel method
  757. *
  758. * @return void
  759. */
  760. public function testValidateHiddenMultipleModel() {
  761. $this->Controller->Security->startup($this->Controller);
  762. $key = $this->Controller->request->params['_Token']['key'];
  763. $fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid';
  764. $unlocked = '';
  765. $this->Controller->request->data = array(
  766. 'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
  767. 'Model2' => array('valid' => '0'),
  768. 'Model3' => array('valid' => '0'),
  769. '_Token' => compact('key', 'fields', 'unlocked')
  770. );
  771. $result = $this->Controller->Security->validatePost($this->Controller);
  772. $this->assertTrue($result);
  773. }
  774. /**
  775. * testValidateHasManyModel method
  776. *
  777. * @return void
  778. */
  779. public function testValidateHasManyModel() {
  780. $this->Controller->Security->startup($this->Controller);
  781. $key = $this->Controller->request->params['_Token']['key'];
  782. $fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid';
  783. $fields .= '%7CModel.1.hidden%7CModel.1.valid';
  784. $unlocked = '';
  785. $this->Controller->request->data = array(
  786. 'Model' => array(
  787. array(
  788. 'username' => 'username', 'password' => 'password',
  789. 'hidden' => 'value', 'valid' => '0'
  790. ),
  791. array(
  792. 'username' => 'username', 'password' => 'password',
  793. 'hidden' => 'value', 'valid' => '0'
  794. )
  795. ),
  796. '_Token' => compact('key', 'fields', 'unlocked')
  797. );
  798. $result = $this->Controller->Security->validatePost($this->Controller);
  799. $this->assertTrue($result);
  800. }
  801. /**
  802. * testValidateHasManyRecordsPass method
  803. *
  804. * @return void
  805. */
  806. public function testValidateHasManyRecordsPass() {
  807. $this->Controller->Security->startup($this->Controller);
  808. $key = $this->Controller->request->params['_Token']['key'];
  809. $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
  810. $fields .= 'Address.1.id%7CAddress.1.primary';
  811. $unlocked = '';
  812. $this->Controller->request->data = array(
  813. 'Address' => array(
  814. 0 => array(
  815. 'id' => '123',
  816. 'title' => 'home',
  817. 'first_name' => 'Bilbo',
  818. 'last_name' => 'Baggins',
  819. 'address' => '23 Bag end way',
  820. 'city' => 'the shire',
  821. 'phone' => 'N/A',
  822. 'primary' => '1',
  823. ),
  824. 1 => array(
  825. 'id' => '124',
  826. 'title' => 'home',
  827. 'first_name' => 'Frodo',
  828. 'last_name' => 'Baggins',
  829. 'address' => '50 Bag end way',
  830. 'city' => 'the shire',
  831. 'phone' => 'N/A',
  832. 'primary' => '1'
  833. )
  834. ),
  835. '_Token' => compact('key', 'fields', 'unlocked')
  836. );
  837. $result = $this->Controller->Security->validatePost($this->Controller);
  838. $this->assertTrue($result);
  839. }
  840. /**
  841. * Test that values like Foo.0.1
  842. *
  843. * @return void
  844. */
  845. public function testValidateNestedNumericSets() {
  846. $this->Controller->Security->startup($this->Controller);
  847. $key = $this->Controller->request->params['_Token']['key'];
  848. $unlocked = '';
  849. $hashFields = array('TaxonomyData');
  850. $fields = urlencode(Security::hash(serialize($hashFields) . $unlocked . Configure::read('Security.salt')));
  851. $this->Controller->request->data = array(
  852. 'TaxonomyData' => array(
  853. 1 => array(array(2)),
  854. 2 => array(array(3))
  855. ),
  856. '_Token' => compact('key', 'fields', 'unlocked')
  857. );
  858. $result = $this->Controller->Security->validatePost($this->Controller);
  859. $this->assertTrue($result);
  860. }
  861. /**
  862. * testValidateHasManyRecords method
  863. *
  864. * validatePost should fail, hidden fields have been changed.
  865. *
  866. * @return void
  867. */
  868. public function testValidateHasManyRecordsFail() {
  869. $this->Controller->Security->startup($this->Controller);
  870. $key = $this->Controller->request->params['_Token']['key'];
  871. $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
  872. $fields .= 'Address.1.id%7CAddress.1.primary';
  873. $unlocked = '';
  874. $this->Controller->request->data = array(
  875. 'Address' => array(
  876. 0 => array(
  877. 'id' => '123',
  878. 'title' => 'home',
  879. 'first_name' => 'Bilbo',
  880. 'last_name' => 'Baggins',
  881. 'address' => '23 Bag end way',
  882. 'city' => 'the shire',
  883. 'phone' => 'N/A',
  884. 'primary' => '5',
  885. ),
  886. 1 => array(
  887. 'id' => '124',
  888. 'title' => 'home',
  889. 'first_name' => 'Frodo',
  890. 'last_name' => 'Baggins',
  891. 'address' => '50 Bag end way',
  892. 'city' => 'the shire',
  893. 'phone' => 'N/A',
  894. 'primary' => '1'
  895. )
  896. ),
  897. '_Token' => compact('key', 'fields', 'unlocked')
  898. );
  899. $result = $this->Controller->Security->validatePost($this->Controller);
  900. $this->assertFalse($result);
  901. }
  902. /**
  903. * testFormDisabledFields method
  904. *
  905. * @return void
  906. */
  907. public function testFormDisabledFields() {
  908. $this->Controller->Security->startup($this->Controller);
  909. $key = $this->Controller->request->params['_Token']['key'];
  910. $fields = '11842060341b9d0fc3808b90ba29fdea7054d6ad%3An%3A0%3A%7B%7D';
  911. $unlocked = '';
  912. $this->Controller->request->data = array(
  913. 'MyModel' => array('name' => 'some data'),
  914. '_Token' => compact('key', 'fields', 'unlocked')
  915. );
  916. $result = $this->Controller->Security->validatePost($this->Controller);
  917. $this->assertFalse($result);
  918. $this->Controller->Security->startup($this->Controller);
  919. $this->Controller->Security->disabledFields = array('MyModel.name');
  920. $key = $this->Controller->request->params['_Token']['key'];
  921. $this->Controller->request->data = array(
  922. 'MyModel' => array('name' => 'some data'),
  923. '_Token' => compact('key', 'fields', 'unlocked')
  924. );
  925. $result = $this->Controller->Security->validatePost($this->Controller);
  926. $this->assertTrue($result);
  927. }
  928. /**
  929. * testRadio method
  930. *
  931. * @return void
  932. */
  933. public function testRadio() {
  934. $this->Controller->Security->startup($this->Controller);
  935. $key = $this->Controller->request->params['_Token']['key'];
  936. $fields = '575ef54ca4fc8cab468d6d898e9acd3a9671c17e%3An%3A0%3A%7B%7D';
  937. $unlocked = '';
  938. $this->Controller->request->data = array(
  939. '_Token' => compact('key', 'fields', 'unlocked')
  940. );
  941. $result = $this->Controller->Security->validatePost($this->Controller);
  942. $this->assertFalse($result);
  943. $this->Controller->request->data = array(
  944. '_Token' => compact('key', 'fields', 'unlocked'),
  945. 'Test' => array('test' => '')
  946. );
  947. $result = $this->Controller->Security->validatePost($this->Controller);
  948. $this->assertTrue($result);
  949. $this->Controller->request->data = array(
  950. '_Token' => compact('key', 'fields', 'unlocked'),
  951. 'Test' => array('test' => '1')
  952. );
  953. $result = $this->Controller->Security->validatePost($this->Controller);
  954. $this->assertTrue($result);
  955. $this->Controller->request->data = array(
  956. '_Token' => compact('key', 'fields', 'unlocked'),
  957. 'Test' => array('test' => '2')
  958. );
  959. $result = $this->Controller->Security->validatePost($this->Controller);
  960. $this->assertTrue($result);
  961. }
  962. /**
  963. * test that a requestAction's controller will have the _Token appended to
  964. * the params.
  965. *
  966. * @return void
  967. * @see https://cakephp.lighthouseapp.com/projects/42648/tickets/68
  968. */
  969. public function testSettingTokenForRequestAction() {
  970. $this->Controller->Security->startup($this->Controller);
  971. $key = $this->Controller->request->params['_Token']['key'];
  972. $this->Controller->params['requested'] = 1;
  973. unset($this->Controller->request->params['_Token']);
  974. $this->Controller->Security->startup($this->Controller);
  975. $this->assertEquals($this->Controller->request->params['_Token']['key'], $key);
  976. }
  977. /**
  978. * test that blackhole doesn't delete the _Token session key so repeat data submissions
  979. * stay blackholed.
  980. *
  981. * @link https://cakephp.lighthouseapp.com/projects/42648/tickets/214
  982. * @return void
  983. */
  984. public function testBlackHoleNotDeletingSessionInformation() {
  985. $this->Controller->Security->startup($this->Controller);
  986. $this->Controller->Security->blackHole($this->Controller, 'auth');
  987. $this->assertTrue($this->Controller->Security->Session->check('_Token'), '_Token was deleted by blackHole %s');
  988. }
  989. /**
  990. * test that csrf checks are skipped for request action.
  991. *
  992. * @return void
  993. */
  994. public function testCsrfSkipRequestAction() {
  995. $_SERVER['REQUEST_METHOD'] = 'POST';
  996. $this->Security->validatePost = false;
  997. $this->Security->csrfCheck = true;
  998. $this->Security->csrfExpires = '+10 minutes';
  999. $this->Controller->request->params['requested'] = 1;
  1000. $this->Security->startup($this->Controller);
  1001. $this->assertFalse($this->Controller->failed, 'fail() was called.');
  1002. }
  1003. /**
  1004. * test setting
  1005. *
  1006. * @return void
  1007. */
  1008. public function testCsrfSettings() {
  1009. $this->Security->validatePost = false;
  1010. $this->Security->csrfCheck = true;
  1011. $this->Security->csrfExpires = '+10 minutes';
  1012. $this->Security->startup($this->Controller);
  1013. $token = $this->Security->Session->read('_Token');
  1014. $this->assertEquals(1, count($token['csrfTokens']), 'Missing the csrf token.');
  1015. $this->assertEquals(strtotime('+10 minutes'), current($token['csrfTokens']), 'Token expiry does not match');
  1016. $this->assertEquals(array('key', 'unlockedFields'), array_keys($this->Controller->request->params['_Token']), 'Keys don not match');
  1017. }
  1018. /**
  1019. * Test setting multiple nonces, when startup() is called more than once, (ie more than one request.)
  1020. *
  1021. * @return void
  1022. */
  1023. public function testCsrfSettingMultipleNonces() {
  1024. $this->Security->validatePost = false;
  1025. $this->Security->csrfCheck = true;
  1026. $this->Security->csrfExpires = '+10 minutes';
  1027. $csrfExpires = strtotime('+10 minutes');
  1028. $this->Security->startup($this->Controller);
  1029. $this->Security->startup($this->Controller);
  1030. $token = $this->Security->Session->read('_Token');
  1031. $this->assertEquals(2, count($token['csrfTokens']), 'Missing the csrf token.');
  1032. foreach ($token['csrfTokens'] as $expires) {
  1033. $diff = $csrfExpires - $expires;
  1034. $this->assertTrue($diff === 0 || $diff === 1, 'Token expiry does not match');
  1035. }
  1036. }
  1037. /**
  1038. * test that nonces are consumed by form submits.
  1039. *
  1040. * @return void
  1041. */
  1042. public function testCsrfNonceConsumption() {
  1043. $this->Security->validatePost = false;
  1044. $this->Security->csrfCheck = true;
  1045. $this->Security->csrfExpires = '+10 minutes';
  1046. $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
  1047. $this->Controller->request = $this->getMock('CakeRequest', array('is'));
  1048. $this->Controller->request->expects($this->once())->method('is')
  1049. ->with('post')
  1050. ->will($this->returnValue(true));
  1051. $this->Controller->request->params['action'] = 'index';
  1052. $this->Controller->request->data = array(
  1053. '_Token' => array(
  1054. 'key' => 'nonce1'
  1055. ),
  1056. 'Post' => array(
  1057. 'title' => 'Woot'
  1058. )
  1059. );
  1060. $this->Security->startup($this->Controller);
  1061. $token = $this->Security->Session->read('_Token');
  1062. $this->assertFalse(isset($token['csrfTokens']['nonce1']), 'Token was not consumed');
  1063. }
  1064. /**
  1065. * test that expired values in the csrfTokens are cleaned up.
  1066. *
  1067. * @return void
  1068. */
  1069. public function testCsrfNonceVacuum() {
  1070. $this->Security->validatePost = false;
  1071. $this->Security->csrfCheck = true;
  1072. $this->Security->csrfExpires = '+10 minutes';
  1073. $this->Security->Session->write('_Token.csrfTokens', array(
  1074. 'valid' => strtotime('+30 minutes'),
  1075. 'poof' => strtotime('-11 minutes'),
  1076. 'dust' => strtotime('-20 minutes')
  1077. ));
  1078. $this->Security->startup($this->Controller);
  1079. $tokens = $this->Security->Session->read('_Token.csrfTokens');
  1080. $this->assertEquals(2, count($tokens), 'Too many tokens left behind');
  1081. $this->assertNotEmpty('valid', $tokens, 'Valid token was removed.');
  1082. }
  1083. /**
  1084. * test that when the key is missing the request is blackHoled
  1085. *
  1086. * @return void
  1087. */
  1088. public function testCsrfBlackHoleOnKeyMismatch() {
  1089. $this->Security->validatePost = false;
  1090. $this->Security->csrfCheck = true;
  1091. $this->Security->csrfExpires = '+10 minutes';
  1092. $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
  1093. $this->Controller->request = $this->getMock('CakeRequest', array('is'));
  1094. $this->Controller->request->expects($this->once())->method('is')
  1095. ->with('post')
  1096. ->will($this->returnValue(true));
  1097. $this->Controller->request->params['action'] = 'index';
  1098. $this->Controller->request->data = array(
  1099. '_Token' => array(
  1100. 'key' => 'not the right value'
  1101. ),
  1102. 'Post' => array(
  1103. 'title' => 'Woot'
  1104. )
  1105. );
  1106. $this->Security->startup($this->Controller);
  1107. $this->assertTrue($this->Controller->failed, 'fail() was not called.');
  1108. }
  1109. /**
  1110. * test that when the key is missing the request is blackHoled
  1111. *
  1112. * @return void
  1113. */
  1114. public function testCsrfBlackHoleOnExpiredKey() {
  1115. $this->Security->validatePost = false;
  1116. $this->Security->csrfCheck = true;
  1117. $this->Security->csrfExpires = '+10 minutes';
  1118. $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('-5 minutes')));
  1119. $this->Controller->request = $this->getMock('CakeRequest', array('is'));
  1120. $this->Controller->request->expects($this->once())->method('is')
  1121. ->with('post')
  1122. ->will($this->returnValue(true));
  1123. $this->Controller->request->params['action'] = 'index';
  1124. $this->Controller->request->data = array(
  1125. '_Token' => array(
  1126. 'key' => 'nonce1'
  1127. ),
  1128. 'Post' => array(
  1129. 'title' => 'Woot'
  1130. )
  1131. );
  1132. $this->Security->startup($this->Controller);
  1133. $this->assertTrue($this->Controller->failed, 'fail() was not called.');
  1134. }
  1135. /**
  1136. * test that csrfUseOnce = false works.
  1137. *
  1138. * @return void
  1139. */
  1140. public function testCsrfNotUseOnce() {
  1141. $this->Security->validatePost = false;
  1142. $this->Security->csrfCheck = true;
  1143. $this->Security->csrfUseOnce = false;
  1144. $this->Security->csrfExpires = '+10 minutes';
  1145. // Generate one token
  1146. $this->Security->startup($this->Controller);
  1147. $token = $this->Security->Session->read('_Token.csrfTokens');
  1148. $this->assertEquals(1, count($token), 'Should only be one token.');
  1149. $this->Security->startup($this->Controller);
  1150. $tokenTwo = $this->Security->Session->read('_Token.csrfTokens');
  1151. $this->assertEquals(1, count($tokenTwo), 'Should only be one token.');
  1152. $this->assertEquals($token, $tokenTwo, 'Tokens should not be different.');
  1153. $key = $this->Controller->request->params['_Token']['key'];
  1154. $this->assertEquals(array($key), array_keys($token), '_Token.key and csrfToken do not match request will blackhole.');
  1155. }
  1156. /**
  1157. * ensure that longer session tokens are not consumed
  1158. *
  1159. * @return void
  1160. */
  1161. public function testCsrfNotUseOnceValidationLeavingToken() {
  1162. $this->Security->validatePost = false;
  1163. $this->Security->csrfCheck = true;
  1164. $this->Security->csrfUseOnce = false;
  1165. $this->Security->csrfExpires = '+10 minutes';
  1166. $this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
  1167. $this->Controller->request = $this->getMock('CakeRequest', array('is'));
  1168. $this->Controller->request->expects($this->once())->method('is')
  1169. ->with('post')
  1170. ->will($this->returnValue(true));
  1171. $this->Controller->request->params['action'] = 'index';
  1172. $this->Controller->request->data = array(
  1173. '_Token' => array(
  1174. 'key' => 'nonce1'
  1175. ),
  1176. 'Post' => array(
  1177. 'title' => 'Woot'
  1178. )
  1179. );
  1180. $this->Security->startup($this->Controller);
  1181. $token = $this->Security->Session->read('_Token');
  1182. $this->assertTrue(isset($token['csrfTokens']['nonce1']), 'Token was consumed');
  1183. }
  1184. /**
  1185. * Test generateToken()
  1186. *
  1187. * @return void
  1188. */
  1189. public function testGenerateToken() {
  1190. $request = $this->Controller->request;
  1191. $this->Security->generateToken($request);
  1192. $this->assertNotEmpty($request->params['_Token']);
  1193. $this->assertTrue(isset($request->params['_Token']['unlockedFields']));
  1194. $this->assertTrue(isset($request->params['_Token']['key']));
  1195. }
  1196. /**
  1197. * Test the limiting of CSRF tokens.
  1198. *
  1199. * @return void
  1200. */
  1201. public function testCsrfLimit() {
  1202. $this->Security->csrfLimit = 3;
  1203. $time = strtotime('+10 minutes');
  1204. $tokens = array(
  1205. '1' => $time,
  1206. '2' => $time,
  1207. '3' => $time,
  1208. '4' => $time,
  1209. '5' => $time,
  1210. );
  1211. $this->Security->Session->write('_Token', array('csrfTokens' => $tokens));
  1212. $this->Security->generateToken($this->Controller->request);
  1213. $result = $this->Security->Session->read('_Token.csrfTokens');
  1214. $this->assertFalse(isset($result['1']));
  1215. $this->assertFalse(isset($result['2']));
  1216. $this->assertFalse(isset($result['3']));
  1217. $this->assertTrue(isset($result['4']));
  1218. $this->assertTrue(isset($result['5']));
  1219. }
  1220. /**
  1221. * Test unlocked actions
  1222. *
  1223. * @return void
  1224. */
  1225. public function testUnlockedActions() {
  1226. $_SERVER['REQUEST_METHOD'] = 'POST';
  1227. $this->Controller->request->data = array('data');
  1228. $this->Controller->Security->unlockedActions = 'index';
  1229. $this->Controller->Security->blackHoleCallback = null;
  1230. $result = $this->Controller->Security->startup($this->Controller);
  1231. $this->assertNull($result);
  1232. }
  1233. }