PasswordableBehaviorTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. <?php
  2. App::uses('ComponentCollection', 'Controller');
  3. App::uses('AuthComponent', 'Controller/Component');
  4. App::uses('SimplePasswordHasher', 'Controller/Component/Auth');
  5. if (!function_exists('password_hash')) {
  6. require_once CakePlugin::path('Tools') . 'Lib/Bootstrap/Password.php';
  7. }
  8. class PasswordableBehaviorTest extends CakeTestCase {
  9. public $fixtures = array(
  10. 'plugin.tools.tools_user', 'plugin.tools.role',
  11. );
  12. /**
  13. * SetUp method
  14. *
  15. * @return void
  16. */
  17. public function setUp() {
  18. parent::setUp();
  19. Configure::write('Config.language', 'deu');
  20. Configure::delete('Passwordable');
  21. Configure::write('Passwordable.auth', 'AuthTest');
  22. $this->User = ClassRegistry::init('Tools.ToolsUser');
  23. if (isset($this->User->validate['pwd'])) {
  24. unset($this->User->validate['pwd']);
  25. }
  26. if (isset($this->User->validate['pwd_repeat'])) {
  27. unset($this->User->validate['pwd_repeat']);
  28. }
  29. if (isset($this->User->validate['pwd_current'])) {
  30. unset($this->User->validate['pwd_current']);
  31. }
  32. if (isset($this->User->order)) {
  33. unset($this->User->order);
  34. }
  35. $this->User->create();
  36. $data = array(
  37. 'id' => '5',
  38. 'name' => 'admin',
  39. 'password' => Security::hash('somepwd', null, true),
  40. 'role_id' => '1'
  41. );
  42. $this->User->set($data);
  43. $result = $this->User->save();
  44. $this->assertTrue((bool)$result);
  45. Router::setRequestInfo(new CakeRequest(null, false));
  46. }
  47. /**
  48. * PasswordableBehaviorTest::testObject()
  49. *
  50. * @return void
  51. */
  52. public function testObject() {
  53. $this->User->Behaviors->load('Tools.Passwordable', array());
  54. $this->assertInstanceOf('PasswordableBehavior', $this->User->Behaviors->Passwordable);
  55. $result = $this->User->Behaviors->loaded('Passwordable');
  56. $this->assertTrue($result);
  57. }
  58. /**
  59. * Make sure validation is triggered correctly
  60. *
  61. * @return void
  62. */
  63. public function testValidate() {
  64. $this->User->Behaviors->load('Tools.Passwordable', array());
  65. $this->User->create();
  66. $data = array(
  67. 'pwd' => '123456',
  68. );
  69. $this->User->set($data);
  70. $is = $this->User->save();
  71. //debug($this->User->validationErrors);
  72. $this->assertFalse($is);
  73. $this->assertEquals(array('pwd_repeat'), array_keys($this->User->validationErrors));
  74. $this->User->create();
  75. $data = array(
  76. 'pwd' => '1234ab',
  77. 'pwd_repeat' => '123456'
  78. );
  79. $this->User->set($data);
  80. $is = $this->User->save();
  81. //debug($this->User->validationErrors);
  82. $this->assertFalse($is);
  83. $this->assertEquals(array(__d('tools', 'valErrPwdNotMatch')), $this->User->validationErrors['pwd_repeat']);
  84. $this->User->create();
  85. $data = array(
  86. 'pwd' => '123456',
  87. 'pwd_repeat' => '123456'
  88. );
  89. $this->User->set($data);
  90. //debug($this->User->validate);
  91. $is = $this->User->validates();
  92. $this->assertTrue(!empty($is));
  93. }
  94. /**
  95. * Test that confirm false does not require confirmation
  96. *
  97. * @return void
  98. */
  99. public function testValidateNoConfirm() {
  100. $this->User->Behaviors->load('Tools.Passwordable', array('confirm' => false));
  101. $this->User->create();
  102. $data = array(
  103. 'pwd' => '123456',
  104. );
  105. $this->User->set($data);
  106. $is = $this->User->save();
  107. //debug($is);
  108. $this->assertTrue(!empty($is));
  109. }
  110. /**
  111. * Trigger validation and update process if no values are entered but are required
  112. *
  113. * @return void
  114. */
  115. public function testValidateRequired() {
  116. $this->User->Behaviors->load('Tools.Passwordable');
  117. $this->User->create();
  118. $data = array(
  119. 'pwd' => '',
  120. 'pwd_repeat' => ''
  121. );
  122. $this->User->set($data);
  123. $is = $this->User->save();
  124. $this->assertFalse($is);
  125. $this->assertEquals(array('pwd', 'pwd_repeat'), array_keys($this->User->validationErrors));
  126. }
  127. /**
  128. * Validation and update process gets skipped if no values are entered
  129. *
  130. * @return void
  131. */
  132. public function testValidateNotRequired() {
  133. $this->User->Behaviors->load('Tools.Passwordable', array('require' => false));
  134. $this->User->create();
  135. $data = array(
  136. 'name' => 'foo', // we need at least one field besides the password on CREATE
  137. 'pwd' => '',
  138. 'pwd_repeat' => ''
  139. );
  140. $this->User->set($data);
  141. $is = $this->User->save();
  142. $this->assertTrue((bool)$is);
  143. $this->assertEquals(array('name', 'id'), array_keys($is[$this->User->alias]));
  144. $id = $this->User->id;
  145. $data = array(
  146. 'id' => $id,
  147. 'pwd' => '',
  148. 'pwd_repeat' => ''
  149. );
  150. $this->User->set($data);
  151. $is = $this->User->save();
  152. $this->assertTrue((bool)$is);
  153. $this->assertEquals(array('id'), array_keys($is[$this->User->alias]));
  154. }
  155. /**
  156. * PasswordableBehaviorTest::testValidateEmptyWithCurrentPassword()
  157. *
  158. * @return void
  159. */
  160. public function testValidateEmptyWithCurrentPassword() {
  161. $this->User->Behaviors->load('Tools.Passwordable', array('current' => true));
  162. $this->User->create();
  163. $data = array(
  164. 'id' => '123',
  165. 'pwd' => '',
  166. 'pwd_repeat' => '',
  167. 'pwd_current' => '123456',
  168. );
  169. $this->User->set($data);
  170. $is = $this->User->save();
  171. //debug($this->User->validationErrors);
  172. $this->assertFalse($is);
  173. $this->assertEquals(array('pwd', 'pwd_repeat', 'pwd_current'), array_keys($this->User->validationErrors));
  174. $this->tearDown();
  175. $this->setUp();
  176. $this->User->Behaviors->load('Tools.Passwordable', array('require' => false, 'current' => true));
  177. $this->User->create();
  178. $data = array(
  179. 'name' => 'foo',
  180. 'pwd' => '',
  181. 'pwd_repeat' => '',
  182. 'pwd_current' => '',
  183. );
  184. $is = $this->User->save($data);
  185. $this->assertTrue(!empty($is));
  186. }
  187. /**
  188. * PasswordableBehaviorTest::testValidateCustomRule()
  189. *
  190. * @return void
  191. */
  192. public function testValidateCustomRule() {
  193. $rules = array('validateCustom' => array(
  194. 'rule' => array('custom', '#^[a-z0-9]+$#'), // Just a test example, never use this regexp!
  195. 'message' => 'Foo Bar',
  196. 'last' => true,
  197. ),
  198. 'validateCustomExt' => array(
  199. 'rule' => array('custom', '#^[a-z]+$#'), // Just a test example, never use this regexp!
  200. 'message' => 'Foo Bar Ext',
  201. 'last' => true,
  202. )
  203. );
  204. $this->User->Behaviors->load('Tools.Passwordable', array(
  205. 'customValidation' => $rules));
  206. $this->User->create();
  207. $data = array(
  208. 'pwd' => '%123456',
  209. 'pwd_repeat' => '%123456'
  210. );
  211. $this->User->set($data);
  212. $is = $this->User->save();
  213. $this->assertFalse($is);
  214. $result = $this->User->validationErrors;
  215. $expected = array('pwd' => array('Foo Bar'));
  216. $this->assertSame($expected, $result);
  217. $this->User->create();
  218. $data = array(
  219. 'pwd' => 'abc123',
  220. 'pwd_repeat' => 'abc123'
  221. );
  222. $this->User->set($data);
  223. $is = $this->User->save();
  224. $this->assertFalse($is);
  225. $result = $this->User->validationErrors;
  226. $expected = array('pwd' => array('Foo Bar Ext'));
  227. $this->assertSame($expected, $result);
  228. $this->User->create();
  229. $data = array(
  230. 'pwd' => 'abcdef',
  231. 'pwd_repeat' => 'abcdef'
  232. );
  233. $this->User->set($data);
  234. $is = $this->User->save();
  235. $this->assertTrue((bool)$is);
  236. }
  237. /**
  238. * Test aliases for field names
  239. */
  240. public function testDifferentFieldNames() {
  241. $this->User->Behaviors->load('Tools.Passwordable', array(
  242. 'formField' => 'passw',
  243. 'formFieldRepeat' => 'passw_repeat',
  244. 'formFieldCurrent' => 'passw_current',
  245. ));
  246. $this->User->create();
  247. $data = array(
  248. 'passw' => '123456',
  249. 'passw_repeat' => '123456'
  250. );
  251. $this->User->set($data);
  252. //debug($this->User->data);
  253. $is = $this->User->save();
  254. $this->assertTrue(!empty($is));
  255. }
  256. /**
  257. * Assert that allowSame false does not allow storing the same password as previously entered
  258. */
  259. public function testNotSame() {
  260. $this->User->Behaviors->load('Tools.Passwordable', array(
  261. 'formField' => 'passw',
  262. 'formFieldRepeat' => 'passw_repeat',
  263. 'formFieldCurrent' => 'passw_current',
  264. 'allowSame' => false,
  265. 'current' => true,
  266. ));
  267. $this->User->create();
  268. $data = array(
  269. 'id' => '5',
  270. 'passw_current' => 'something',
  271. 'passw' => 'somepwd',
  272. 'passw_repeat' => 'somepwd'
  273. );
  274. $this->User->set($data);
  275. $is = $this->User->save();
  276. //debug($this->User->validationErrors);
  277. $this->assertFalse($is);
  278. $this->User->create();
  279. $data = array(
  280. 'id' => '5',
  281. 'passw_current' => 'somepwd',
  282. 'passw' => 'newpwd',
  283. 'passw_repeat' => 'newpwd'
  284. );
  285. $this->User->set($data);
  286. $is = $this->User->save();
  287. $this->assertTrue(!empty($is));
  288. }
  289. /**
  290. * Assert that allowSame false does not allow storing the same password as previously entered
  291. */
  292. public function testNotSameWithoutCurrentField() {
  293. $this->User->Behaviors->load('Tools.Passwordable', array(
  294. 'formField' => 'passw',
  295. 'formFieldRepeat' => 'passw_repeat',
  296. 'allowSame' => false,
  297. 'current' => false
  298. ));
  299. $this->User->create();
  300. $data = array(
  301. 'passw' => 'somepwd',
  302. 'passw_repeat' => 'somepwd'
  303. );
  304. $this->User->set($data);
  305. $is = $this->User->save();
  306. $this->assertTrue((bool)$is);
  307. $id = $is[$this->User->alias]['id'];
  308. $this->User->create();
  309. $data = array(
  310. 'id' => $id,
  311. 'passw' => 'somepwd',
  312. 'passw_repeat' => 'somepwd'
  313. );
  314. $this->User->set($data);
  315. $is = $this->User->save();
  316. $this->assertFalse((bool)$is);
  317. $this->User->create();
  318. $data = array(
  319. 'id' => $id,
  320. 'passw' => 'newpwd',
  321. 'passw_repeat' => 'newpwd'
  322. );
  323. $this->User->set($data);
  324. $is = $this->User->save();
  325. $this->assertTrue((bool)$is);
  326. }
  327. /**
  328. * Assert that on edit it does not wrongly pass validation (require => false)
  329. */
  330. public function testRequireFalse() {
  331. $this->User->Behaviors->load('Tools.Passwordable', array(
  332. 'formField' => 'passw',
  333. 'formFieldRepeat' => 'passw_repeat',
  334. 'require' => false
  335. ));
  336. $this->User->create();
  337. $data = array(
  338. 'passw' => 'somepwd',
  339. 'passw_repeat' => 'somepwd'
  340. );
  341. $this->User->set($data);
  342. $is = $this->User->save();
  343. $this->assertTrue((bool)$is);
  344. $id = $is[$this->User->alias]['id'];
  345. $this->User->create();
  346. $data = array(
  347. 'id' => $id,
  348. 'passw' => 'somepwd2',
  349. 'passw_repeat' => ''
  350. );
  351. $this->User->set($data);
  352. $is = $this->User->save();
  353. $this->assertFalse((bool)$is);
  354. //debug($this->User->validationErrors);
  355. $this->User->create();
  356. $data = array(
  357. 'id' => $id,
  358. 'passw' => 'somepwd2',
  359. 'passw_repeat' => 'somepwd2'
  360. );
  361. $this->User->set($data);
  362. $is = $this->User->save();
  363. $this->assertTrue((bool)$is);
  364. }
  365. /**
  366. * Needs faking of pwd check...
  367. */
  368. public function testValidateCurrent() {
  369. $this->assertFalse($this->User->Behaviors->loaded('Passwordable'));
  370. $this->User->create();
  371. $data = array(
  372. 'name' => 'xyz',
  373. 'password' => Security::hash('somepwd', null, true));
  374. $result = $this->User->save($data);
  375. $this->assertTrue(!empty($result));
  376. $uid = (string)$this->User->id;
  377. $this->User->Behaviors->load('Tools.Passwordable', array('current' => true));
  378. $this->User->create();
  379. $data = array(
  380. 'id' => $uid,
  381. 'pwd' => '123456',
  382. 'pwd_repeat' => '12345678',
  383. //'pwd_current' => '',
  384. );
  385. $this->User->set($data);
  386. $this->assertTrue($this->User->Behaviors->loaded('Passwordable'));
  387. $is = $this->User->save();
  388. $this->assertFalse($is);
  389. $this->User->create();
  390. $data = array(
  391. 'id' => $uid,
  392. 'pwd_current' => 'somepwdx',
  393. 'pwd' => '123456',
  394. 'pwd_repeat' => '123456'
  395. );
  396. $this->User->set($data);
  397. $is = $this->User->save();
  398. $this->assertFalse($is);
  399. $this->User->create();
  400. $data = array(
  401. 'id' => $uid,
  402. 'name' => 'Yeah',
  403. 'pwd_current' => 'somepwd',
  404. 'pwd' => '123456',
  405. 'pwd_repeat' => '123456'
  406. );
  407. $this->User->set($data);
  408. // Test whitelist setting - only "password" needs to gets auto-added
  409. $options = array('validate' => true, 'fieldList' => array('id', 'pwd', 'pwd_repeat', 'pwd_current'));
  410. $is = $this->User->save(null, $options);
  411. $this->assertTrue(!empty($is));
  412. $user = $this->User->findById($uid);
  413. // The password is updated, the name not
  414. $this->assertSame($is['ToolsUser']['password'], $user['ToolsUser']['password']);
  415. $this->assertSame('xyz', $user['ToolsUser']['name']);
  416. // Proof that we manually need to add pwd, pwd_repeat etc due to a bug in CakePHP<=2.4 allowing behaviors to only modify saving,
  417. // not validating of additional whitelist fields. Validation for those will be just skipped, no matter what the behavior tries
  418. // to set.
  419. $this->User->create();
  420. $data = array(
  421. 'id' => $uid,
  422. 'name' => 'Yeah',
  423. 'pwd_current' => '123', // Obviously wrong
  424. 'pwd' => 'some', // Too short
  425. 'pwd_repeat' => 'somex' // Don't match
  426. );
  427. $this->User->set($data);
  428. // Test whitelist setting - only "password" gets auto-added, pwd, pwd_repeat etc need to be added manually
  429. // NOTE that I had to remove the code for adding those fields from the behavior (as it was not functional)
  430. // So of course, this won't work now as expected. But feel free to try to add them in the behavior. Results will be the same.
  431. $options = array('validate' => true, 'fieldList' => array('id', 'name'));
  432. $is = $this->User->save(null, $options);
  433. if ((float)Configure::version() >= 2.5) {
  434. // Validation errors triggered - as expected
  435. $this->assertFalse($is);
  436. $this->assertSame(array('pwd', 'pwd_repeat', 'pwd_current'), array_keys($this->User->validationErrors));
  437. return;
  438. }
  439. // Save is successful
  440. $this->assertTrue(!empty($is));
  441. $user = $this->User->get($uid);
  442. $this->assertSame('Yeah', $user['ToolsUser']['name']);
  443. // The password is not updated, the name is
  444. $this->assertSame($is['ToolsUser']['password'], $user['ToolsUser']['password']);
  445. $this->assertSame('Yeah', $user['ToolsUser']['name']);
  446. }
  447. /**
  448. * Test cake2.4 passwordHasher feature
  449. *
  450. * @return void
  451. */
  452. public function testPasswordHasher() {
  453. $this->skipIf((float)Configure::version() < 2.4, 'Needs 2.4 and above');
  454. $this->User->Behaviors->load('Tools.Passwordable', array(
  455. 'formField' => 'pwd',
  456. 'formFieldRepeat' => 'pwd_repeat',
  457. 'allowSame' => false,
  458. 'current' => false,
  459. 'passwordHasher' => 'Complex',
  460. ));
  461. $this->User->create();
  462. $data = array(
  463. 'pwd' => 'somepwd',
  464. 'pwd_repeat' => 'somepwd'
  465. );
  466. $this->User->set($data);
  467. $result = $this->User->save();
  468. $this->assertTrue((bool)$result);
  469. $uid = (string)$this->User->id;
  470. $this->User->Behaviors->load('Tools.Passwordable', array('current' => true));
  471. $this->User->create();
  472. $data = array(
  473. 'id' => $uid,
  474. 'pwd' => '123456',
  475. 'pwd_repeat' => '12345678',
  476. //'pwd_current' => '',
  477. );
  478. $this->User->set($data);
  479. $this->assertTrue($this->User->Behaviors->loaded('Passwordable'));
  480. $is = $this->User->save();
  481. $this->assertFalse($is);
  482. $this->User->create();
  483. $data = array(
  484. 'id' => $uid,
  485. 'pwd_current' => 'somepwdx',
  486. 'pwd' => '123456',
  487. 'pwd_repeat' => '123456'
  488. );
  489. $this->User->set($data);
  490. $is = $this->User->save();
  491. $this->assertFalse($is);
  492. $this->User->create();
  493. $data = array(
  494. 'id' => $uid,
  495. 'pwd_current' => 'somepwd',
  496. 'pwd' => '123456',
  497. 'pwd_repeat' => '123456'
  498. );
  499. $this->User->set($data);
  500. $is = $this->User->save();
  501. $this->assertTrue(!empty($is));
  502. }
  503. /**
  504. * PasswordableBehaviorTest::testBlowfish()
  505. *
  506. * @return void
  507. */
  508. public function testBlowfish() {
  509. $this->User->Behaviors->load('Tools.Passwordable', array(
  510. 'allowSame' => false,
  511. 'current' => false,
  512. 'authType' => 'Blowfish',
  513. ));
  514. $this->User->create();
  515. $data = array(
  516. 'pwd' => 'somepwd',
  517. 'pwd_repeat' => 'somepwd'
  518. );
  519. $this->User->set($data);
  520. $result = $this->User->save();
  521. $this->assertTrue((bool)$result);
  522. $uid = (string)$this->User->id;
  523. $this->User->Behaviors->load('Tools.Passwordable', array('current' => true));
  524. // Without the current password it will not continue
  525. $this->User->create();
  526. $data = array(
  527. 'id' => $uid,
  528. 'pwd' => '123456',
  529. 'pwd_repeat' => '12345678',
  530. );
  531. $this->User->set($data);
  532. $this->assertTrue($this->User->Behaviors->loaded('Passwordable'));
  533. $result = $this->User->save();
  534. $this->assertFalse($result);
  535. // Without the correct current password it will not continue
  536. $this->User->create();
  537. $data = array(
  538. 'id' => $uid,
  539. 'pwd_current' => 'somepwdx',
  540. 'pwd' => '123456',
  541. 'pwd_repeat' => '123456'
  542. );
  543. $this->User->set($data);
  544. $result = $this->User->save();
  545. $this->assertFalse($result);
  546. // Now it will
  547. $this->User->create();
  548. $data = array(
  549. 'id' => $uid,
  550. 'pwd_current' => 'somepwd',
  551. 'pwd' => '123456',
  552. 'pwd_repeat' => '123456'
  553. );
  554. $this->User->set($data);
  555. $result = $this->User->save();
  556. $this->assertTrue((bool)$result);
  557. }
  558. /**
  559. * Tests that passwords prior to PHP5.5 and/or password_hash() are still working
  560. * if Tools.Modern is being used.
  561. *
  562. * @return void
  563. */
  564. public function testBlowfishWithBC() {
  565. $this->skipIf(!function_exists('password_hash'), 'password_hash() is not available.');
  566. $oldHash = Security::hash('foobar', 'blowfish', false);
  567. $newHash = password_hash('foobar', PASSWORD_BCRYPT);
  568. $this->User->Behaviors->load('Tools.Passwordable', array(
  569. 'allowSame' => false,
  570. 'current' => false,
  571. 'authType' => 'Blowfish',
  572. 'passwordHasher' => 'Tools.Modern'
  573. ));
  574. $this->User->create();
  575. $data = array(
  576. 'pwd' => 'somepwd',
  577. 'pwd_repeat' => 'somepwd'
  578. );
  579. $this->User->set($data);
  580. $result = $this->User->save();
  581. $this->assertTrue((bool)$result);
  582. $uid = (string)$this->User->id;
  583. // Same pwd is not allowed
  584. $this->User->create();
  585. $data = array(
  586. 'id' => $uid,
  587. 'pwd' => 'somepwd',
  588. 'pwd_repeat' => 'somepwd'
  589. );
  590. $this->User->set($data);
  591. $result = $this->User->save();
  592. $this->assertFalse($result);
  593. $this->User->Behaviors->load('Tools.Passwordable', array('current' => true));
  594. // Without the correct current password it will not continue
  595. $this->User->create();
  596. $data = array(
  597. 'id' => $uid,
  598. 'pwd_current' => 'somepwdxyz',
  599. 'pwd' => '123456',
  600. 'pwd_repeat' => '123456'
  601. );
  602. $this->User->set($data);
  603. $result = $this->User->save();
  604. $this->assertFalse($result);
  605. // Now it will
  606. $this->User->create();
  607. $data = array(
  608. 'id' => $uid,
  609. 'pwd_current' => 'somepwd',
  610. 'pwd' => '123456',
  611. 'pwd_repeat' => '123456'
  612. );
  613. $this->User->set($data);
  614. $result = $this->User->save();
  615. $this->assertTrue((bool)$result);
  616. // Lets set a BC password (without password_hash() method but Security class)
  617. $data = array(
  618. 'id' => $uid,
  619. 'password' => $oldHash,
  620. );
  621. $result = $this->User->save($data, array('validate' => false));
  622. $this->assertTrue((bool)$result);
  623. // Now it will still work
  624. $this->User->create();
  625. $data = array(
  626. 'id' => $uid,
  627. 'pwd_current' => 'foobar',
  628. 'pwd' => '123456',
  629. 'pwd_repeat' => '123456'
  630. );
  631. $this->User->set($data);
  632. $result = $this->User->save();
  633. $this->assertTrue((bool)$result);
  634. // Lets set an invalid BC password (without password_hash() method but Security class)
  635. $data = array(
  636. 'id' => $uid,
  637. 'password' => $oldHash . 'x',
  638. );
  639. $result = $this->User->save($data, array('validate' => false));
  640. $this->assertTrue((bool)$result);
  641. // Now it will still work
  642. $this->User->create();
  643. $data = array(
  644. 'id' => $uid,
  645. 'pwd_current' => 'foobar',
  646. 'pwd' => '123456',
  647. 'pwd_repeat' => '123456'
  648. );
  649. $this->User->set($data);
  650. $result = $this->User->save();
  651. $this->assertFalse($result);
  652. // Lets set a valid BC password (without password_hash() method but Security class)
  653. // But the provided pwd is incorrect
  654. $data = array(
  655. 'id' => $uid,
  656. 'password' => $oldHash,
  657. );
  658. $result = $this->User->save($data, array('validate' => false));
  659. $this->assertTrue((bool)$result);
  660. // Now it will still work
  661. $this->User->create();
  662. $data = array(
  663. 'id' => $uid,
  664. 'pwd_current' => 'foobarx',
  665. 'pwd' => '123456',
  666. 'pwd_repeat' => '123456'
  667. );
  668. $this->User->set($data);
  669. $result = $this->User->save();
  670. $this->assertFalse($result);
  671. }
  672. /**
  673. * Tests needsPasswordRehash()
  674. *
  675. * @return void
  676. */
  677. public function testNeedsPasswordRehash() {
  678. $this->skipIf(!function_exists('password_hash'), 'password_hash() is not available.');
  679. $this->User->Behaviors->load('Tools.Passwordable', array(
  680. 'allowSame' => false,
  681. 'current' => false,
  682. 'authType' => 'Blowfish',
  683. 'passwordHasher' => 'Tools.Modern'
  684. ));
  685. $hash = password_hash('foobar', PASSWORD_BCRYPT);
  686. $result = $this->User->needsPasswordRehash($hash);
  687. $this->assertFalse($result);
  688. $hash = sha1('foobar');
  689. $result = $this->User->needsPasswordRehash($hash);
  690. $this->assertTrue($result);
  691. }
  692. /**
  693. * Tests needsPasswordRehash()
  694. *
  695. * @return void
  696. */
  697. public function testNeedsPasswordRehashWithNotSupportedHasher() {
  698. $this->User->Behaviors->load('Tools.Passwordable', array(
  699. 'allowSame' => false,
  700. 'current' => false,
  701. 'authType' => 'Blowfish',
  702. ));
  703. $hash = password_hash('foobar', PASSWORD_BCRYPT);
  704. $result = $this->User->needsPasswordRehash($hash);
  705. $this->assertFalse($result);
  706. $this->User->Behaviors->load('Tools.Passwordable', array(
  707. 'allowSame' => false,
  708. 'current' => false,
  709. 'authType' => 'Blowfish',
  710. 'passwordHasher' => 'Simple'
  711. ));
  712. $hash = password_hash('foobar', PASSWORD_BCRYPT);
  713. $result = $this->User->needsPasswordRehash($hash);
  714. $this->assertFalse($result);
  715. }
  716. /**
  717. * PasswordableBehaviorTest::testSettings()
  718. *
  719. * @return void
  720. */
  721. public function testSettings() {
  722. // Pwd min and max length
  723. $this->User->Behaviors->load('Tools.Passwordable', array(
  724. 'allowSame' => false,
  725. 'current' => false,
  726. 'minLength' => 3,
  727. 'maxLength' => 6,
  728. ));
  729. $this->User->create();
  730. $data = array(
  731. 'pwd' => '123',
  732. 'pwd_repeat' => '123'
  733. );
  734. $this->User->set($data);
  735. $result = $this->User->save();
  736. $this->assertTrue((bool)$result);
  737. $this->User->create();
  738. $data = array(
  739. 'pwd' => '12345678',
  740. 'pwd_repeat' => '12345678'
  741. );
  742. $this->User->set($data);
  743. $result = $this->User->save();
  744. $this->assertFalse($result);
  745. $expected = array(
  746. 'pwd' => array(__d('tools', 'valErrBetweenCharacters %s %s', 3, 6))
  747. );
  748. $this->assertEquals($expected, $this->User->validationErrors);
  749. }
  750. /**
  751. * Test that validate false also works.
  752. *
  753. * @return void
  754. */
  755. public function testSaveWithValidateFalse() {
  756. $this->User->Behaviors->load('Tools.Passwordable');
  757. $this->User->create();
  758. $data = array(
  759. 'pwd' => '123',
  760. );
  761. $this->User->set($data);
  762. $result = $this->User->save(null, array('validate' => false));
  763. $this->assertTrue((bool)$result);
  764. $uid = (string)$this->User->id;
  765. $data = array(
  766. 'id' => $uid,
  767. 'pwd' => '1234'
  768. );
  769. $this->User->set($data);
  770. $result2 = $this->User->save(null, array('validate' => false));
  771. $this->assertTrue((bool)$result2);
  772. $this->assertTrue($result['ToolsUser']['password'] !== $result2['ToolsUser']['password']);
  773. }
  774. }
  775. /**
  776. * Test component
  777. */
  778. class AuthTestComponent extends AuthComponent {
  779. }
  780. class ComplexPasswordHasher extends SimplePasswordHasher {
  781. }