PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/cake/tests/cases/libs/controller/components/security.test.php

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