UserTest.php 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  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. $avatar->expects($this->any())
  492. ->method('exists')
  493. ->willReturn(true);
  494. $avatar->expects($this->any())
  495. ->method('isCustomAvatar')
  496. ->willReturn(true);
  497. $this->avatarManager->expects($this->any())
  498. ->method('getAvatar')
  499. ->with($this->uid)
  500. ->willReturn($avatar);
  501. $this->connection->expects($this->any())
  502. ->method('resolveRule')
  503. ->with('avatar')
  504. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  505. $this->assertTrue($this->user->updateAvatar());
  506. }
  507. public function XtestUpdateAvatarThumbnailPhotoProvided() {
  508. $this->access->expects($this->any())
  509. ->method('readAttribute')
  510. ->willReturnCallback(function ($dn, $attr) {
  511. if ($dn === $this->dn
  512. && $attr === 'jpegphoto') {
  513. return false;
  514. } elseif ($dn === $this->dn
  515. && $attr === 'thumbnailphoto') {
  516. return ['this is a photo'];
  517. }
  518. return null;
  519. });
  520. $this->image->expects($this->once())
  521. ->method('loadFromBase64')
  522. ->willReturn('imageResource');
  523. $this->image->expects($this->once())
  524. ->method('valid')
  525. ->willReturn(true);
  526. $this->image->expects($this->once())
  527. ->method('width')
  528. ->willReturn(128);
  529. $this->image->expects($this->once())
  530. ->method('height')
  531. ->willReturn(128);
  532. $this->image->expects($this->once())
  533. ->method('centerCrop')
  534. ->willReturn(true);
  535. $this->image->expects($this->once())
  536. ->method('data')
  537. ->willReturn('this is a photo');
  538. $this->config->expects($this->once())
  539. ->method('getUserValue')
  540. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '')
  541. ->willReturn('');
  542. $this->config->expects($this->once())
  543. ->method('setUserValue')
  544. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo'));
  545. $this->filesystemhelper->expects($this->once())
  546. ->method('isLoaded')
  547. ->willReturn(true);
  548. $avatar = $this->createMock(IAvatar::class);
  549. $avatar->expects($this->once())
  550. ->method('set')
  551. ->with($this->isInstanceOf($this->image));
  552. $this->avatarManager->expects($this->once())
  553. ->method('getAvatar')
  554. ->with($this->equalTo($this->uid))
  555. ->willReturn($avatar);
  556. $this->connection->expects($this->any())
  557. ->method('resolveRule')
  558. ->with('avatar')
  559. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  560. $this->user->updateAvatar();
  561. }
  562. public function testUpdateAvatarCorruptPhotoProvided() {
  563. $this->access->expects($this->any())
  564. ->method('readAttribute')
  565. ->willReturnCallback(function ($dn, $attr) {
  566. if ($dn === $this->dn
  567. && $attr === 'jpegphoto') {
  568. return false;
  569. } elseif ($dn === $this->dn
  570. && $attr === 'thumbnailphoto') {
  571. return ['this is a photo'];
  572. }
  573. return null;
  574. });
  575. $this->image->expects($this->once())
  576. ->method('loadFromBase64')
  577. ->willReturn(false);
  578. $this->image->expects($this->never())
  579. ->method('valid');
  580. $this->image->expects($this->never())
  581. ->method('width');
  582. $this->image->expects($this->never())
  583. ->method('height');
  584. $this->image->expects($this->never())
  585. ->method('centerCrop');
  586. $this->image->expects($this->never())
  587. ->method('data');
  588. $this->config->expects($this->never())
  589. ->method('getUserValue');
  590. $this->config->expects($this->never())
  591. ->method('setUserValue');
  592. $this->filesystemhelper->expects($this->never())
  593. ->method('isLoaded');
  594. $avatar = $this->createMock(IAvatar::class);
  595. $avatar->expects($this->never())
  596. ->method('set');
  597. $this->avatarManager->expects($this->never())
  598. ->method('getAvatar');
  599. $this->connection->expects($this->any())
  600. ->method('resolveRule')
  601. ->with('avatar')
  602. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  603. $this->user->updateAvatar();
  604. }
  605. public function XtestUpdateAvatarUnsupportedThumbnailPhotoProvided() {
  606. $this->access->expects($this->any())
  607. ->method('readAttribute')
  608. ->willReturnCallback(function ($dn, $attr) {
  609. if ($dn === $this->dn
  610. && $attr === 'jpegphoto') {
  611. return false;
  612. } elseif ($dn === $this->dn
  613. && $attr === 'thumbnailphoto') {
  614. return ['this is a photo'];
  615. }
  616. return null;
  617. });
  618. $this->image->expects($this->once())
  619. ->method('loadFromBase64')
  620. ->willReturn('imageResource');
  621. $this->image->expects($this->once())
  622. ->method('valid')
  623. ->willReturn(true);
  624. $this->image->expects($this->once())
  625. ->method('width')
  626. ->willReturn(128);
  627. $this->image->expects($this->once())
  628. ->method('height')
  629. ->willReturn(128);
  630. $this->image->expects($this->once())
  631. ->method('centerCrop')
  632. ->willReturn(true);
  633. $this->image->expects($this->once())
  634. ->method('data')
  635. ->willReturn('this is a photo');
  636. $this->config->expects($this->once())
  637. ->method('getUserValue')
  638. ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '')
  639. ->willReturn('');
  640. $this->config->expects($this->never())
  641. ->method('setUserValue');
  642. $this->filesystemhelper->expects($this->once())
  643. ->method('isLoaded')
  644. ->willReturn(true);
  645. $avatar = $this->createMock(IAvatar::class);
  646. $avatar->expects($this->once())
  647. ->method('set')
  648. ->with($this->isInstanceOf($this->image))
  649. ->willThrowException(new \Exception());
  650. $this->avatarManager->expects($this->once())
  651. ->method('getAvatar')
  652. ->with($this->equalTo($this->uid))
  653. ->willReturn($avatar);
  654. $this->connection->expects($this->any())
  655. ->method('resolveRule')
  656. ->with('avatar')
  657. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  658. $this->assertFalse($this->user->updateAvatar());
  659. }
  660. public function testUpdateAvatarNotProvided() {
  661. $this->access->expects($this->any())
  662. ->method('readAttribute')
  663. ->willReturnCallback(function ($dn, $attr) {
  664. if ($dn === $this->dn
  665. && $attr === 'jpegPhoto') {
  666. return false;
  667. } elseif ($dn === $this->dn
  668. && $attr === 'thumbnailPhoto') {
  669. return false;
  670. }
  671. return null;
  672. });
  673. $this->image->expects($this->never())
  674. ->method('valid');
  675. $this->image->expects($this->never())
  676. ->method('width');
  677. $this->image->expects($this->never())
  678. ->method('height');
  679. $this->image->expects($this->never())
  680. ->method('centerCrop');
  681. $this->image->expects($this->never())
  682. ->method('data');
  683. $this->config->expects($this->never())
  684. ->method('getUserValue');
  685. $this->config->expects($this->never())
  686. ->method('setUserValue');
  687. $this->filesystemhelper->expects($this->never())
  688. ->method('isLoaded');
  689. $this->avatarManager->expects($this->never())
  690. ->method('getAvatar');
  691. $this->connection->expects($this->any())
  692. ->method('resolveRule')
  693. ->with('avatar')
  694. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  695. $this->user->updateAvatar();
  696. }
  697. public function extStorageHomeDataProvider() {
  698. return [
  699. [ 'myFolder', null ],
  700. [ '', null, false ],
  701. [ 'myFolder', 'myFolder' ],
  702. ];
  703. }
  704. /**
  705. * @dataProvider extStorageHomeDataProvider
  706. */
  707. public function testUpdateExtStorageHome(string $expected, string $valueFromLDAP = null, bool $isSet = true) {
  708. if ($valueFromLDAP === null) {
  709. $this->connection->expects($this->once())
  710. ->method('__get')
  711. ->willReturnMap([
  712. ['ldapExtStorageHomeAttribute', 'homeDirectory'],
  713. ]);
  714. $return = [];
  715. if ($isSet) {
  716. $return[] = $expected;
  717. }
  718. $this->access->expects($this->once())
  719. ->method('readAttribute')
  720. ->with($this->dn, 'homeDirectory')
  721. ->willReturn($return);
  722. }
  723. if ($expected !== '') {
  724. $this->config->expects($this->once())
  725. ->method('setUserValue')
  726. ->with($this->uid, 'user_ldap', 'extStorageHome', $expected);
  727. } else {
  728. $this->config->expects($this->once())
  729. ->method('deleteUserValue')
  730. ->with($this->uid, 'user_ldap', 'extStorageHome');
  731. }
  732. $actual = $this->user->updateExtStorageHome($valueFromLDAP);
  733. $this->assertSame($expected, $actual);
  734. }
  735. public function testMarkLogin() {
  736. $this->config->expects($this->once())
  737. ->method('setUserValue')
  738. ->with($this->equalTo($this->uid),
  739. $this->equalTo('user_ldap'),
  740. $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN),
  741. $this->equalTo(1))
  742. ->willReturn(true);
  743. $this->user->markLogin();
  744. }
  745. public function testGetAvatarImageProvided() {
  746. $this->access->expects($this->once())
  747. ->method('readAttribute')
  748. ->with($this->equalTo($this->dn),
  749. $this->equalTo('jpegphoto'))
  750. ->willReturn(['this is a photo']);
  751. $this->connection->expects($this->any())
  752. ->method('resolveRule')
  753. ->with('avatar')
  754. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  755. $photo = $this->user->getAvatarImage();
  756. $this->assertSame('this is a photo', $photo);
  757. //make sure readAttribute is not called again but the already fetched
  758. //photo is returned
  759. $this->user->getAvatarImage();
  760. }
  761. public function testGetAvatarImageDisabled() {
  762. $this->access->expects($this->never())
  763. ->method('readAttribute')
  764. ->with($this->equalTo($this->dn), $this->anything());
  765. $this->connection->expects($this->any())
  766. ->method('resolveRule')
  767. ->with('avatar')
  768. ->willReturn([]);
  769. $this->assertFalse($this->user->getAvatarImage());
  770. }
  771. public function imageDataProvider() {
  772. return [
  773. [ false, false ],
  774. [ 'corruptData', false ],
  775. [ 'validData', true ],
  776. ];
  777. }
  778. public function testProcessAttributes() {
  779. $requiredMethods = [
  780. 'updateQuota',
  781. 'updateEmail',
  782. 'composeAndStoreDisplayName',
  783. 'storeLDAPUserName',
  784. 'getHomePath',
  785. 'updateAvatar',
  786. 'updateExtStorageHome',
  787. ];
  788. /** @var User|\PHPUnit\Framework\MockObject\MockObject $userMock */
  789. $userMock = $this->getMockBuilder(User::class)
  790. ->setConstructorArgs([
  791. $this->uid,
  792. $this->dn,
  793. $this->access,
  794. $this->config,
  795. $this->filesystemhelper,
  796. $this->image,
  797. $this->logger,
  798. $this->avatarManager,
  799. $this->userManager,
  800. $this->notificationManager
  801. ])
  802. ->setMethods($requiredMethods)
  803. ->getMock();
  804. $this->connection->setConfiguration([
  805. 'homeFolderNamingRule' => 'homeDirectory'
  806. ]);
  807. $this->connection->expects($this->any())
  808. ->method('__get')
  809. ->willReturnCallback(function ($name) {
  810. if ($name === 'homeFolderNamingRule') {
  811. return 'attr:homeDirectory';
  812. }
  813. return $name;
  814. });
  815. $this->connection->expects($this->any())
  816. ->method('resolveRule')
  817. ->with('avatar')
  818. ->willReturn(['jpegphoto', 'thumbnailphoto']);
  819. $record = [
  820. strtolower($this->connection->ldapQuotaAttribute) => ['4096'],
  821. strtolower($this->connection->ldapEmailAttribute) => ['alice@wonderland.org'],
  822. strtolower($this->connection->ldapUserDisplayName) => ['Aaaaalice'],
  823. strtolower($this->connection->ldapExtStorageHomeAttribute) => ['homeDirectory'],
  824. 'uid' => [$this->uid],
  825. 'homedirectory' => ['Alice\'s Folder'],
  826. 'memberof' => ['cn=groupOne', 'cn=groupTwo'],
  827. 'jpegphoto' => ['here be an image']
  828. ];
  829. foreach ($requiredMethods as $method) {
  830. $userMock->expects($this->once())
  831. ->method($method);
  832. }
  833. \OC_Hook::clear();//disconnect irrelevant hooks
  834. $userMock->processAttributes($record);
  835. /** @noinspection PhpUnhandledExceptionInspection */
  836. \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]);
  837. }
  838. public function emptyHomeFolderAttributeValueProvider() {
  839. return [
  840. 'empty' => [''],
  841. 'prefixOnly' => ['attr:'],
  842. ];
  843. }
  844. /**
  845. * @dataProvider emptyHomeFolderAttributeValueProvider
  846. */
  847. public function testGetHomePathNotConfigured($attributeValue) {
  848. $this->connection->expects($this->any())
  849. ->method('__get')
  850. ->with($this->equalTo('homeFolderNamingRule'))
  851. ->willReturn($attributeValue);
  852. $this->access->expects($this->never())
  853. ->method('readAttribute');
  854. $this->config->expects($this->never())
  855. ->method('getAppValue');
  856. /** @noinspection PhpUnhandledExceptionInspection */
  857. $this->assertFalse($this->user->getHomePath());
  858. }
  859. public function testGetHomePathConfiguredNotAvailableAllowed() {
  860. $this->connection->expects($this->any())
  861. ->method('__get')
  862. ->with($this->equalTo('homeFolderNamingRule'))
  863. ->willReturn('attr:foobar');
  864. $this->access->expects($this->once())
  865. ->method('readAttribute')
  866. ->willReturn(false);
  867. $this->access->expects($this->once())
  868. ->method('username2dn')
  869. ->willReturn($this->dn);
  870. // asks for "enforce_home_folder_naming_rule"
  871. $this->config->expects($this->once())
  872. ->method('getAppValue')
  873. ->willReturn(false);
  874. /** @noinspection PhpUnhandledExceptionInspection */
  875. $this->assertFalse($this->user->getHomePath());
  876. }
  877. public function testGetHomePathConfiguredNotAvailableNotAllowed() {
  878. $this->expectException(\Exception::class);
  879. $this->connection->expects($this->any())
  880. ->method('__get')
  881. ->with($this->equalTo('homeFolderNamingRule'))
  882. ->willReturn('attr:foobar');
  883. $this->access->expects($this->once())
  884. ->method('readAttribute')
  885. ->willReturn(false);
  886. $this->access->expects($this->once())
  887. ->method('username2dn')
  888. ->willReturn($this->dn);
  889. // asks for "enforce_home_folder_naming_rule"
  890. $this->config->expects($this->once())
  891. ->method('getAppValue')
  892. ->willReturn(true);
  893. $this->user->getHomePath();
  894. }
  895. public function displayNameProvider() {
  896. return [
  897. ['Roland Deschain', '', 'Roland Deschain', false],
  898. ['Roland Deschain', '', 'Roland Deschain', true],
  899. ['Roland Deschain', null, 'Roland Deschain', false],
  900. ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', false],
  901. ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', true],
  902. ];
  903. }
  904. /**
  905. * @dataProvider displayNameProvider
  906. */
  907. public function testComposeAndStoreDisplayName($part1, $part2, $expected, $expectTriggerChange) {
  908. $this->config->expects($this->once())
  909. ->method('setUserValue');
  910. $oldName = $expectTriggerChange ? 'xxGunslingerxx' : null;
  911. $this->config->expects($this->once())
  912. ->method('getUserValue')
  913. ->with($this->user->getUsername(), 'user_ldap', 'displayName', null)
  914. ->willReturn($oldName);
  915. $ncUserObj = $this->createMock(\OC\User\User::class);
  916. if ($expectTriggerChange) {
  917. $ncUserObj->expects($this->once())
  918. ->method('triggerChange')
  919. ->with('displayName', $expected);
  920. } else {
  921. $ncUserObj->expects($this->never())
  922. ->method('triggerChange');
  923. }
  924. $this->userManager->expects($this->once())
  925. ->method('get')
  926. ->willReturn($ncUserObj);
  927. $displayName = $this->user->composeAndStoreDisplayName($part1, $part2);
  928. $this->assertSame($expected, $displayName);
  929. }
  930. public function testComposeAndStoreDisplayNameNoOverwrite() {
  931. $displayName = 'Randall Flagg';
  932. $this->config->expects($this->never())
  933. ->method('setUserValue');
  934. $this->config->expects($this->once())
  935. ->method('getUserValue')
  936. ->willReturn($displayName);
  937. $this->userManager->expects($this->never())
  938. ->method('get'); // Implicit: no triggerChange can be called
  939. $composedDisplayName = $this->user->composeAndStoreDisplayName($displayName);
  940. $this->assertSame($composedDisplayName, $displayName);
  941. }
  942. public function testHandlePasswordExpiryWarningDefaultPolicy() {
  943. $this->connection->expects($this->any())
  944. ->method('__get')
  945. ->willReturnCallback(function ($name) {
  946. if ($name === 'ldapDefaultPPolicyDN') {
  947. return 'cn=default,ou=policies,dc=foo,dc=bar';
  948. }
  949. if ($name === 'turnOnPasswordChange') {
  950. return '1';
  951. }
  952. return $name;
  953. });
  954. $this->access->expects($this->any())
  955. ->method('search')
  956. ->willReturnCallback(function ($filter, $base) {
  957. if ($base === $this->dn) {
  958. return [
  959. [
  960. 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'],
  961. 'pwdgraceusetime' => [],
  962. ],
  963. ];
  964. }
  965. if ($base === 'cn=default,ou=policies,dc=foo,dc=bar') {
  966. return [
  967. [
  968. 'pwdmaxage' => ['2592000'],
  969. 'pwdexpirewarning' => ['2591999'],
  970. ],
  971. ];
  972. }
  973. return [];
  974. });
  975. $notification = $this->getMockBuilder(INotification::class)
  976. ->disableOriginalConstructor()
  977. ->getMock();
  978. $notification->expects($this->any())
  979. ->method('setApp')
  980. ->willReturn($notification);
  981. $notification->expects($this->any())
  982. ->method('setUser')
  983. ->willReturn($notification);
  984. $notification->expects($this->any())
  985. ->method('setObject')
  986. ->willReturn($notification);
  987. $notification->expects($this->any())
  988. ->method('setDateTime')
  989. ->willReturn($notification);
  990. $this->notificationManager->expects($this->exactly(2))
  991. ->method('createNotification')
  992. ->willReturn($notification);
  993. $this->notificationManager->expects($this->exactly(1))
  994. ->method('notify');
  995. \OC_Hook::clear();//disconnect irrelevant hooks
  996. \OCP\Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry');
  997. /** @noinspection PhpUnhandledExceptionInspection */
  998. \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]);
  999. }
  1000. public function testHandlePasswordExpiryWarningCustomPolicy() {
  1001. $this->connection->expects($this->any())
  1002. ->method('__get')
  1003. ->willReturnCallback(function ($name) {
  1004. if ($name === 'ldapDefaultPPolicyDN') {
  1005. return 'cn=default,ou=policies,dc=foo,dc=bar';
  1006. }
  1007. if ($name === 'turnOnPasswordChange') {
  1008. return '1';
  1009. }
  1010. return $name;
  1011. });
  1012. $this->access->expects($this->any())
  1013. ->method('search')
  1014. ->willReturnCallback(function ($filter, $base) {
  1015. if ($base === $this->dn) {
  1016. return [
  1017. [
  1018. 'pwdpolicysubentry' => ['cn=custom,ou=policies,dc=foo,dc=bar'],
  1019. 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'],
  1020. 'pwdgraceusetime' => [],
  1021. ]
  1022. ];
  1023. }
  1024. if ($base === 'cn=custom,ou=policies,dc=foo,dc=bar') {
  1025. return [
  1026. [
  1027. 'pwdmaxage' => ['2592000'],
  1028. 'pwdexpirewarning' => ['2591999'],
  1029. ]
  1030. ];
  1031. }
  1032. return [];
  1033. });
  1034. $notification = $this->getMockBuilder(INotification::class)
  1035. ->disableOriginalConstructor()
  1036. ->getMock();
  1037. $notification->expects($this->any())
  1038. ->method('setApp')
  1039. ->willReturn($notification);
  1040. $notification->expects($this->any())
  1041. ->method('setUser')
  1042. ->willReturn($notification);
  1043. $notification->expects($this->any())
  1044. ->method('setObject')
  1045. ->willReturn($notification);
  1046. $notification->expects($this->any())
  1047. ->method('setDateTime')
  1048. ->willReturn($notification);
  1049. $this->notificationManager->expects($this->exactly(2))
  1050. ->method('createNotification')
  1051. ->willReturn($notification);
  1052. $this->notificationManager->expects($this->exactly(1))
  1053. ->method('notify');
  1054. \OC_Hook::clear();//disconnect irrelevant hooks
  1055. \OCP\Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry');
  1056. /** @noinspection PhpUnhandledExceptionInspection */
  1057. \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]);
  1058. }
  1059. }