1
0

UserTest.php 33 KB

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