You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UserTest.php 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Juan Pablo Villafáñez <jvillafanez@solidgear.es>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Roeland Jago Douma <roeland@famdouma.nl>
  11. * @author Roger Szabo <roger.szabo@web.de>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. *
  14. * @license AGPL-3.0
  15. *
  16. * This code is free software: you can redistribute it and/or modify
  17. * it under the terms of the GNU Affero General Public License, version 3,
  18. * as published by the Free Software Foundation.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU Affero General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Affero General Public License, version 3,
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>
  27. *
  28. */
  29. namespace OCA\User_LDAP\Tests\User;
  30. use OCA\User_LDAP\Access;
  31. use OCA\User_LDAP\Connection;
  32. use OCA\User_LDAP\FilesystemHelper;
  33. use OCA\User_LDAP\LogWrapper;
  34. use OCA\User_LDAP\User\User;
  35. use OCP\IAvatar;
  36. use OCP\IAvatarManager;
  37. use OCP\IConfig;
  38. use OCP\Image;
  39. use OCP\IUser;
  40. use OCP\IUserManager;
  41. use OCP\Notification\IManager as INotificationManager;
  42. use OCP\Notification\INotification;
  43. /**
  44. * Class UserTest
  45. *
  46. * @group DB
  47. *
  48. * @package OCA\User_LDAP\Tests\User
  49. */
  50. class UserTest extends \Test\TestCase {
  51. /** @var Access|\PHPUnit\Framework\MockObject\MockObject */
  52. protected $access;
  53. /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */
  54. protected $connection;
  55. /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
  56. protected $config;
  57. /** @var FilesystemHelper|\PHPUnit\Framework\MockObject\MockObject */
  58. protected $filesystemhelper;
  59. /** @var INotificationManager|\PHPUnit\Framework\MockObject\MockObject */
  60. protected $notificationManager;
  61. /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
  62. protected $userManager;
  63. /** @var Image|\PHPUnit\Framework\MockObject\MockObject */
  64. protected $image;
  65. /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */
  66. protected $avatarManager;
  67. /** @var LogWrapper|\PHPUnit\Framework\MockObject\MockObject */
  68. protected $log;
  69. /** @var string */
  70. protected $uid = 'alice';
  71. /** @var string */
  72. protected $dn = 'uid=alice,dc=foo,dc=bar';
  73. /** @var User */
  74. protected $user;
  75. protected function setUp(): void {
  76. parent::setUp();
  77. $this->connection = $this->createMock(Connection::class);
  78. $this->access = $this->createMock(Access::class);
  79. $this->access->connection = $this->connection;
  80. $this->access->expects($this->any())
  81. ->method('getConnection')
  82. ->willReturn($this->connection);
  83. $this->config = $this->createMock(IConfig::class);
  84. $this->filesystemhelper = $this->createMock(FilesystemHelper::class);
  85. $this->log = $this->createMock(LogWrapper::class);
  86. $this->avatarManager = $this->createMock(IAvatarManager::class);
  87. $this->image = $this->createMock(Image::class);
  88. $this->userManager = $this->createMock(IUserManager::class);
  89. $this->notificationManager = $this->createMock(INotificationManager::class);
  90. $this->user = new User(
  91. $this->uid,
  92. $this->dn,
  93. $this->access,
  94. $this->config,
  95. $this->filesystemhelper,
  96. $this->image,
  97. $this->log,
  98. $this->avatarManager,
  99. $this->userManager,
  100. $this->notificationManager
  101. );
  102. }
  103. public function testGetDNandUsername() {
  104. $this->assertSame($this->dn, $this->user->getDN());
  105. $this->assertSame($this->uid, $this->user->getUsername());
  106. }
  107. public function testUpdateEmailProvided() {
  108. $this->connection->expects($this->once())
  109. ->method('__get')
  110. ->with($this->equalTo('ldapEmailAttribute'))
  111. ->willReturn('email');
  112. $this->access->expects($this->once())
  113. ->method('readAttribute')
  114. ->with($this->equalTo($this->dn),
  115. $this->equalTo('email'))
  116. ->willReturn(['alice@foo.bar']);
  117. $coreUser = $this->getMockBuilder(IUser::class)
  118. ->disableOriginalConstructor()
  119. ->getMock();
  120. $coreUser->expects($this->once())
  121. ->method('setEMailAddress')
  122. ->with('alice@foo.bar');
  123. $this->userManager->expects($this->any())
  124. ->method('get')
  125. ->willReturn($coreUser);
  126. $this->user->updateEmail();
  127. }
  128. public function testUpdateEmailNotProvided() {
  129. $this->connection->expects($this->once())
  130. ->method('__get')
  131. ->with($this->equalTo('ldapEmailAttribute'))
  132. ->willReturn('email');
  133. $this->access->expects($this->once())
  134. ->method('readAttribute')
  135. ->with($this->equalTo($this->dn),
  136. $this->equalTo('email'))
  137. ->willReturn(false);
  138. $this->config->expects($this->never())
  139. ->method('setUserValue');
  140. $this->user->updateEmail();
  141. }
  142. public function testUpdateEmailNotConfigured() {
  143. $this->connection->expects($this->once())
  144. ->method('__get')
  145. ->with($this->equalTo('ldapEmailAttribute'))
  146. ->willReturn('');
  147. $this->access->expects($this->never())
  148. ->method('readAttribute');
  149. $this->config->expects($this->never())
  150. ->method('setUserValue');
  151. $this->user->updateEmail();
  152. }
  153. public function testUpdateQuotaAllProvided() {
  154. $this->connection->expects($this->exactly(2))
  155. ->method('__get')
  156. ->willReturnMap([
  157. ['ldapQuotaAttribute', 'myquota'],
  158. ['ldapQuotaDefault', '']
  159. ]);
  160. $this->access->expects($this->once())
  161. ->method('readAttribute')
  162. ->with($this->equalTo($this->dn),
  163. $this->equalTo('myquota'))
  164. ->willReturn(['42 GB']);
  165. $coreUser = $this->createMock(IUser::class);
  166. $coreUser->expects($this->once())
  167. ->method('setQuota')
  168. ->with('42 GB');
  169. $this->userManager->expects($this->atLeastOnce())
  170. ->method('get')
  171. ->with($this->uid)
  172. ->willReturn($coreUser);
  173. $this->user->updateQuota();
  174. }
  175. public function testUpdateQuotaToDefaultAllProvided() {
  176. $this->connection->expects($this->exactly(2))
  177. ->method('__get')
  178. ->willReturnMap([
  179. ['ldapQuotaAttribute', 'myquota'],
  180. ['ldapQuotaDefault', '']
  181. ]);
  182. $this->access->expects($this->once())
  183. ->method('readAttribute')
  184. ->with($this->equalTo($this->dn),
  185. $this->equalTo('myquota'))
  186. ->willReturn(['default']);
  187. $coreUser = $this->createMock(IUser::class);
  188. $coreUser->expects($this->once())
  189. ->method('setQuota')
  190. ->with('default');
  191. $this->userManager->expects($this->once())
  192. ->method('get')
  193. ->with($this->uid)
  194. ->willReturn($coreUser);
  195. $this->user->updateQuota();
  196. }
  197. public function testUpdateQuotaToNoneAllProvided() {
  198. $this->connection->expects($this->exactly(2))
  199. ->method('__get')
  200. ->willReturnMap([
  201. ['ldapQuotaAttribute', 'myquota'],
  202. ['ldapQuotaDefault', '']
  203. ]);
  204. $this->access->expects($this->once())
  205. ->method('readAttribute')
  206. ->with($this->equalTo($this->dn),
  207. $this->equalTo('myquota'))
  208. ->willReturn(['none']);
  209. $coreUser = $this->createMock(IUser::class);
  210. $coreUser->expects($this->once())
  211. ->method('setQuota')
  212. ->with('none');
  213. $this->userManager->expects($this->once())
  214. ->method('get')
  215. ->with($this->uid)
  216. ->willReturn($coreUser);
  217. $this->user->updateQuota();
  218. }
  219. public function testUpdateQuotaDefaultProvided() {
  220. $this->connection->expects($this->at(0))
  221. ->method('__get')
  222. ->with($this->equalTo('ldapQuotaAttribute'))
  223. ->willReturn('myquota');
  224. $this->connection->expects($this->at(1))
  225. ->method('__get')
  226. ->with($this->equalTo('ldapQuotaDefault'))
  227. ->willReturn('25 GB');
  228. $this->connection->expects($this->exactly(2))
  229. ->method('__get');
  230. $this->access->expects($this->once())
  231. ->method('readAttribute')
  232. ->with($this->equalTo($this->dn),
  233. $this->equalTo('myquota'))
  234. ->willReturn(false);
  235. $coreUser = $this->createMock(IUser::class);
  236. $coreUser->expects($this->once())
  237. ->method('setQuota')
  238. ->with('25 GB');
  239. $this->userManager->expects($this->once())
  240. ->method('get')
  241. ->with($this->uid)
  242. ->willReturn($coreUser);
  243. $this->user->updateQuota();
  244. }
  245. public function testUpdateQuotaIndividualProvided() {
  246. $this->connection->expects($this->exactly(2))
  247. ->method('__get')
  248. ->willReturnMap([
  249. ['ldapQuotaAttribute', 'myquota'],
  250. ['ldapQuotaDefault', '']
  251. ]);
  252. $this->access->expects($this->once())
  253. ->method('readAttribute')
  254. ->with($this->equalTo($this->dn),
  255. $this->equalTo('myquota'))
  256. ->willReturn(['27 GB']);
  257. $coreUser = $this->createMock(IUser::class);
  258. $coreUser->expects($this->once())
  259. ->method('setQuota')
  260. ->with('27 GB');
  261. $this->userManager->expects($this->once())
  262. ->method('get')
  263. ->with($this->uid)
  264. ->willReturn($coreUser);
  265. $this->user->updateQuota();
  266. }
  267. public function testUpdateQuotaNoneProvided() {
  268. $this->connection->expects($this->exactly(2))
  269. ->method('__get')
  270. ->willReturnMap([
  271. ['ldapQuotaAttribute', 'myquota'],
  272. ['ldapQuotaDefault', '']
  273. ]);
  274. $this->access->expects($this->once())
  275. ->method('readAttribute')
  276. ->with($this->equalTo($this->dn),
  277. $this->equalTo('myquota'))
  278. ->willReturn(false);
  279. $coreUser = $this->createMock(IUser::class);
  280. $coreUser->expects($this->never())
  281. ->method('setQuota');
  282. $this->userManager->expects($this->never())
  283. ->method('get')
  284. ->with($this->uid);
  285. $this->config->expects($this->never())
  286. ->method('setUserValue');
  287. $this->user->updateQuota();
  288. }
  289. public function testUpdateQuotaNoneConfigured() {
  290. $this->connection->expects($this->exactly(2))
  291. ->method('__get')
  292. ->willReturnMap([
  293. ['ldapQuotaAttribute', ''],
  294. ['ldapQuotaDefault', '']
  295. ]);
  296. $coreUser = $this->createMock(IUser::class);
  297. $coreUser->expects($this->never())
  298. ->method('setQuota');
  299. $this->userManager->expects($this->never())
  300. ->method('get');
  301. $this->access->expects($this->never())
  302. ->method('readAttribute');
  303. $this->config->expects($this->never())
  304. ->method('setUserValue');
  305. $this->user->updateQuota();
  306. }
  307. public function testUpdateQuotaFromValue() {
  308. $readQuota = '19 GB';
  309. $this->connection->expects($this->exactly(2))
  310. ->method('__get')
  311. ->willReturnMap([
  312. ['ldapQuotaAttribute', 'myquota'],
  313. ['ldapQuotaDefault', '']
  314. ]);
  315. $this->access->expects($this->never())
  316. ->method('readAttribute');
  317. $user = $this->createMock(IUser::class);
  318. $user->expects($this->once())
  319. ->method('setQuota')
  320. ->with($readQuota);
  321. $this->userManager->expects($this->once())
  322. ->method('get')
  323. ->with($this->uid)
  324. ->willReturn($user);
  325. $this->user->updateQuota($readQuota);
  326. }
  327. /**
  328. * Unparseable quota will fallback to use the LDAP default
  329. */
  330. public function testUpdateWrongQuotaAllProvided() {
  331. $this->connection->expects($this->exactly(2))
  332. ->method('__get')
  333. ->willReturnMap([
  334. ['ldapQuotaAttribute', 'myquota'],
  335. ['ldapQuotaDefault', '23 GB']
  336. ]);
  337. $this->access->expects($this->once())
  338. ->method('readAttribute')
  339. ->with($this->equalTo($this->dn),
  340. $this->equalTo('myquota'))
  341. ->willReturn(['42 GBwos']);
  342. $coreUser = $this->createMock(IUser::class);
  343. $coreUser->expects($this->once())
  344. ->method('setQuota')
  345. ->with('23 GB');
  346. $this->userManager->expects($this->once())
  347. ->method('get')
  348. ->with($this->uid)
  349. ->willReturn($coreUser);
  350. $this->user->updateQuota();
  351. }
  352. /**
  353. * No user quota and wrong default will set 'default' as quota
  354. */
  355. public function testUpdateWrongDefaultQuotaProvided() {
  356. $this->connection->expects($this->exactly(2))
  357. ->method('__get')
  358. ->willReturnMap([
  359. ['ldapQuotaAttribute', 'myquota'],
  360. ['ldapQuotaDefault', '23 GBwowowo']
  361. ]);
  362. $this->access->expects($this->once())
  363. ->method('readAttribute')
  364. ->with($this->equalTo($this->dn),
  365. $this->equalTo('myquota'))
  366. ->willReturn(false);
  367. $coreUser = $this->createMock(IUser::class);
  368. $coreUser->expects($this->never())
  369. ->method('setQuota');
  370. $this->userManager->expects($this->never())
  371. ->method('get');
  372. $this->user->updateQuota();
  373. }
  374. /**
  375. * Wrong user quota and wrong default will set 'default' as quota
  376. */
  377. public function testUpdateWrongQuotaAndDefaultAllProvided() {
  378. $this->connection->expects($this->exactly(2))
  379. ->method('__get')
  380. ->willReturnMap([
  381. ['ldapQuotaAttribute', 'myquota'],
  382. ['ldapQuotaDefault', '23 GBwowowo']
  383. ]);
  384. $this->access->expects($this->once())
  385. ->method('readAttribute')
  386. ->with($this->equalTo($this->dn),
  387. $this->equalTo('myquota'))
  388. ->willReturn(['23 flush']);
  389. $coreUser = $this->createMock(IUser::class);
  390. $coreUser->expects($this->never())
  391. ->method('setQuota');
  392. $this->userManager->expects($this->never())
  393. ->method('get');
  394. $this->user->updateQuota();
  395. }
  396. /**
  397. * No quota attribute set and wrong default will set 'default' as quota
  398. */
  399. public function testUpdateWrongDefaultQuotaNotProvided() {
  400. $this->connection->expects($this->exactly(2))
  401. ->method('__get')
  402. ->willReturnMap([
  403. ['ldapQuotaAttribute', ''],
  404. ['ldapQuotaDefault', '23 GBwowowo']
  405. ]);
  406. $this->access->expects($this->never())
  407. ->method('readAttribute');
  408. $coreUser = $this->createMock(IUser::class);
  409. $coreUser->expects($this->never())
  410. ->method('setQuota');
  411. $this->userManager->expects($this->never())
  412. ->method('get');
  413. $this->user->updateQuota();
  414. }
  415. //the testUpdateAvatar series also implicitely tests getAvatarImage
  416. public function XtestUpdateAvatarJpegPhotoProvided() {
  417. $this->access->expects($this->once())
  418. ->method('readAttribute')
  419. ->with($this->equalTo($this->dn),
  420. $this->equalTo('jpegphoto'))
  421. ->willReturn(['this is a photo']);
  422. $this->image->expects($this->once())
  423. ->method('loadFromBase64')
  424. ->willReturn('imageResource');
  425. $this->image->expects($this->once())
  426. ->method('valid')
  427. ->willReturn(true);
  428. $this->image->expects($this->once())
  429. ->method('width')
  430. ->willReturn(128);
  431. $this->image->expects($this->once())
  432. ->method('height')
  433. ->willReturn(128);
  434. $this->image->expects($this->once())
  435. ->method('centerCrop')
  436. ->willReturn(true);
  437. $this->image->expects($this->once())
  438. ->method('data')
  439. ->willReturn('this is a photo');
  440. $this->config->expects($this->once())
  441. ->method('getUserValue')
  442. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '')
  443. ->willReturn('');
  444. $this->config->expects($this->once())
  445. ->method('setUserValue')
  446. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo'));
  447. $this->filesystemhelper->expects($this->once())
  448. ->method('isLoaded')
  449. ->willReturn(true);
  450. $avatar = $this->createMock(IAvatar::class);
  451. $avatar->expects($this->once())
  452. ->method('set')
  453. ->with($this->isInstanceOf($this->image));
  454. $this->avatarManager->expects($this->once())
  455. ->method('getAvatar')
  456. ->with($this->equalTo($this->uid))
  457. ->willReturn($avatar);
  458. $this->connection->expects($this->any())
  459. ->method('resolveRule')
  460. ->with('avatar')
  461. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  462. $this->user->updateAvatar();
  463. }
  464. public function testUpdateAvatarKnownJpegPhotoProvided() {
  465. $this->access->expects($this->once())
  466. ->method('readAttribute')
  467. ->with($this->equalTo($this->dn),
  468. $this->equalTo('jpegphoto'))
  469. ->willReturn(['this is a photo']);
  470. $this->image->expects($this->once())
  471. ->method('loadFromBase64')
  472. ->willReturn('imageResource');
  473. $this->image->expects($this->never())
  474. ->method('valid');
  475. $this->image->expects($this->never())
  476. ->method('width');
  477. $this->image->expects($this->never())
  478. ->method('height');
  479. $this->image->expects($this->never())
  480. ->method('centerCrop');
  481. $this->image->expects($this->once())
  482. ->method('data')
  483. ->willReturn('this is a photo');
  484. $this->config->expects($this->once())
  485. ->method('getUserValue')
  486. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '')
  487. ->willReturn(md5('this is a photo'));
  488. $this->config->expects($this->never())
  489. ->method('setUserValue');
  490. $this->filesystemhelper->expects($this->never())
  491. ->method('isLoaded');
  492. $avatar = $this->createMock(IAvatar::class);
  493. $avatar->expects($this->never())
  494. ->method('set');
  495. $this->avatarManager->expects($this->never())
  496. ->method('getAvatar');
  497. $this->connection->expects($this->any())
  498. ->method('resolveRule')
  499. ->with('avatar')
  500. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  501. $this->assertTrue($this->user->updateAvatar());
  502. }
  503. public function XtestUpdateAvatarThumbnailPhotoProvided() {
  504. $this->access->expects($this->any())
  505. ->method('readAttribute')
  506. ->willReturnCallback(function ($dn, $attr) {
  507. if ($dn === $this->dn
  508. && $attr === 'jpegphoto') {
  509. return false;
  510. } elseif ($dn === $this->dn
  511. && $attr === 'thumbnailphoto') {
  512. return ['this is a photo'];
  513. }
  514. return null;
  515. });
  516. $this->image->expects($this->once())
  517. ->method('loadFromBase64')
  518. ->willReturn('imageResource');
  519. $this->image->expects($this->once())
  520. ->method('valid')
  521. ->willReturn(true);
  522. $this->image->expects($this->once())
  523. ->method('width')
  524. ->willReturn(128);
  525. $this->image->expects($this->once())
  526. ->method('height')
  527. ->willReturn(128);
  528. $this->image->expects($this->once())
  529. ->method('centerCrop')
  530. ->willReturn(true);
  531. $this->image->expects($this->once())
  532. ->method('data')
  533. ->willReturn('this is a photo');
  534. $this->config->expects($this->once())
  535. ->method('getUserValue')
  536. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '')
  537. ->willReturn('');
  538. $this->config->expects($this->once())
  539. ->method('setUserValue')
  540. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo'));
  541. $this->filesystemhelper->expects($this->once())
  542. ->method('isLoaded')
  543. ->willReturn(true);
  544. $avatar = $this->createMock(IAvatar::class);
  545. $avatar->expects($this->once())
  546. ->method('set')
  547. ->with($this->isInstanceOf($this->image));
  548. $this->avatarManager->expects($this->once())
  549. ->method('getAvatar')
  550. ->with($this->equalTo($this->uid))
  551. ->willReturn($avatar);
  552. $this->connection->expects($this->any())
  553. ->method('resolveRule')
  554. ->with('avatar')
  555. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  556. $this->user->updateAvatar();
  557. }
  558. public function testUpdateAvatarCorruptPhotoProvided() {
  559. $this->access->expects($this->any())
  560. ->method('readAttribute')
  561. ->willReturnCallback(function ($dn, $attr) {
  562. if ($dn === $this->dn
  563. && $attr === 'jpegphoto') {
  564. return false;
  565. } elseif ($dn === $this->dn
  566. && $attr === 'thumbnailphoto') {
  567. return ['this is a photo'];
  568. }
  569. return null;
  570. });
  571. $this->image->expects($this->once())
  572. ->method('loadFromBase64')
  573. ->willReturn(false);
  574. $this->image->expects($this->never())
  575. ->method('valid');
  576. $this->image->expects($this->never())
  577. ->method('width');
  578. $this->image->expects($this->never())
  579. ->method('height');
  580. $this->image->expects($this->never())
  581. ->method('centerCrop');
  582. $this->image->expects($this->never())
  583. ->method('data');
  584. $this->config->expects($this->never())
  585. ->method('getUserValue');
  586. $this->config->expects($this->never())
  587. ->method('setUserValue');
  588. $this->filesystemhelper->expects($this->never())
  589. ->method('isLoaded');
  590. $avatar = $this->createMock(IAvatar::class);
  591. $avatar->expects($this->never())
  592. ->method('set');
  593. $this->avatarManager->expects($this->never())
  594. ->method('getAvatar');
  595. $this->connection->expects($this->any())
  596. ->method('resolveRule')
  597. ->with('avatar')
  598. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  599. $this->user->updateAvatar();
  600. }
  601. public function XtestUpdateAvatarUnsupportedThumbnailPhotoProvided() {
  602. $this->access->expects($this->any())
  603. ->method('readAttribute')
  604. ->willReturnCallback(function ($dn, $attr) {
  605. if ($dn === $this->dn
  606. && $attr === 'jpegphoto') {
  607. return false;
  608. } elseif ($dn === $this->dn
  609. && $attr === 'thumbnailphoto') {
  610. return ['this is a photo'];
  611. }
  612. return null;
  613. });
  614. $this->image->expects($this->once())
  615. ->method('loadFromBase64')
  616. ->willReturn('imageResource');
  617. $this->image->expects($this->once())
  618. ->method('valid')
  619. ->willReturn(true);
  620. $this->image->expects($this->once())
  621. ->method('width')
  622. ->willReturn(128);
  623. $this->image->expects($this->once())
  624. ->method('height')
  625. ->willReturn(128);
  626. $this->image->expects($this->once())
  627. ->method('centerCrop')
  628. ->willReturn(true);
  629. $this->image->expects($this->once())
  630. ->method('data')
  631. ->willReturn('this is a photo');
  632. $this->config->expects($this->once())
  633. ->method('getUserValue')
  634. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '')
  635. ->willReturn('');
  636. $this->config->expects($this->never())
  637. ->method('setUserValue');
  638. $this->filesystemhelper->expects($this->once())
  639. ->method('isLoaded')
  640. ->willReturn(true);
  641. $avatar = $this->createMock(IAvatar::class);
  642. $avatar->expects($this->once())
  643. ->method('set')
  644. ->with($this->isInstanceOf($this->image))
  645. ->willThrowException(new \Exception());
  646. $this->avatarManager->expects($this->once())
  647. ->method('getAvatar')
  648. ->with($this->equalTo($this->uid))
  649. ->willReturn($avatar);
  650. $this->connection->expects($this->any())
  651. ->method('resolveRule')
  652. ->with('avatar')
  653. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  654. $this->assertFalse($this->user->updateAvatar());
  655. }
  656. public function testUpdateAvatarNotProvided() {
  657. $this->access->expects($this->any())
  658. ->method('readAttribute')
  659. ->willReturnCallback(function ($dn, $attr) {
  660. if ($dn === $this->dn
  661. && $attr === 'jpegPhoto') {
  662. return false;
  663. } elseif ($dn === $this->dn
  664. && $attr === 'thumbnailPhoto') {
  665. return false;
  666. }
  667. return null;
  668. });
  669. $this->image->expects($this->never())
  670. ->method('valid');
  671. $this->image->expects($this->never())
  672. ->method('width');
  673. $this->image->expects($this->never())
  674. ->method('height');
  675. $this->image->expects($this->never())
  676. ->method('centerCrop');
  677. $this->image->expects($this->never())
  678. ->method('data');
  679. $this->config->expects($this->never())
  680. ->method('getUserValue');
  681. $this->config->expects($this->never())
  682. ->method('setUserValue');
  683. $this->filesystemhelper->expects($this->never())
  684. ->method('isLoaded');
  685. $this->avatarManager->expects($this->never())
  686. ->method('getAvatar');
  687. $this->connection->expects($this->any())
  688. ->method('resolveRule')
  689. ->with('avatar')
  690. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  691. $this->user->updateAvatar();
  692. }
  693. public function extStorageHomeDataProvider() {
  694. return [
  695. [ 'myFolder', null ],
  696. [ '', null, false ],
  697. [ 'myFolder', 'myFolder' ],
  698. ];
  699. }
  700. /**
  701. * @dataProvider extStorageHomeDataProvider
  702. */
  703. public function testUpdateExtStorageHome(string $expected, string $valueFromLDAP = null, bool $isSet = true) {
  704. if ($valueFromLDAP === null) {
  705. $this->connection->expects($this->once())
  706. ->method('__get')
  707. ->willReturnMap([
  708. ['ldapExtStorageHomeAttribute', 'homeDirectory'],
  709. ]);
  710. $return = [];
  711. if ($isSet) {
  712. $return[] = $expected;
  713. }
  714. $this->access->expects($this->once())
  715. ->method('readAttribute')
  716. ->with($this->dn, 'homeDirectory')
  717. ->willReturn($return);
  718. }
  719. if ($expected !== '') {
  720. $this->config->expects($this->once())
  721. ->method('setUserValue')
  722. ->with($this->uid, 'user_ldap', 'extStorageHome', $expected);
  723. } else {
  724. $this->config->expects($this->once())
  725. ->method('deleteUserValue')
  726. ->with($this->uid, 'user_ldap', 'extStorageHome');
  727. }
  728. $actual = $this->user->updateExtStorageHome($valueFromLDAP);
  729. $this->assertSame($expected, $actual);
  730. }
  731. public function testMarkLogin() {
  732. $this->config->expects($this->once())
  733. ->method('setUserValue')
  734. ->with($this->equalTo($this->uid),
  735. $this->equalTo('user_ldap'),
  736. $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN),
  737. $this->equalTo(1))
  738. ->willReturn(true);
  739. $this->user->markLogin();
  740. }
  741. public function testGetAvatarImageProvided() {
  742. $this->access->expects($this->once())
  743. ->method('readAttribute')
  744. ->with($this->equalTo($this->dn),
  745. $this->equalTo('jpegphoto'))
  746. ->willReturn(['this is a photo']);
  747. $this->connection->expects($this->any())
  748. ->method('resolveRule')
  749. ->with('avatar')
  750. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  751. $photo = $this->user->getAvatarImage();
  752. $this->assertSame('this is a photo', $photo);
  753. //make sure readAttribute is not called again but the already fetched
  754. //photo is returned
  755. $this->user->getAvatarImage();
  756. }
  757. public function testGetAvatarImageDisabled() {
  758. $this->access->expects($this->never())
  759. ->method('readAttribute')
  760. ->with($this->equalTo($this->dn), $this->anything());
  761. $this->connection->expects($this->any())
  762. ->method('resolveRule')
  763. ->with('avatar')
  764. ->willReturn([]);
  765. $this->assertFalse($this->user->getAvatarImage());
  766. }
  767. public function imageDataProvider() {
  768. return [
  769. [ false, false ],
  770. [ 'corruptData', false ],
  771. [ 'validData', true ],
  772. ];
  773. }
  774. public function testProcessAttributes() {
  775. $requiredMethods = [
  776. 'updateQuota',
  777. 'updateEmail',
  778. 'composeAndStoreDisplayName',
  779. 'storeLDAPUserName',
  780. 'getHomePath',
  781. 'updateAvatar',
  782. 'updateExtStorageHome',
  783. ];
  784. /** @var User|\PHPUnit\Framework\MockObject\MockObject $userMock */
  785. $userMock = $this->getMockBuilder(User::class)
  786. ->setConstructorArgs([
  787. $this->uid,
  788. $this->dn,
  789. $this->access,
  790. $this->config,
  791. $this->filesystemhelper,
  792. $this->image,
  793. $this->log,
  794. $this->avatarManager,
  795. $this->userManager,
  796. $this->notificationManager
  797. ])
  798. ->setMethods($requiredMethods)
  799. ->getMock();
  800. $this->connection->setConfiguration([
  801. 'homeFolderNamingRule' => 'homeDirectory'
  802. ]);
  803. $this->connection->expects($this->any())
  804. ->method('__get')
  805. ->willReturnCallback(function ($name) {
  806. if ($name === 'homeFolderNamingRule') {
  807. return 'attr:homeDirectory';
  808. }
  809. return $name;
  810. });
  811. $this->connection->expects($this->any())
  812. ->method('resolveRule')
  813. ->with('avatar')
  814. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  815. $record = [
  816. strtolower($this->connection->ldapQuotaAttribute) => ['4096'],
  817. strtolower($this->connection->ldapEmailAttribute) => ['alice@wonderland.org'],
  818. strtolower($this->connection->ldapUserDisplayName) => ['Aaaaalice'],
  819. strtolower($this->connection->ldapExtStorageHomeAttribute) => ['homeDirectory'],
  820. 'uid' => [$this->uid],
  821. 'homedirectory' => ['Alice\'s Folder'],
  822. 'memberof' => ['cn=groupOne', 'cn=groupTwo'],
  823. 'jpegphoto' => ['here be an image']
  824. ];
  825. foreach ($requiredMethods as $method) {
  826. $userMock->expects($this->once())
  827. ->method($method);
  828. }
  829. \OC_Hook::clear();//disconnect irrelevant hooks
  830. $userMock->processAttributes($record);
  831. /** @noinspection PhpUnhandledExceptionInspection */
  832. \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]);
  833. }
  834. public function emptyHomeFolderAttributeValueProvider() {
  835. return [
  836. 'empty' => [''],
  837. 'prefixOnly' => ['attr:'],
  838. ];
  839. }
  840. /**
  841. * @dataProvider emptyHomeFolderAttributeValueProvider
  842. */
  843. public function testGetHomePathNotConfigured($attributeValue) {
  844. $this->connection->expects($this->any())
  845. ->method('__get')
  846. ->with($this->equalTo('homeFolderNamingRule'))
  847. ->willReturn($attributeValue);
  848. $this->access->expects($this->never())
  849. ->method('readAttribute');
  850. $this->config->expects($this->never())
  851. ->method('getAppValue');
  852. /** @noinspection PhpUnhandledExceptionInspection */
  853. $this->assertFalse($this->user->getHomePath());
  854. }
  855. public function testGetHomePathConfiguredNotAvailableAllowed() {
  856. $this->connection->expects($this->any())
  857. ->method('__get')
  858. ->with($this->equalTo('homeFolderNamingRule'))
  859. ->willReturn('attr:foobar');
  860. $this->access->expects($this->once())
  861. ->method('readAttribute')
  862. ->willReturn(false);
  863. // asks for "enforce_home_folder_naming_rule"
  864. $this->config->expects($this->once())
  865. ->method('getAppValue')
  866. ->willReturn(false);
  867. /** @noinspection PhpUnhandledExceptionInspection */
  868. $this->assertFalse($this->user->getHomePath());
  869. }
  870. public function testGetHomePathConfiguredNotAvailableNotAllowed() {
  871. $this->expectException(\Exception::class);
  872. $this->connection->expects($this->any())
  873. ->method('__get')
  874. ->with($this->equalTo('homeFolderNamingRule'))
  875. ->willReturn('attr:foobar');
  876. $this->access->expects($this->once())
  877. ->method('readAttribute')
  878. ->willReturn(false);
  879. // asks for "enforce_home_folder_naming_rule"
  880. $this->config->expects($this->once())
  881. ->method('getAppValue')
  882. ->willReturn(true);
  883. $this->user->getHomePath();
  884. }
  885. public function displayNameProvider() {
  886. return [
  887. ['Roland Deschain', '', 'Roland Deschain', false],
  888. ['Roland Deschain', '', 'Roland Deschain', true],
  889. ['Roland Deschain', null, 'Roland Deschain', false],
  890. ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', false],
  891. ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', true],
  892. ];
  893. }
  894. /**
  895. * @dataProvider displayNameProvider
  896. */
  897. public function testComposeAndStoreDisplayName($part1, $part2, $expected, $expectTriggerChange) {
  898. $this->config->expects($this->once())
  899. ->method('setUserValue');
  900. $oldName = $expectTriggerChange ? 'xxGunslingerxx' : null;
  901. $this->config->expects($this->once())
  902. ->method('getUserValue')
  903. ->with($this->user->getUsername(), 'user_ldap', 'displayName', null)
  904. ->willReturn($oldName);
  905. $ncUserObj = $this->createMock(\OC\User\User::class);
  906. if ($expectTriggerChange) {
  907. $ncUserObj->expects($this->once())
  908. ->method('triggerChange')
  909. ->with('displayName', $expected);
  910. } else {
  911. $ncUserObj->expects($this->never())
  912. ->method('triggerChange');
  913. }
  914. $this->userManager->expects($this->once())
  915. ->method('get')
  916. ->willReturn($ncUserObj);
  917. $displayName = $this->user->composeAndStoreDisplayName($part1, $part2);
  918. $this->assertSame($expected, $displayName);
  919. }
  920. public function testComposeAndStoreDisplayNameNoOverwrite() {
  921. $displayName = 'Randall Flagg';
  922. $this->config->expects($this->never())
  923. ->method('setUserValue');
  924. $this->config->expects($this->once())
  925. ->method('getUserValue')
  926. ->willReturn($displayName);
  927. $this->userManager->expects($this->never())
  928. ->method('get'); // Implicit: no triggerChange can be called
  929. $composedDisplayName = $this->user->composeAndStoreDisplayName($displayName);
  930. $this->assertSame($composedDisplayName, $displayName);
  931. }
  932. public function testHandlePasswordExpiryWarningDefaultPolicy() {
  933. $this->connection->expects($this->any())
  934. ->method('__get')
  935. ->willReturnCallback(function ($name) {
  936. if ($name === 'ldapDefaultPPolicyDN') {
  937. return 'cn=default,ou=policies,dc=foo,dc=bar';
  938. }
  939. if ($name === 'turnOnPasswordChange') {
  940. return '1';
  941. }
  942. return $name;
  943. });
  944. $this->access->expects($this->any())
  945. ->method('search')
  946. ->willReturnCallback(function ($filter, $base) {
  947. if ($base === $this->dn) {
  948. return [
  949. [
  950. 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'],
  951. 'pwdgraceusetime' => [],
  952. ],
  953. ];
  954. }
  955. if ($base === 'cn=default,ou=policies,dc=foo,dc=bar') {
  956. return [
  957. [
  958. 'pwdmaxage' => ['2592000'],
  959. 'pwdexpirewarning' => ['2591999'],
  960. ],
  961. ];
  962. }
  963. return [];
  964. });
  965. $notification = $this->getMockBuilder(INotification::class)
  966. ->disableOriginalConstructor()
  967. ->getMock();
  968. $notification->expects($this->any())
  969. ->method('setApp')
  970. ->willReturn($notification);
  971. $notification->expects($this->any())
  972. ->method('setUser')
  973. ->willReturn($notification);
  974. $notification->expects($this->any())
  975. ->method('setObject')
  976. ->willReturn($notification);
  977. $notification->expects($this->any())
  978. ->method('setDateTime')
  979. ->willReturn($notification);
  980. $this->notificationManager->expects($this->exactly(2))
  981. ->method('createNotification')
  982. ->willReturn($notification);
  983. $this->notificationManager->expects($this->exactly(1))
  984. ->method('notify');
  985. \OC_Hook::clear();//disconnect irrelevant hooks
  986. \OCP\Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry');
  987. /** @noinspection PhpUnhandledExceptionInspection */
  988. \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]);
  989. }
  990. public function testHandlePasswordExpiryWarningCustomPolicy() {
  991. $this->connection->expects($this->any())
  992. ->method('__get')
  993. ->willReturnCallback(function ($name) {
  994. if ($name === 'ldapDefaultPPolicyDN') {
  995. return 'cn=default,ou=policies,dc=foo,dc=bar';
  996. }
  997. if ($name === 'turnOnPasswordChange') {
  998. return '1';
  999. }
  1000. return $name;
  1001. });
  1002. $this->access->expects($this->any())
  1003. ->method('search')
  1004. ->willReturnCallback(function ($filter, $base) {
  1005. if ($base === $this->dn) {
  1006. return [
  1007. [
  1008. 'pwdpolicysubentry' => ['cn=custom,ou=policies,dc=foo,dc=bar'],
  1009. 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'],
  1010. 'pwdgraceusetime' => [],
  1011. ]
  1012. ];
  1013. }
  1014. if ($base === 'cn=custom,ou=policies,dc=foo,dc=bar') {
  1015. return [
  1016. [
  1017. 'pwdmaxage' => ['2592000'],
  1018. 'pwdexpirewarning' => ['2591999'],
  1019. ]
  1020. ];
  1021. }
  1022. return [];
  1023. });
  1024. $notification = $this->getMockBuilder(INotification::class)
  1025. ->disableOriginalConstructor()
  1026. ->getMock();
  1027. $notification->expects($this->any())
  1028. ->method('setApp')
  1029. ->willReturn($notification);
  1030. $notification->expects($this->any())
  1031. ->method('setUser')
  1032. ->willReturn($notification);
  1033. $notification->expects($this->any())
  1034. ->method('setObject')
  1035. ->willReturn($notification);
  1036. $notification->expects($this->any())
  1037. ->method('setDateTime')
  1038. ->willReturn($notification);
  1039. $this->notificationManager->expects($this->exactly(2))
  1040. ->method('createNotification')
  1041. ->willReturn($notification);
  1042. $this->notificationManager->expects($this->exactly(1))
  1043. ->method('notify');
  1044. \OC_Hook::clear();//disconnect irrelevant hooks
  1045. \OCP\Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry');
  1046. /** @noinspection PhpUnhandledExceptionInspection */
  1047. \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]);
  1048. }
  1049. }