PasswordableBehaviorTest.php 20 KB

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