AccessTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
  5. *
  6. * @author Andreas Fischer <bantu@owncloud.com>
  7. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  8. * @author Joas Schilling <coding@schilljs.com>
  9. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  10. * @author Lukas Reschke <lukas@statuscode.ch>
  11. * @author Morris Jobke <hey@morrisjobke.de>
  12. * @author Roeland Jago Douma <roeland@famdouma.nl>
  13. * @author Roger Szabo <roger.szabo@web.de>
  14. * @author root <root@localhost.localdomain>
  15. * @author Thomas Müller <thomas.mueller@tmit.eu>
  16. * @author Victor Dubiniuk <dubiniuk@owncloud.com>
  17. *
  18. * @license AGPL-3.0
  19. *
  20. * This code is free software: you can redistribute it and/or modify
  21. * it under the terms of the GNU Affero General Public License, version 3,
  22. * as published by the Free Software Foundation.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. * GNU Affero General Public License for more details.
  28. *
  29. * You should have received a copy of the GNU Affero General Public License, version 3,
  30. * along with this program. If not, see <http://www.gnu.org/licenses/>
  31. *
  32. */
  33. namespace OCA\User_LDAP\Tests;
  34. use OCA\User_LDAP\Access;
  35. use OCA\User_LDAP\Connection;
  36. use OCA\User_LDAP\Exceptions\ConstraintViolationException;
  37. use OCA\User_LDAP\FilesystemHelper;
  38. use OCA\User_LDAP\Helper;
  39. use OCA\User_LDAP\ILDAPWrapper;
  40. use OCA\User_LDAP\LDAP;
  41. use OCA\User_LDAP\LogWrapper;
  42. use OCA\User_LDAP\Mapping\UserMapping;
  43. use OCA\User_LDAP\User\Manager;
  44. use OCA\User_LDAP\User\OfflineUser;
  45. use OCA\User_LDAP\User\User;
  46. use OCP\IAvatarManager;
  47. use OCP\IConfig;
  48. use OCP\IDBConnection;
  49. use OCP\Image;
  50. use OCP\IUserManager;
  51. use OCP\Notification\IManager as INotificationManager;
  52. use Test\TestCase;
  53. /**
  54. * Class AccessTest
  55. *
  56. * @group DB
  57. *
  58. * @package OCA\User_LDAP\Tests
  59. */
  60. class AccessTest extends TestCase {
  61. /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject */
  62. protected $userMapper;
  63. /** @var Connection|\PHPUnit_Framework_MockObject_MockObject */
  64. private $connection;
  65. /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */
  66. private $ldap;
  67. /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */
  68. private $userManager;
  69. /** @var Helper|\PHPUnit_Framework_MockObject_MockObject */
  70. private $helper;
  71. /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
  72. private $config;
  73. /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */
  74. private $ncUserManager;
  75. /** @var Access */
  76. private $access;
  77. public function setUp() {
  78. $this->connection = $this->createMock(Connection::class);
  79. $this->ldap = $this->createMock(LDAP::class);
  80. $this->userManager = $this->createMock(Manager::class);
  81. $this->helper = $this->createMock(Helper::class);
  82. $this->config = $this->createMock(IConfig::class);
  83. $this->userMapper = $this->createMock(UserMapping::class);
  84. $this->ncUserManager = $this->createMock(IUserManager::class);
  85. $this->access = new Access(
  86. $this->connection,
  87. $this->ldap,
  88. $this->userManager,
  89. $this->helper,
  90. $this->config,
  91. $this->ncUserManager
  92. );
  93. $this->access->setUserMapper($this->userMapper);
  94. }
  95. private function getConnectorAndLdapMock() {
  96. $lw = $this->createMock(ILDAPWrapper::class);
  97. $connector = $this->getMockBuilder(Connection::class)
  98. ->setConstructorArgs([$lw, null, null])
  99. ->getMock();
  100. $um = $this->getMockBuilder(Manager::class)
  101. ->setConstructorArgs([
  102. $this->createMock(IConfig::class),
  103. $this->createMock(FilesystemHelper::class),
  104. $this->createMock(LogWrapper::class),
  105. $this->createMock(IAvatarManager::class),
  106. $this->createMock(Image::class),
  107. $this->createMock(IDBConnection::class),
  108. $this->createMock(IUserManager::class),
  109. $this->createMock(INotificationManager::class)])
  110. ->getMock();
  111. $helper = new Helper(\OC::$server->getConfig());
  112. return array($lw, $connector, $um, $helper);
  113. }
  114. public function testEscapeFilterPartValidChars() {
  115. $input = 'okay';
  116. $this->assertTrue($input === $this->access->escapeFilterPart($input));
  117. }
  118. public function testEscapeFilterPartEscapeWildcard() {
  119. $input = '*';
  120. $expected = '\\\\*';
  121. $this->assertTrue($expected === $this->access->escapeFilterPart($input));
  122. }
  123. public function testEscapeFilterPartEscapeWildcard2() {
  124. $input = 'foo*bar';
  125. $expected = 'foo\\\\*bar';
  126. $this->assertTrue($expected === $this->access->escapeFilterPart($input));
  127. }
  128. /**
  129. * @dataProvider convertSID2StrSuccessData
  130. * @param array $sidArray
  131. * @param $sidExpected
  132. */
  133. public function testConvertSID2StrSuccess(array $sidArray, $sidExpected) {
  134. $sidBinary = implode('', $sidArray);
  135. $this->assertSame($sidExpected, $this->access->convertSID2Str($sidBinary));
  136. }
  137. public function convertSID2StrSuccessData() {
  138. return array(
  139. array(
  140. array(
  141. "\x01",
  142. "\x04",
  143. "\x00\x00\x00\x00\x00\x05",
  144. "\x15\x00\x00\x00",
  145. "\xa6\x81\xe5\x0e",
  146. "\x4d\x6c\x6c\x2b",
  147. "\xca\x32\x05\x5f",
  148. ),
  149. 'S-1-5-21-249921958-728525901-1594176202',
  150. ),
  151. array(
  152. array(
  153. "\x01",
  154. "\x02",
  155. "\xFF\xFF\xFF\xFF\xFF\xFF",
  156. "\xFF\xFF\xFF\xFF",
  157. "\xFF\xFF\xFF\xFF",
  158. ),
  159. 'S-1-281474976710655-4294967295-4294967295',
  160. ),
  161. );
  162. }
  163. public function testConvertSID2StrInputError() {
  164. $sidIllegal = 'foobar';
  165. $sidExpected = '';
  166. $this->assertSame($sidExpected, $this->access->convertSID2Str($sidIllegal));
  167. }
  168. public function testGetDomainDNFromDNSuccess() {
  169. $inputDN = 'uid=zaphod,cn=foobar,dc=my,dc=server,dc=com';
  170. $domainDN = 'dc=my,dc=server,dc=com';
  171. $this->ldap->expects($this->once())
  172. ->method('explodeDN')
  173. ->with($inputDN, 0)
  174. ->will($this->returnValue(explode(',', $inputDN)));
  175. $this->assertSame($domainDN, $this->access->getDomainDNFromDN($inputDN));
  176. }
  177. public function testGetDomainDNFromDNError() {
  178. $inputDN = 'foobar';
  179. $expected = '';
  180. $this->ldap->expects($this->once())
  181. ->method('explodeDN')
  182. ->with($inputDN, 0)
  183. ->will($this->returnValue(false));
  184. $this->assertSame($expected, $this->access->getDomainDNFromDN($inputDN));
  185. }
  186. public function dnInputDataProvider() {
  187. return [[
  188. [
  189. 'input' => 'foo=bar,bar=foo,dc=foobar',
  190. 'interResult' => array(
  191. 'count' => 3,
  192. 0 => 'foo=bar',
  193. 1 => 'bar=foo',
  194. 2 => 'dc=foobar'
  195. ),
  196. 'expectedResult' => true
  197. ],
  198. [
  199. 'input' => 'foobarbarfoodcfoobar',
  200. 'interResult' => false,
  201. 'expectedResult' => false
  202. ]
  203. ]];
  204. }
  205. /**
  206. * @dataProvider dnInputDataProvider
  207. * @param array $case
  208. */
  209. public function testStringResemblesDN($case) {
  210. list($lw, $con, $um, $helper) = $this->getConnectorAndLdapMock();
  211. /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject $config */
  212. $config = $this->createMock(IConfig::class);
  213. $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager);
  214. $lw->expects($this->exactly(1))
  215. ->method('explodeDN')
  216. ->will($this->returnCallback(function ($dn) use ($case) {
  217. if($dn === $case['input']) {
  218. return $case['interResult'];
  219. }
  220. return null;
  221. }));
  222. $this->assertSame($case['expectedResult'], $access->stringResemblesDN($case['input']));
  223. }
  224. /**
  225. * @dataProvider dnInputDataProvider
  226. * @param $case
  227. */
  228. public function testStringResemblesDNLDAPmod($case) {
  229. list(, $con, $um, $helper) = $this->getConnectorAndLdapMock();
  230. /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject $config */
  231. $config = $this->createMock(IConfig::class);
  232. $lw = new LDAP();
  233. $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager);
  234. if(!function_exists('ldap_explode_dn')) {
  235. $this->markTestSkipped('LDAP Module not available');
  236. }
  237. $this->assertSame($case['expectedResult'], $access->stringResemblesDN($case['input']));
  238. }
  239. public function testCacheUserHome() {
  240. $this->connection->expects($this->once())
  241. ->method('writeToCache');
  242. $this->access->cacheUserHome('foobar', '/foobars/path');
  243. }
  244. public function testBatchApplyUserAttributes() {
  245. $this->ldap->expects($this->any())
  246. ->method('isResource')
  247. ->willReturn(true);
  248. $this->ldap->expects($this->any())
  249. ->method('getAttributes')
  250. ->willReturn(['displayname' => ['bar', 'count' => 1]]);
  251. /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */
  252. $mapperMock = $this->createMock(UserMapping::class);
  253. $mapperMock->expects($this->any())
  254. ->method('getNameByDN')
  255. ->willReturn(false);
  256. $mapperMock->expects($this->any())
  257. ->method('map')
  258. ->willReturn(true);
  259. $userMock = $this->createMock(User::class);
  260. // also returns for userUuidAttribute
  261. $this->access->connection->expects($this->any())
  262. ->method('__get')
  263. ->will($this->returnValue('displayName'));
  264. $this->access->setUserMapper($mapperMock);
  265. $displayNameAttribute = strtolower($this->access->connection->ldapUserDisplayName);
  266. $data = [
  267. [
  268. 'dn' => ['foobar'],
  269. $displayNameAttribute => 'barfoo'
  270. ],
  271. [
  272. 'dn' => ['foo'],
  273. $displayNameAttribute => 'bar'
  274. ],
  275. [
  276. 'dn' => ['raboof'],
  277. $displayNameAttribute => 'oofrab'
  278. ]
  279. ];
  280. $userMock->expects($this->exactly(count($data)))
  281. ->method('processAttributes');
  282. $this->userManager->expects($this->exactly(count($data) * 2))
  283. ->method('get')
  284. ->will($this->returnValue($userMock));
  285. $this->access->batchApplyUserAttributes($data);
  286. }
  287. public function testBatchApplyUserAttributesSkipped() {
  288. /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */
  289. $mapperMock = $this->createMock(UserMapping::class);
  290. $mapperMock->expects($this->any())
  291. ->method('getNameByDN')
  292. ->will($this->returnValue('a_username'));
  293. $userMock = $this->createMock(User::class);
  294. $this->access->connection->expects($this->any())
  295. ->method('__get')
  296. ->will($this->returnValue('displayName'));
  297. $this->access->setUserMapper($mapperMock);
  298. $displayNameAttribute = strtolower($this->access->connection->ldapUserDisplayName);
  299. $data = [
  300. [
  301. 'dn' => ['foobar'],
  302. $displayNameAttribute => 'barfoo'
  303. ],
  304. [
  305. 'dn' => ['foo'],
  306. $displayNameAttribute => 'bar'
  307. ],
  308. [
  309. 'dn' => ['raboof'],
  310. $displayNameAttribute => 'oofrab'
  311. ]
  312. ];
  313. $userMock->expects($this->never())
  314. ->method('processAttributes');
  315. $this->userManager->expects($this->any())
  316. ->method('get')
  317. ->willReturn($this->createMock(User::class));
  318. $this->access->batchApplyUserAttributes($data);
  319. }
  320. public function testBatchApplyUserAttributesDontSkip() {
  321. /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */
  322. $mapperMock = $this->createMock(UserMapping::class);
  323. $mapperMock->expects($this->any())
  324. ->method('getNameByDN')
  325. ->will($this->returnValue('a_username'));
  326. $userMock = $this->createMock(User::class);
  327. $this->access->connection->expects($this->any())
  328. ->method('__get')
  329. ->will($this->returnValue('displayName'));
  330. $this->access->setUserMapper($mapperMock);
  331. $displayNameAttribute = strtolower($this->access->connection->ldapUserDisplayName);
  332. $data = [
  333. [
  334. 'dn' => ['foobar'],
  335. $displayNameAttribute => 'barfoo'
  336. ],
  337. [
  338. 'dn' => ['foo'],
  339. $displayNameAttribute => 'bar'
  340. ],
  341. [
  342. 'dn' => ['raboof'],
  343. $displayNameAttribute => 'oofrab'
  344. ]
  345. ];
  346. $userMock->expects($this->exactly(count($data)))
  347. ->method('processAttributes');
  348. $this->userManager->expects($this->exactly(count($data) * 2))
  349. ->method('get')
  350. ->will($this->returnValue($userMock));
  351. $this->access->batchApplyUserAttributes($data);
  352. }
  353. public function dNAttributeProvider() {
  354. // corresponds to Access::resemblesDN()
  355. return array(
  356. 'dn' => array('dn'),
  357. 'uniqueMember' => array('uniquemember'),
  358. 'member' => array('member'),
  359. 'memberOf' => array('memberof')
  360. );
  361. }
  362. /**
  363. * @dataProvider dNAttributeProvider
  364. * @param $attribute
  365. */
  366. public function testSanitizeDN($attribute) {
  367. list($lw, $con, $um, $helper) = $this->getConnectorAndLdapMock();
  368. /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject $config */
  369. $config = $this->createMock(IConfig::class);
  370. $dnFromServer = 'cn=Mixed Cases,ou=Are Sufficient To,ou=Test,dc=example,dc=org';
  371. $lw->expects($this->any())
  372. ->method('isResource')
  373. ->will($this->returnValue(true));
  374. $lw->expects($this->any())
  375. ->method('getAttributes')
  376. ->will($this->returnValue(array(
  377. $attribute => array('count' => 1, $dnFromServer)
  378. )));
  379. $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager);
  380. $values = $access->readAttribute('uid=whoever,dc=example,dc=org', $attribute);
  381. $this->assertSame($values[0], strtolower($dnFromServer));
  382. }
  383. /**
  384. * @expectedException \Exception
  385. * @expectedExceptionMessage LDAP password changes are disabled
  386. */
  387. public function testSetPasswordWithDisabledChanges() {
  388. $this->connection
  389. ->method('__get')
  390. ->willReturn(false);
  391. /** @noinspection PhpUnhandledExceptionInspection */
  392. $this->access->setPassword('CN=foo', 'MyPassword');
  393. }
  394. public function testSetPasswordWithLdapNotAvailable() {
  395. $this->connection
  396. ->method('__get')
  397. ->willReturn(true);
  398. $connection = $this->createMock(LDAP::class);
  399. $this->connection
  400. ->expects($this->once())
  401. ->method('getConnectionResource')
  402. ->willReturn($connection);
  403. $this->ldap
  404. ->expects($this->once())
  405. ->method('isResource')
  406. ->with($connection)
  407. ->willReturn(false);
  408. /** @noinspection PhpUnhandledExceptionInspection */
  409. $this->assertFalse($this->access->setPassword('CN=foo', 'MyPassword'));
  410. }
  411. /**
  412. * @expectedException \OC\HintException
  413. * @expectedExceptionMessage Password change rejected.
  414. */
  415. public function testSetPasswordWithRejectedChange() {
  416. $this->connection
  417. ->method('__get')
  418. ->willReturn(true);
  419. $connection = $this->createMock(LDAP::class);
  420. $this->connection
  421. ->expects($this->once())
  422. ->method('getConnectionResource')
  423. ->willReturn($connection);
  424. $this->ldap
  425. ->expects($this->once())
  426. ->method('isResource')
  427. ->with($connection)
  428. ->willReturn(true);
  429. $this->ldap
  430. ->expects($this->once())
  431. ->method('modReplace')
  432. ->with($connection, 'CN=foo', 'MyPassword')
  433. ->willThrowException(new ConstraintViolationException());
  434. /** @noinspection PhpUnhandledExceptionInspection */
  435. $this->access->setPassword('CN=foo', 'MyPassword');
  436. }
  437. public function testSetPassword() {
  438. $this->connection
  439. ->method('__get')
  440. ->willReturn(true);
  441. $connection = $this->createMock(LDAP::class);
  442. $this->connection
  443. ->expects($this->once())
  444. ->method('getConnectionResource')
  445. ->willReturn($connection);
  446. $this->ldap
  447. ->expects($this->once())
  448. ->method('isResource')
  449. ->with($connection)
  450. ->willReturn(true);
  451. $this->ldap
  452. ->expects($this->once())
  453. ->method('modReplace')
  454. ->with($connection, 'CN=foo', 'MyPassword')
  455. ->willReturn(true);
  456. /** @noinspection PhpUnhandledExceptionInspection */
  457. $this->assertTrue($this->access->setPassword('CN=foo', 'MyPassword'));
  458. }
  459. protected function prepareMocksForSearchTests(
  460. $base,
  461. $fakeConnection,
  462. $fakeSearchResultResource,
  463. $fakeLdapEntries
  464. ) {
  465. $this->connection
  466. ->expects($this->any())
  467. ->method('getConnectionResource')
  468. ->willReturn($fakeConnection);
  469. $this->connection->expects($this->any())
  470. ->method('__get')
  471. ->willReturnCallback(function($key) use ($base) {
  472. if(stripos($key, 'base') !== false) {
  473. return $base;
  474. }
  475. return null;
  476. });
  477. $this->ldap
  478. ->expects($this->any())
  479. ->method('isResource')
  480. ->willReturnCallback(function ($resource) use ($fakeConnection) {
  481. return $resource === $fakeConnection;
  482. });
  483. $this->ldap
  484. ->expects($this->any())
  485. ->method('errno')
  486. ->willReturn(0);
  487. $this->ldap
  488. ->expects($this->once())
  489. ->method('search')
  490. ->willReturn([$fakeSearchResultResource]);
  491. $this->ldap
  492. ->expects($this->exactly(count($base)))
  493. ->method('getEntries')
  494. ->willReturn($fakeLdapEntries);
  495. $this->helper->expects($this->any())
  496. ->method('sanitizeDN')
  497. ->willReturnArgument(0);
  498. }
  499. public function testSearchNoPagedSearch() {
  500. // scenario: no pages search, 1 search base
  501. $filter = 'objectClass=nextcloudUser';
  502. $base = ['ou=zombies,dc=foobar,dc=nextcloud,dc=com'];
  503. $fakeConnection = new \stdClass();
  504. $fakeSearchResultResource = new \stdClass();
  505. $fakeLdapEntries = [
  506. 'count' => 2,
  507. [
  508. 'dn' => 'uid=sgarth,' . $base[0],
  509. ],
  510. [
  511. 'dn' => 'uid=wwilson,' . $base[0],
  512. ]
  513. ];
  514. $expected = $fakeLdapEntries;
  515. unset($expected['count']);
  516. $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries);
  517. /** @noinspection PhpUnhandledExceptionInspection */
  518. $result = $this->access->search($filter, $base);
  519. $this->assertSame($expected, $result);
  520. }
  521. public function testFetchListOfUsers() {
  522. $filter = 'objectClass=nextcloudUser';
  523. $base = ['ou=zombies,dc=foobar,dc=nextcloud,dc=com'];
  524. $attrs = ['dn', 'uid'];
  525. $fakeConnection = new \stdClass();
  526. $fakeSearchResultResource = new \stdClass();
  527. $fakeLdapEntries = [
  528. 'count' => 2,
  529. [
  530. 'dn' => 'uid=sgarth,' . $base[0],
  531. 'uid' => [ 'sgarth' ],
  532. ],
  533. [
  534. 'dn' => 'uid=wwilson,' . $base[0],
  535. 'uid' => [ 'wwilson' ],
  536. ]
  537. ];
  538. $expected = $fakeLdapEntries;
  539. unset($expected['count']);
  540. array_walk($expected, function(&$v) {
  541. $v['dn'] = [$v['dn']]; // dn is translated into an array internally for consistency
  542. });
  543. $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries);
  544. $this->connection->expects($this->exactly($fakeLdapEntries['count']))
  545. ->method('writeToCache')
  546. ->with($this->stringStartsWith('userExists'), true);
  547. $this->userMapper->expects($this->exactly($fakeLdapEntries['count']))
  548. ->method('getNameByDN')
  549. ->willReturnCallback(function($fdn) {
  550. $parts = ldap_explode_dn($fdn, false);
  551. return $parts[0];
  552. });
  553. /** @noinspection PhpUnhandledExceptionInspection */
  554. $list = $this->access->fetchListOfUsers($filter, $attrs);
  555. $this->assertSame($expected, $list);
  556. }
  557. public function intUsernameProvider() {
  558. // system dependent :-/
  559. $translitExpected = @iconv('UTF-8', 'ASCII//TRANSLIT', 'fränk') ? 'frank' : 'frnk';
  560. return [
  561. ['alice', 'alice'],
  562. ['b/ob', 'bob'],
  563. ['charly🐬', 'charly'],
  564. ['debo rah', 'debo_rah'],
  565. ['epost@poste.test', 'epost@poste.test'],
  566. ['fränk', $translitExpected],
  567. [' gerda ', 'gerda'],
  568. ['🕱🐵🐘🐑', null]
  569. ];
  570. }
  571. /**
  572. * @dataProvider intUsernameProvider
  573. *
  574. * @param $name
  575. * @param $expected
  576. */
  577. public function testSanitizeUsername($name, $expected) {
  578. if($expected === null) {
  579. $this->expectException(\InvalidArgumentException::class);
  580. }
  581. $sanitizedName = $this->access->sanitizeUsername($name);
  582. $this->assertSame($expected, $sanitizedName);
  583. }
  584. public function testUserStateUpdate() {
  585. $this->connection->expects($this->any())
  586. ->method('__get')
  587. ->willReturnMap([
  588. [ 'ldapUserDisplayName', 'displayName' ],
  589. [ 'ldapUserDisplayName2', null],
  590. ]);
  591. $offlineUserMock = $this->createMock(OfflineUser::class);
  592. $offlineUserMock->expects($this->once())
  593. ->method('unmark');
  594. $regularUserMock = $this->createMock(User::class);
  595. $this->userManager->expects($this->atLeastOnce())
  596. ->method('get')
  597. ->with('detta')
  598. ->willReturnOnConsecutiveCalls($offlineUserMock, $regularUserMock);
  599. /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */
  600. $mapperMock = $this->createMock(UserMapping::class);
  601. $mapperMock->expects($this->any())
  602. ->method('getNameByDN')
  603. ->with('uid=detta,ou=users,dc=hex,dc=ample')
  604. ->willReturn('detta');
  605. $this->access->setUserMapper($mapperMock);
  606. $records = [
  607. [
  608. 'dn' => ['uid=detta,ou=users,dc=hex,dc=ample'],
  609. 'displayName' => ['Detta Detkova'],
  610. ]
  611. ];
  612. $this->access->nextcloudUserNames($records);
  613. }
  614. }