CakeSessionTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. <?php
  2. /**
  3. * SessionTest file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
  15. * @package Cake.Test.Case.Model.Datasource
  16. * @since CakePHP(tm) v 1.2.0.4206
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. App::uses('CakeSession', 'Model/Datasource');
  20. class TestCakeSession extends CakeSession {
  21. public static function setUserAgent($value) {
  22. self::$_userAgent = $value;
  23. }
  24. public static function setHost($host) {
  25. self::_setHost($host);
  26. }
  27. }
  28. /**
  29. * CakeSessionTest class
  30. *
  31. * @package Cake.Test.Case.Model.Datasource
  32. */
  33. class CakeSessionTest extends CakeTestCase {
  34. protected static $_gcDivisor;
  35. /**
  36. * Fixtures used in the SessionTest
  37. *
  38. * @var array
  39. */
  40. public $fixtures = array('core.session');
  41. /**
  42. * setup before class.
  43. *
  44. * @return void
  45. */
  46. public static function setupBeforeClass() {
  47. // Make sure garbage colector will be called
  48. self::$_gcDivisor = ini_get('session.gc_divisor');
  49. ini_set('session.gc_divisor', '1');
  50. }
  51. /**
  52. * teardown after class
  53. *
  54. * @return void
  55. */
  56. public static function teardownAfterClass() {
  57. // Revert to the default setting
  58. ini_set('session.gc_divisor', self::$_gcDivisor);
  59. }
  60. /**
  61. * setUp method
  62. *
  63. * @return void
  64. */
  65. public function setup() {
  66. parent::setup();
  67. Configure::write('Session', array(
  68. 'defaults' => 'php',
  69. 'cookie' => 'cakephp',
  70. 'timeout' => 120,
  71. 'cookieTimeout' => 120,
  72. 'ini' => array(),
  73. ));
  74. TestCakeSession::init();
  75. }
  76. /**
  77. * tearDown method
  78. *
  79. * @return void
  80. */
  81. public function teardown() {
  82. if (TestCakeSession::started()) {
  83. TestCakeSession::clear();
  84. }
  85. unset($_SESSION);
  86. parent::teardown();
  87. }
  88. /**
  89. * test setting ini properties with Session configuration.
  90. *
  91. * @return void
  92. */
  93. public function testSessionConfigIniSetting() {
  94. $_SESSION = null;
  95. Configure::write('Session', array(
  96. 'cookie' => 'test',
  97. 'checkAgent' => false,
  98. 'timeout' => 86400,
  99. 'ini' => array(
  100. 'session.referer_check' => 'example.com',
  101. 'session.use_trans_sid' => false
  102. )
  103. ));
  104. TestCakeSession::start();
  105. $this->assertEquals('', ini_get('session.use_trans_sid'), 'Ini value is incorrect');
  106. $this->assertEquals('example.com', ini_get('session.referer_check'), 'Ini value is incorrect');
  107. $this->assertEquals('test', ini_get('session.name'), 'Ini value is incorrect');
  108. }
  109. /**
  110. * testSessionPath
  111. *
  112. * @return void
  113. */
  114. public function testSessionPath() {
  115. TestCakeSession::init('/index.php');
  116. $this->assertEquals(TestCakeSession::$path, '/');
  117. TestCakeSession::init('/sub_dir/index.php');
  118. $this->assertEquals(TestCakeSession::$path, '/sub_dir/');
  119. }
  120. /**
  121. * testCakeSessionPathEmpty
  122. *
  123. * @return void
  124. */
  125. public function testCakeSessionPathEmpty() {
  126. TestCakeSession::init('');
  127. $this->assertEquals(TestCakeSession::$path, '/', 'Session path is empty, with "" as $base needs to be /');
  128. }
  129. /**
  130. * testCakeSessionPathContainsParams
  131. *
  132. * @return void
  133. */
  134. public function testCakeSessionPathContainsQuestion() {
  135. TestCakeSession::init('/index.php?');
  136. $this->assertEquals(TestCakeSession::$path, '/');
  137. }
  138. /**
  139. * testSetHost
  140. *
  141. * @return void
  142. */
  143. public function testSetHost() {
  144. TestCakeSession::init();
  145. TestCakeSession::setHost('cakephp.org');
  146. $this->assertEquals(TestCakeSession::$host, 'cakephp.org');
  147. }
  148. /**
  149. * testSetHostWithPort
  150. *
  151. * @return void
  152. */
  153. public function testSetHostWithPort() {
  154. TestCakeSession::init();
  155. TestCakeSession::setHost('cakephp.org:443');
  156. $this->assertEquals(TestCakeSession::$host, 'cakephp.org');
  157. }
  158. /**
  159. * test valid with bogus user agent.
  160. *
  161. * @return void
  162. */
  163. public function testValidBogusUserAgent() {
  164. Configure::write('Session.checkAgent', true);
  165. TestCakeSession::start();
  166. $this->assertTrue(TestCakeSession::valid(), 'Newly started session should be valid');
  167. TestCakeSession::userAgent('bogus!');
  168. $this->assertFalse(TestCakeSession::valid(), 'user agent mismatch should fail.');
  169. }
  170. /**
  171. * test valid with bogus user agent.
  172. *
  173. * @return void
  174. */
  175. public function testValidTimeExpiry() {
  176. Configure::write('Session.checkAgent', true);
  177. TestCakeSession::start();
  178. $this->assertTrue(TestCakeSession::valid(), 'Newly started session should be valid');
  179. TestCakeSession::$time = strtotime('next year');
  180. $this->assertFalse(TestCakeSession::valid(), 'time should cause failure.');
  181. }
  182. /**
  183. * testCheck method
  184. *
  185. * @return void
  186. */
  187. public function testCheck() {
  188. TestCakeSession::write('SessionTestCase', 'value');
  189. $this->assertTrue(TestCakeSession::check('SessionTestCase'));
  190. $this->assertFalse(TestCakeSession::check('NotExistingSessionTestCase'), false);
  191. }
  192. /**
  193. * testSimpleRead method
  194. *
  195. * @return void
  196. */
  197. public function testSimpleRead() {
  198. TestCakeSession::write('testing', '1,2,3');
  199. $result = TestCakeSession::read('testing');
  200. $this->assertEquals('1,2,3', $result);
  201. TestCakeSession::write('testing', array('1' => 'one', '2' => 'two','3' => 'three'));
  202. $result = TestCakeSession::read('testing.1');
  203. $this->assertEquals('one', $result);
  204. $result = TestCakeSession::read('testing');
  205. $this->assertEquals(array('1' => 'one', '2' => 'two', '3' => 'three'), $result);
  206. $result = TestCakeSession::read();
  207. $this->assertTrue(isset($result['testing']));
  208. $this->assertTrue(isset($result['Config']));
  209. $this->assertTrue(isset($result['Config']['userAgent']));
  210. TestCakeSession::write('This.is.a.deep.array.my.friend', 'value');
  211. $result = TestCakeSession::read('This.is.a.deep.array.my.friend');
  212. $this->assertEquals($result, 'value');
  213. }
  214. /**
  215. * testReadyEmpty
  216. *
  217. * @return void
  218. */
  219. public function testReadyEmpty() {
  220. $this->assertFalse(TestCakeSession::read(''));
  221. }
  222. /**
  223. * test writing a hash of values/
  224. *
  225. * @return void
  226. */
  227. public function testWriteArray() {
  228. $result = TestCakeSession::write(array(
  229. 'one' => 1,
  230. 'two' => 2,
  231. 'three' => array('something'),
  232. 'null' => null
  233. ));
  234. $this->assertTrue($result);
  235. $this->assertEquals(1, TestCakeSession::read('one'));
  236. $this->assertEquals(array('something'), TestCakeSession::read('three'));
  237. $this->assertEquals(null, TestCakeSession::read('null'));
  238. }
  239. /**
  240. * testWriteEmptyKey
  241. *
  242. * @return void
  243. */
  244. public function testWriteEmptyKey() {
  245. $this->assertFalse(TestCakeSession::write('', 'graham'));
  246. $this->assertFalse(TestCakeSession::write('', ''));
  247. $this->assertFalse(TestCakeSession::write(''));
  248. }
  249. /**
  250. * testId method
  251. *
  252. * @return void
  253. */
  254. public function testId() {
  255. TestCakeSession::destroy();
  256. $result = TestCakeSession::id();
  257. $expected = session_id();
  258. $this->assertEquals($expected, $result);
  259. TestCakeSession::id('MySessionId');
  260. $result = TestCakeSession::id();
  261. $this->assertEquals('MySessionId', $result);
  262. }
  263. /**
  264. * testStarted method
  265. *
  266. * @return void
  267. */
  268. public function testStarted() {
  269. unset($_SESSION);
  270. $_SESSION = null;
  271. $this->assertFalse(TestCakeSession::started());
  272. $this->assertTrue(TestCakeSession::start());
  273. $this->assertTrue(TestCakeSession::started());
  274. }
  275. /**
  276. * testError method
  277. *
  278. * @return void
  279. */
  280. public function testError() {
  281. TestCakeSession::read('Does.not.exist');
  282. $result = TestCakeSession::error();
  283. $this->assertEquals("Does.not.exist doesn't exist", $result);
  284. TestCakeSession::delete('Failing.delete');
  285. $result = TestCakeSession::error();
  286. $this->assertEquals("Failing.delete doesn't exist", $result);
  287. }
  288. /**
  289. * testDel method
  290. *
  291. * @return void
  292. */
  293. public function testDelete() {
  294. $this->assertTrue(TestCakeSession::write('Delete.me', 'Clearing out'));
  295. $this->assertTrue(TestCakeSession::delete('Delete.me'));
  296. $this->assertFalse(TestCakeSession::check('Delete.me'));
  297. $this->assertTrue(TestCakeSession::check('Delete'));
  298. $this->assertTrue(TestCakeSession::write('Clearing.sale', 'everything must go'));
  299. $this->assertTrue(TestCakeSession::delete('Clearing'));
  300. $this->assertFalse(TestCakeSession::check('Clearing.sale'));
  301. $this->assertFalse(TestCakeSession::check('Clearing'));
  302. }
  303. /**
  304. * testDestroy method
  305. *
  306. * @return void
  307. */
  308. public function testDestroy() {
  309. TestCakeSession::write('bulletProof', 'invicible');
  310. $id = TestCakeSession::id();
  311. TestCakeSession::destroy();
  312. $this->assertFalse(TestCakeSession::check('bulletProof'));
  313. $this->assertNotEqual($id, TestCakeSession::id());
  314. }
  315. /**
  316. * testCheckingSavedEmpty method
  317. *
  318. * @return void
  319. */
  320. public function testCheckingSavedEmpty() {
  321. $this->assertTrue(TestCakeSession::write('SessionTestCase', 0));
  322. $this->assertTrue(TestCakeSession::check('SessionTestCase'));
  323. $this->assertTrue(TestCakeSession::write('SessionTestCase', '0'));
  324. $this->assertTrue(TestCakeSession::check('SessionTestCase'));
  325. $this->assertTrue(TestCakeSession::write('SessionTestCase', false));
  326. $this->assertTrue(TestCakeSession::check('SessionTestCase'));
  327. $this->assertTrue(TestCakeSession::write('SessionTestCase', null));
  328. $this->assertFalse(TestCakeSession::check('SessionTestCase'));
  329. }
  330. /**
  331. * testCheckKeyWithSpaces method
  332. *
  333. * @return void
  334. */
  335. public function testCheckKeyWithSpaces() {
  336. $this->assertTrue(TestCakeSession::write('Session Test', "test"));
  337. $this->assertEquals('test', TestCakeSession::check('Session Test'));
  338. TestCakeSession::delete('Session Test');
  339. $this->assertTrue(TestCakeSession::write('Session Test.Test Case', "test"));
  340. $this->assertTrue(TestCakeSession::check('Session Test.Test Case'));
  341. }
  342. /**
  343. * testCheckEmpty
  344. *
  345. * @return void
  346. */
  347. public function testCheckEmpty() {
  348. $this->assertFalse(TestCakeSession::check());
  349. }
  350. /**
  351. * test key exploitation
  352. *
  353. * @return void
  354. */
  355. public function testKeyExploit() {
  356. $key = "a'] = 1; phpinfo(); \$_SESSION['a";
  357. $result = TestCakeSession::write($key, 'haxored');
  358. $this->assertTrue($result);
  359. $result = TestCakeSession::read($key);
  360. $this->assertEquals('haxored', $result);
  361. }
  362. /**
  363. * testReadingSavedEmpty method
  364. *
  365. * @return void
  366. */
  367. public function testReadingSavedEmpty() {
  368. TestCakeSession::write('SessionTestCase', 0);
  369. $this->assertEquals(0, TestCakeSession::read('SessionTestCase'));
  370. TestCakeSession::write('SessionTestCase', '0');
  371. $this->assertEquals('0', TestCakeSession::read('SessionTestCase'));
  372. $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0);
  373. TestCakeSession::write('SessionTestCase', false);
  374. $this->assertFalse(TestCakeSession::read('SessionTestCase'));
  375. TestCakeSession::write('SessionTestCase', null);
  376. $this->assertEquals(null, TestCakeSession::read('SessionTestCase'));
  377. }
  378. /**
  379. * testCheckUserAgentFalse method
  380. *
  381. * @return void
  382. */
  383. public function testCheckUserAgentFalse() {
  384. Configure::write('Session.checkAgent', false);
  385. TestCakeSession::setUserAgent(md5('http://randomdomainname.com' . Configure::read('Security.salt')));
  386. $this->assertTrue(TestCakeSession::valid());
  387. }
  388. /**
  389. * testCheckUserAgentTrue method
  390. *
  391. * @return void
  392. */
  393. public function testCheckUserAgentTrue() {
  394. Configure::write('Session.checkAgent', true);
  395. TestCakeSession::$error = false;
  396. $agent = md5('http://randomdomainname.com' . Configure::read('Security.salt'));
  397. TestCakeSession::write('Config.userAgent', md5('Hacking you!'));
  398. TestCakeSession::setUserAgent($agent);
  399. $this->assertFalse(TestCakeSession::valid());
  400. }
  401. /**
  402. * testReadAndWriteWithDatabaseStorage method
  403. *
  404. * @return void
  405. */
  406. public function testReadAndWriteWithCakeStorage() {
  407. Configure::write('Session.defaults', 'cake');
  408. TestCakeSession::init();
  409. TestCakeSession::start();
  410. TestCakeSession::write('SessionTestCase', 0);
  411. $this->assertEquals(0, TestCakeSession::read('SessionTestCase'));
  412. TestCakeSession::write('SessionTestCase', '0');
  413. $this->assertEquals('0', TestCakeSession::read('SessionTestCase'));
  414. $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0);
  415. TestCakeSession::write('SessionTestCase', false);
  416. $this->assertFalse(TestCakeSession::read('SessionTestCase'));
  417. TestCakeSession::write('SessionTestCase', null);
  418. $this->assertEquals(null, TestCakeSession::read('SessionTestCase'));
  419. TestCakeSession::write('SessionTestCase', 'This is a Test');
  420. $this->assertEquals('This is a Test', TestCakeSession::read('SessionTestCase'));
  421. TestCakeSession::write('SessionTestCase', 'This is a Test');
  422. TestCakeSession::write('SessionTestCase', 'This was updated');
  423. $this->assertEquals('This was updated', TestCakeSession::read('SessionTestCase'));
  424. TestCakeSession::destroy();
  425. $this->assertNull(TestCakeSession::read('SessionTestCase'));
  426. }
  427. /**
  428. * test using a handler from app/Model/Datasource/Session.
  429. *
  430. * @return void
  431. */
  432. public function testUsingAppLibsHandler() {
  433. App::build(array(
  434. 'Model/Datasource/Session' => array(
  435. CAKE . 'Test' . DS . 'test_app' . DS . 'Model' . DS . 'Datasource' . DS . 'Session' . DS
  436. ),
  437. 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  438. ), true);
  439. Configure::write('Session', array(
  440. 'defaults' => 'cake',
  441. 'handler' => array(
  442. 'engine' => 'TestAppLibSession'
  443. )
  444. ));
  445. TestCakeSession::destroy();
  446. $this->assertTrue(TestCakeSession::started());
  447. App::build();
  448. }
  449. /**
  450. * test using a handler from a plugin.
  451. *
  452. * @return void
  453. */
  454. public function testUsingPluginHandler() {
  455. App::build(array(
  456. 'plugins' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  457. ), true);
  458. Configure::write('Session', array(
  459. 'defaults' => 'cake',
  460. 'handler' => array(
  461. 'engine' => 'TestPlugin.TestPluginSession'
  462. )
  463. ));
  464. TestCakeSession::destroy();
  465. $this->assertTrue(TestCakeSession::started());
  466. App::build();
  467. }
  468. /**
  469. * testReadAndWriteWithDatabaseStorage method
  470. *
  471. * @return void
  472. */
  473. public function testReadAndWriteWithCacheStorage() {
  474. Configure::write('Session.defaults', 'cache');
  475. TestCakeSession::init();
  476. TestCakeSession::destroy();
  477. TestCakeSession::write('SessionTestCase', 0);
  478. $this->assertEquals(0, TestCakeSession::read('SessionTestCase'));
  479. TestCakeSession::write('SessionTestCase', '0');
  480. $this->assertEquals('0', TestCakeSession::read('SessionTestCase'));
  481. $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0);
  482. TestCakeSession::write('SessionTestCase', false);
  483. $this->assertFalse(TestCakeSession::read('SessionTestCase'));
  484. TestCakeSession::write('SessionTestCase', null);
  485. $this->assertEquals(null, TestCakeSession::read('SessionTestCase'));
  486. TestCakeSession::write('SessionTestCase', 'This is a Test');
  487. $this->assertEquals('This is a Test', TestCakeSession::read('SessionTestCase'));
  488. TestCakeSession::write('SessionTestCase', 'This is a Test');
  489. TestCakeSession::write('SessionTestCase', 'This was updated');
  490. $this->assertEquals('This was updated', TestCakeSession::read('SessionTestCase'));
  491. TestCakeSession::destroy();
  492. $this->assertNull(TestCakeSession::read('SessionTestCase'));
  493. }
  494. /**
  495. * test that changing the config name of the cache config works.
  496. *
  497. * @return void
  498. */
  499. public function testReadAndWriteWithCustomCacheConfig() {
  500. Configure::write('Session.defaults', 'cache');
  501. Configure::write('Session.handler.config', 'session_test');
  502. Cache::config('session_test', array(
  503. 'engine' => 'File',
  504. 'prefix' => 'session_test_',
  505. ));
  506. TestCakeSession::init();
  507. TestCakeSession::start();
  508. TestCakeSession::write('SessionTestCase', 'Some value');
  509. $this->assertEquals('Some value', TestCakeSession::read('SessionTestCase'));
  510. $id = TestCakeSession::id();
  511. Cache::delete($id, 'session_test');
  512. }
  513. /**
  514. * testReadAndWriteWithDatabaseStorage method
  515. *
  516. * @return void
  517. */
  518. public function testReadAndWriteWithDatabaseStorage() {
  519. Configure::write('Session.defaults', 'database');
  520. Configure::write('Session.handler.table', 'sessions');
  521. Configure::write('Session.handler.model', 'Session');
  522. Configure::write('Session.handler.database', 'test');
  523. TestCakeSession::init();
  524. TestCakeSession::start();
  525. TestCakeSession::write('SessionTestCase', 0);
  526. $this->assertEquals(0, TestCakeSession::read('SessionTestCase'));
  527. TestCakeSession::write('SessionTestCase', '0');
  528. $this->assertEquals('0', TestCakeSession::read('SessionTestCase'));
  529. $this->assertFalse(TestCakeSession::read('SessionTestCase') === 0);
  530. TestCakeSession::write('SessionTestCase', false);
  531. $this->assertFalse(TestCakeSession::read('SessionTestCase'));
  532. TestCakeSession::write('SessionTestCase', null);
  533. $this->assertEquals(null, TestCakeSession::read('SessionTestCase'));
  534. TestCakeSession::write('SessionTestCase', 'This is a Test');
  535. $this->assertEquals('This is a Test', TestCakeSession::read('SessionTestCase'));
  536. TestCakeSession::write('SessionTestCase', 'Some additional data');
  537. $this->assertEquals('Some additional data', TestCakeSession::read('SessionTestCase'));
  538. TestCakeSession::destroy();
  539. $this->assertNull(TestCakeSession::read('SessionTestCase'));
  540. Configure::write('Session', array(
  541. 'defaults' => 'php'
  542. ));
  543. TestCakeSession::init();
  544. }
  545. /**
  546. * testSessionTimeout method
  547. *
  548. * @return void
  549. */
  550. public function testSessionTimeout() {
  551. Configure::write('debug', 2);
  552. Configure::write('Session.autoRegenerate', false);
  553. $timeoutSeconds = Configure::read('Session.timeout') * 60;
  554. TestCakeSession::destroy();
  555. TestCakeSession::write('Test', 'some value');
  556. $this->assertEquals(time() + $timeoutSeconds, CakeSession::$sessionTime);
  557. $this->assertEquals(10, $_SESSION['Config']['countdown']);
  558. $this->assertEquals(CakeSession::$sessionTime, $_SESSION['Config']['time']);
  559. $this->assertEquals(time(), CakeSession::$time);
  560. $this->assertEquals(time() + $timeoutSeconds, $_SESSION['Config']['time']);
  561. Configure::write('Session.harden', true);
  562. TestCakeSession::destroy();
  563. TestCakeSession::write('Test', 'some value');
  564. $this->assertEquals(time() + $timeoutSeconds, CakeSession::$sessionTime);
  565. $this->assertEquals(10, $_SESSION['Config']['countdown']);
  566. $this->assertEquals(CakeSession::$sessionTime, $_SESSION['Config']['time']);
  567. $this->assertEquals(time(), CakeSession::$time);
  568. $this->assertEquals(CakeSession::$time + $timeoutSeconds, $_SESSION['Config']['time']);
  569. }
  570. }