1
0

UserTest.php 33 KB

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