PasswordableBehaviorTest.php 20 KB

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