Group_LDAPTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Frédéric Fortier <frederic.fortier@oronospolytechnique.com>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Lukas Reschke <lukas@statuscode.ch>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Thomas Müller <thomas.mueller@tmit.eu>
  11. * @author Vincent Petry <pvince81@owncloud.com>
  12. *
  13. * @license AGPL-3.0
  14. *
  15. * This code is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License, version 3,
  17. * as published by the Free Software Foundation.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License, version 3,
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>
  26. *
  27. */
  28. namespace OCA\User_LDAP\Tests;
  29. use OCA\User_LDAP\Group_LDAP as GroupLDAP;
  30. use OCA\User_LDAP\ILDAPWrapper;
  31. /**
  32. * Class GroupLDAPTest
  33. *
  34. * @group DB
  35. *
  36. * @package OCA\User_LDAP\Tests
  37. */
  38. class Group_LDAPTest extends \Test\TestCase {
  39. private function getAccessMock() {
  40. static $conMethods;
  41. static $accMethods;
  42. if(is_null($conMethods) || is_null($accMethods)) {
  43. $conMethods = get_class_methods('\OCA\User_LDAP\Connection');
  44. $accMethods = get_class_methods('\OCA\User_LDAP\Access');
  45. }
  46. $lw = $this->createMock(ILDAPWrapper::class);
  47. $connector = $this->getMockBuilder('\OCA\User_LDAP\Connection')
  48. ->setMethods($conMethods)
  49. ->setConstructorArgs([$lw, null, null])
  50. ->getMock();
  51. $um = $this->getMockBuilder('\OCA\User_LDAP\User\Manager')
  52. ->disableOriginalConstructor()
  53. ->getMock();
  54. $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig());
  55. $access = $this->getMockBuilder('\OCA\User_LDAP\Access')
  56. ->setMethods($accMethods)
  57. ->setConstructorArgs([$connector, $lw, $um, $helper])
  58. ->getMock();
  59. $access->expects($this->any())
  60. ->method('getConnection')
  61. ->will($this->returnValue($connector));
  62. return $access;
  63. }
  64. private function enableGroups($access) {
  65. $access->connection->expects($this->any())
  66. ->method('__get')
  67. ->will($this->returnCallback(function($name) {
  68. if($name === 'ldapDynamicGroupMemberURL') {
  69. return '';
  70. }
  71. return 1;
  72. }));
  73. }
  74. public function testCountEmptySearchString() {
  75. $access = $this->getAccessMock();
  76. $this->enableGroups($access);
  77. $access->expects($this->any())
  78. ->method('groupname2dn')
  79. ->will($this->returnValue('cn=group,dc=foo,dc=bar'));
  80. $access->expects($this->any())
  81. ->method('readAttribute')
  82. ->will($this->returnValue(array('u11', 'u22', 'u33', 'u34')));
  83. // for primary groups
  84. $access->expects($this->once())
  85. ->method('countUsers')
  86. ->will($this->returnValue(2));
  87. $groupBackend = new GroupLDAP($access);
  88. $users = $groupBackend->countUsersInGroup('group');
  89. $this->assertSame(6, $users);
  90. }
  91. public function testCountWithSearchString() {
  92. $access = $this->getAccessMock();
  93. $this->enableGroups($access);
  94. $access->expects($this->any())
  95. ->method('groupname2dn')
  96. ->will($this->returnValue('cn=group,dc=foo,dc=bar'));
  97. $access->expects($this->any())
  98. ->method('fetchListOfUsers')
  99. ->will($this->returnValue(array()));
  100. $access->expects($this->any())
  101. ->method('readAttribute')
  102. ->will($this->returnCallback(function($name) {
  103. //the search operation will call readAttribute, thus we need
  104. //to anaylze the "dn". All other times we just need to return
  105. //something that is neither null or false, but once an array
  106. //with the users in the group – so we do so all other times for
  107. //simplicicity.
  108. if(strpos($name, 'u') === 0) {
  109. return strpos($name, '3');
  110. }
  111. return array('u11', 'u22', 'u33', 'u34');
  112. }));
  113. $access->expects($this->any())
  114. ->method('dn2username')
  115. ->will($this->returnCallback(function() {
  116. return 'foobar' . \OCP\Util::generateRandomBytes(7);
  117. }));
  118. $groupBackend = new GroupLDAP($access);
  119. $users = $groupBackend->countUsersInGroup('group', '3');
  120. $this->assertSame(2, $users);
  121. }
  122. public function testPrimaryGroupID2NameSuccess() {
  123. $access = $this->getAccessMock();
  124. $this->enableGroups($access);
  125. $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
  126. $access->expects($this->once())
  127. ->method('getSID')
  128. ->with($userDN)
  129. ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202'));
  130. $access->expects($this->once())
  131. ->method('searchGroups')
  132. ->will($this->returnValue([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]));
  133. $access->expects($this->once())
  134. ->method('dn2groupname')
  135. ->with('cn=foo,dc=barfoo,dc=bar')
  136. ->will($this->returnValue('MyGroup'));
  137. $groupBackend = new GroupLDAP($access);
  138. $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
  139. $this->assertSame('MyGroup', $group);
  140. }
  141. public function testPrimaryGroupID2NameNoSID() {
  142. $access = $this->getAccessMock();
  143. $this->enableGroups($access);
  144. $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
  145. $access->expects($this->once())
  146. ->method('getSID')
  147. ->with($userDN)
  148. ->will($this->returnValue(false));
  149. $access->expects($this->never())
  150. ->method('searchGroups');
  151. $access->expects($this->never())
  152. ->method('dn2groupname');
  153. $groupBackend = new GroupLDAP($access);
  154. $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
  155. $this->assertSame(false, $group);
  156. }
  157. public function testPrimaryGroupID2NameNoGroup() {
  158. $access = $this->getAccessMock();
  159. $this->enableGroups($access);
  160. $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
  161. $access->expects($this->once())
  162. ->method('getSID')
  163. ->with($userDN)
  164. ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202'));
  165. $access->expects($this->once())
  166. ->method('searchGroups')
  167. ->will($this->returnValue(array()));
  168. $access->expects($this->never())
  169. ->method('dn2groupname');
  170. $groupBackend = new GroupLDAP($access);
  171. $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
  172. $this->assertSame(false, $group);
  173. }
  174. public function testPrimaryGroupID2NameNoName() {
  175. $access = $this->getAccessMock();
  176. $this->enableGroups($access);
  177. $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar';
  178. $access->expects($this->once())
  179. ->method('getSID')
  180. ->with($userDN)
  181. ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202'));
  182. $access->expects($this->once())
  183. ->method('searchGroups')
  184. ->will($this->returnValue([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]));
  185. $access->expects($this->once())
  186. ->method('dn2groupname')
  187. ->will($this->returnValue(false));
  188. $groupBackend = new GroupLDAP($access);
  189. $group = $groupBackend->primaryGroupID2Name('3117', $userDN);
  190. $this->assertSame(false, $group);
  191. }
  192. public function testGetEntryGroupIDValue() {
  193. //tests getEntryGroupID via getGroupPrimaryGroupID
  194. //which is basically identical to getUserPrimaryGroupIDs
  195. $access = $this->getAccessMock();
  196. $this->enableGroups($access);
  197. $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
  198. $attr = 'primaryGroupToken';
  199. $access->expects($this->once())
  200. ->method('readAttribute')
  201. ->with($dn, $attr)
  202. ->will($this->returnValue(array('3117')));
  203. $groupBackend = new GroupLDAP($access);
  204. $gid = $groupBackend->getGroupPrimaryGroupID($dn);
  205. $this->assertSame('3117', $gid);
  206. }
  207. public function testGetEntryGroupIDNoValue() {
  208. //tests getEntryGroupID via getGroupPrimaryGroupID
  209. //which is basically identical to getUserPrimaryGroupIDs
  210. $access = $this->getAccessMock();
  211. $this->enableGroups($access);
  212. $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar';
  213. $attr = 'primaryGroupToken';
  214. $access->expects($this->once())
  215. ->method('readAttribute')
  216. ->with($dn, $attr)
  217. ->will($this->returnValue(false));
  218. $groupBackend = new GroupLDAP($access);
  219. $gid = $groupBackend->getGroupPrimaryGroupID($dn);
  220. $this->assertSame(false, $gid);
  221. }
  222. /**
  223. * tests whether Group Backend behaves correctly when cache with uid and gid
  224. * is hit
  225. */
  226. public function testInGroupHitsUidGidCache() {
  227. $access = $this->getAccessMock();
  228. $this->enableGroups($access);
  229. $uid = 'someUser';
  230. $gid = 'someGroup';
  231. $cacheKey = 'inGroup'.$uid.':'.$gid;
  232. $access->connection->expects($this->once())
  233. ->method('getFromCache')
  234. ->with($cacheKey)
  235. ->will($this->returnValue(true));
  236. $access->expects($this->never())
  237. ->method('username2dn');
  238. $groupBackend = new GroupLDAP($access);
  239. $groupBackend->inGroup($uid, $gid);
  240. }
  241. public function testGetGroupsWithOffset() {
  242. $access = $this->getAccessMock();
  243. $this->enableGroups($access);
  244. $access->expects($this->once())
  245. ->method('ownCloudGroupNames')
  246. ->will($this->returnValue(array('group1', 'group2')));
  247. $groupBackend = new GroupLDAP($access);
  248. $groups = $groupBackend->getGroups('', 2, 2);
  249. $this->assertSame(2, count($groups));
  250. }
  251. /**
  252. * tests that a user listing is complete, if all it's members have the group
  253. * as their primary.
  254. */
  255. public function testUsersInGroupPrimaryMembersOnly() {
  256. $access = $this->getAccessMock();
  257. $this->enableGroups($access);
  258. $access->connection->expects($this->any())
  259. ->method('getFromCache')
  260. ->will($this->returnValue(null));
  261. $access->expects($this->any())
  262. ->method('readAttribute')
  263. ->will($this->returnCallback(function($dn, $attr) {
  264. if($attr === 'primaryGroupToken') {
  265. return array(1337);
  266. }
  267. return array();
  268. }));
  269. $access->expects($this->any())
  270. ->method('groupname2dn')
  271. ->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
  272. $access->expects($this->once())
  273. ->method('ownCloudUserNames')
  274. ->will($this->returnValue(array('lisa', 'bart', 'kira', 'brad')));
  275. $groupBackend = new GroupLDAP($access);
  276. $users = $groupBackend->usersInGroup('foobar');
  277. $this->assertSame(4, count($users));
  278. }
  279. /**
  280. * tests that a user counting is complete, if all it's members have the group
  281. * as their primary.
  282. */
  283. public function testCountUsersInGroupPrimaryMembersOnly() {
  284. $access = $this->getAccessMock();
  285. $this->enableGroups($access);
  286. $access->connection->expects($this->any())
  287. ->method('getFromCache')
  288. ->will($this->returnValue(null));
  289. $access->expects($this->any())
  290. ->method('readAttribute')
  291. ->will($this->returnCallback(function($dn, $attr) {
  292. if($attr === 'primaryGroupToken') {
  293. return array(1337);
  294. }
  295. return array();
  296. }));
  297. $access->expects($this->any())
  298. ->method('groupname2dn')
  299. ->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
  300. $access->expects($this->once())
  301. ->method('countUsers')
  302. ->will($this->returnValue(4));
  303. $groupBackend = new GroupLDAP($access);
  304. $users = $groupBackend->countUsersInGroup('foobar');
  305. $this->assertSame(4, $users);
  306. }
  307. public function testGetUserGroupsMemberOf() {
  308. $access = $this->getAccessMock();
  309. $this->enableGroups($access);
  310. $dn = 'cn=userX,dc=foobar';
  311. $access->connection->hasPrimaryGroups = false;
  312. $access->expects($this->any())
  313. ->method('username2dn')
  314. ->will($this->returnValue($dn));
  315. $access->expects($this->exactly(3))
  316. ->method('readAttribute')
  317. ->will($this->onConsecutiveCalls(['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar'], [], []));
  318. $access->expects($this->exactly(2))
  319. ->method('dn2groupname')
  320. ->will($this->returnArgument(0));
  321. $access->expects($this->exactly(3))
  322. ->method('groupsMatchFilter')
  323. ->will($this->returnArgument(0));
  324. $groupBackend = new GroupLDAP($access);
  325. $groups = $groupBackend->getUserGroups('userX');
  326. $this->assertSame(2, count($groups));
  327. }
  328. public function testGetUserGroupsMemberOfDisabled() {
  329. $access = $this->getAccessMock();
  330. $access->connection->expects($this->any())
  331. ->method('__get')
  332. ->will($this->returnCallback(function($name) {
  333. if($name === 'useMemberOfToDetectMembership') {
  334. return 0;
  335. } else if($name === 'ldapDynamicGroupMemberURL') {
  336. return '';
  337. }
  338. return 1;
  339. }));
  340. $dn = 'cn=userX,dc=foobar';
  341. $access->connection->hasPrimaryGroups = false;
  342. $access->expects($this->once())
  343. ->method('username2dn')
  344. ->will($this->returnValue($dn));
  345. $access->expects($this->never())
  346. ->method('readAttribute')
  347. ->with($dn, 'memberOf');
  348. $access->expects($this->once())
  349. ->method('ownCloudGroupNames')
  350. ->will($this->returnValue([]));
  351. $groupBackend = new GroupLDAP($access);
  352. $groupBackend->getUserGroups('userX');
  353. }
  354. public function testGetGroupsByMember() {
  355. $access = $this->getAccessMock();
  356. $access->connection->expects($this->any())
  357. ->method('__get')
  358. ->will($this->returnCallback(function($name) {
  359. if($name === 'useMemberOfToDetectMembership') {
  360. return 0;
  361. } else if($name === 'ldapDynamicGroupMemberURL') {
  362. return '';
  363. } else if($name === 'ldapNestedGroups') {
  364. return false;
  365. }
  366. return 1;
  367. }));
  368. $dn = 'cn=userX,dc=foobar';
  369. $access->connection->hasPrimaryGroups = false;
  370. $access->expects($this->exactly(2))
  371. ->method('username2dn')
  372. ->will($this->returnValue($dn));
  373. $access->expects($this->never())
  374. ->method('readAttribute')
  375. ->with($dn, 'memberOf');
  376. $group1 = [
  377. 'cn' => 'group1',
  378. 'dn' => ['cn=group1,ou=groups,dc=domain,dc=com'],
  379. ];
  380. $group2 = [
  381. 'cn' => 'group2',
  382. 'dn' => ['cn=group2,ou=groups,dc=domain,dc=com'],
  383. ];
  384. $access->expects($this->once())
  385. ->method('ownCloudGroupNames')
  386. ->with([$group1, $group2])
  387. ->will($this->returnValue(['group1', 'group2']));
  388. $access->expects($this->once())
  389. ->method('fetchListOfGroups')
  390. ->will($this->returnValue([$group1, $group2]));
  391. $groupBackend = new GroupLDAP($access);
  392. $groups = $groupBackend->getUserGroups('userX');
  393. $this->assertEquals(['group1', 'group2'], $groups);
  394. $groupsAgain = $groupBackend->getUserGroups('userX');
  395. $this->assertEquals(['group1', 'group2'], $groupsAgain);
  396. }
  397. }