diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 6700890c8c7cf..243cca99841c8 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -288,6 +288,10 @@ public function getFromCache($key) { return json_decode(base64_decode($this->cache->get($key) ?? ''), true); } + public function getConfigPrefix(): string { + return $this->configPrefix; + } + /** * @param string $key * @param mixed $value diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index b32e031175ff9..b2bdd09ef9f44 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -45,12 +45,17 @@ namespace OCA\User_LDAP; use Exception; +use OCA\User_LDAP\User\OfflineUser; use OCP\Cache\CappedMemoryCache; use OCP\GroupInterface; use OCP\Group\Backend\IDeleteGroupBackend; use OCP\Group\Backend\IGetDisplayNameBackend; use OC\ServerNotAvailableException; +use OCP\IConfig; +use OCP\IUserManager; +use OCP\Server; use Psr\Log\LoggerInterface; +use function json_decode; class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, IGetDisplayNameBackend, IDeleteGroupBackend { protected bool $enabled = false; @@ -68,8 +73,15 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I * @var string $ldapGroupMemberAssocAttr contains the LDAP setting (in lower case) with the same name */ protected string $ldapGroupMemberAssocAttr; - - public function __construct(Access $access, GroupPluginManager $groupPluginManager) { + private IConfig $config; + private IUserManager $ncUserManager; + + public function __construct( + Access $access, + GroupPluginManager $groupPluginManager, + IConfig $config, + IUserManager $ncUserManager + ) { parent::__construct($access); $filter = $this->access->connection->ldapGroupFilter; $gAssoc = $this->access->connection->ldapGroupMemberAssocAttr; @@ -81,8 +93,10 @@ public function __construct(Access $access, GroupPluginManager $groupPluginManag $this->cachedGroupsByMember = new CappedMemoryCache(); $this->cachedNestedGroups = new CappedMemoryCache(); $this->groupPluginManager = $groupPluginManager; - $this->logger = \OCP\Server::get(LoggerInterface::class); + $this->logger = Server::get(LoggerInterface::class); $this->ldapGroupMemberAssocAttr = strtolower((string)$gAssoc); + $this->config = $config; + $this->ncUserManager = $ncUserManager; } /** @@ -437,6 +451,7 @@ public function getGroupGidNumber(string $dn) { public function getUserGidNumber(string $dn) { $gidNumber = false; if ($this->access->connection->hasGidNumber) { + // FIXME: when $dn does not exist on LDAP anymore, this will be set wrongly to false :/ $gidNumber = $this->getEntryGidNumber($dn, $this->access->connection->ldapGidNumber); if ($gidNumber === false) { $this->access->connection->hasGidNumber = false; @@ -650,6 +665,25 @@ public function getUserPrimaryGroup(string $dn) { return false; } + private function isUserOnLDAP(string $uid): bool { + // forces a user exists check - but does not help if a positive result is cached, while group info is not + $ncUser = $this->ncUserManager->get($uid); + if ($ncUser === null) { + return false; + } + $backend = $ncUser->getBackend(); + if ($backend instanceof User_Proxy) { + // ignoring cache as safeguard (and we are behind the group cache check anyway) + return $backend->userExistsOnLDAP($uid, true); + } + return false; + } + + protected function getCachedGroupsForUserId(string $uid): array { + $groupStr = $this->config->getUserValue($uid, 'user_ldap', 'cached-group-memberships-' . $this->access->connection->getConfigPrefix(), '[]'); + return json_decode($groupStr) ?? []; + } + /** * This function fetches all groups a user belongs to. It does not check * if the user exists at all. @@ -661,15 +695,25 @@ public function getUserPrimaryGroup(string $dn) { * @throws Exception * @throws ServerNotAvailableException */ - public function getUserGroups($uid) { + public function getUserGroups($uid): array { if (!$this->enabled) { return []; } + $ncUid = $uid; + $cacheKey = 'getUserGroups' . $uid; $userGroups = $this->access->connection->getFromCache($cacheKey); if (!is_null($userGroups)) { return $userGroups; } + + $user = $this->access->userManager->get($uid); + if ($user instanceof OfflineUser) { + // We load known group memberships from configuration for remnants, + // because LDAP server does not contain them anymore + return $this->getCachedGroupsForUserId($uid); + } + $userDN = $this->access->username2dn($uid); if (!$userDN) { $this->access->connection->writeToCache($cacheKey, []); @@ -781,9 +825,21 @@ public function getUserGroups($uid) { $groups[] = $gidGroupName; } + if (empty($groups) && !$this->isUserOnLDAP($ncUid)) { + // Groups are enabled, but you user has none? Potentially suspicious: + // it could be that the user was deleted from LDAP, but we are not + // aware of it yet. + $groups = $this->getCachedGroupsForUserId($ncUid); + $this->access->connection->writeToCache($cacheKey, $groups); + return $groups; + } + $groups = array_unique($groups, SORT_LOCALE_STRING); $this->access->connection->writeToCache($cacheKey, $groups); + $groupStr = \json_encode($groups); + $this->config->setUserValue($ncUid, 'user_ldap', 'cached-group-memberships-' . $this->access->connection->getConfigPrefix(), $groupStr); + return $groups; } diff --git a/apps/user_ldap/lib/Group_Proxy.php b/apps/user_ldap/lib/Group_Proxy.php index c8c986318ec7e..f96feb7b023e4 100644 --- a/apps/user_ldap/lib/Group_Proxy.php +++ b/apps/user_ldap/lib/Group_Proxy.php @@ -31,6 +31,9 @@ use OCP\Group\Backend\IDeleteGroupBackend; use OCP\Group\Backend\IGetDisplayNameBackend; use OCP\Group\Backend\INamedBackend; +use OCP\GroupInterface; +use OCP\IConfig; +use OCP\IUserManager; class Group_Proxy extends Proxy implements \OCP\GroupInterface, IGroupLDAP, IGetDisplayNameBackend, INamedBackend, IDeleteGroupBackend { private $backends = []; @@ -38,16 +41,22 @@ class Group_Proxy extends Proxy implements \OCP\GroupInterface, IGroupLDAP, IGet private Helper $helper; private GroupPluginManager $groupPluginManager; private bool $isSetUp = false; + private IConfig $config; + private IUserManager $ncUserManager; public function __construct( Helper $helper, ILDAPWrapper $ldap, AccessFactory $accessFactory, - GroupPluginManager $groupPluginManager + GroupPluginManager $groupPluginManager, + IConfig $config, + IUserManager $ncUserManager, ) { parent::__construct($ldap, $accessFactory); $this->helper = $helper; $this->groupPluginManager = $groupPluginManager; + $this->config = $config; + $this->ncUserManager = $ncUserManager; } protected function setup(): void { @@ -58,7 +67,7 @@ protected function setup(): void { $serverConfigPrefixes = $this->helper->getServerConfigurationPrefixes(true); foreach ($serverConfigPrefixes as $configPrefix) { $this->backends[$configPrefix] = - new Group_LDAP($this->getAccess($configPrefix), $this->groupPluginManager); + new Group_LDAP($this->getAccess($configPrefix), $this->groupPluginManager, $this->config, $this->ncUserManager); if (is_null($this->refBackend)) { $this->refBackend = &$this->backends[$configPrefix]; } diff --git a/apps/user_ldap/tests/Group_LDAPTest.php b/apps/user_ldap/tests/Group_LDAPTest.php index edcb4be881997..8d6c4539cec80 100644 --- a/apps/user_ldap/tests/Group_LDAPTest.php +++ b/apps/user_ldap/tests/Group_LDAPTest.php @@ -37,7 +37,13 @@ use OCA\User_LDAP\ILDAPWrapper; use OCA\User_LDAP\Mapping\GroupMapping; use OCA\User_LDAP\User\Manager; +use OCA\User_LDAP\User\OfflineUser; +use OCA\User_LDAP\User\User; +use OCA\User_LDAP\User_Proxy; use OCP\GroupInterface; +use OCP\IConfig; +use OCP\IUser; +use OCP\IUserManager; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; @@ -49,17 +55,34 @@ * @package OCA\User_LDAP\Tests */ class Group_LDAPTest extends TestCase { + private MockObject|Access $access; + private MockObject|GroupPluginManager $pluginManager; + private MockObject|IConfig $config; + private MockObject|IUserManager $ncUserManager; + private GroupLDAP $groupBackend; + + public function setUp(): void { + parent::setUp(); + + $this->access = $this->getAccessMock(); + $this->pluginManager = $this->createMock(GroupPluginManager::class); + $this->config = $this->createMock(IConfig::class); + $this->ncUserManager = $this->createMock(IUserManager::class); + } + + public function initBackend(): void { + $this->groupBackend = new GroupLDAP($this->access, $this->pluginManager, $this->config, $this->ncUserManager); + } + public function testCountEmptySearchString() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); $groupDN = 'cn=group,dc=foo,dc=bar'; - $this->enableGroups($access); + $this->enableGroups(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturn($groupDN); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturnCallback(function ($dn) use ($groupDN) { if ($dn === $groupDN) { @@ -72,20 +95,20 @@ public function testCountEmptySearchString() { } return []; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); // for primary groups - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('countUsers') ->willReturn(2); - $access->userManager->expects($this->any()) + $this->access->userManager->expects($this->any()) ->method('getAttributes') ->willReturn(['displayName', 'mail']); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('group'); + $this->initBackend(); + $users = $this->groupBackend->countUsersInGroup('group'); $this->assertSame(6, $users); } @@ -102,31 +125,23 @@ private function getAccessMock() { $accMethods = get_class_methods(Access::class); } $lw = $this->createMock(ILDAPWrapper::class); + $connector = $this->getMockBuilder(Connection::class) ->setMethods($conMethods) ->setConstructorArgs([$lw, '', null]) ->getMock(); - $access = $this->createMock(Access::class); - - $access->connection = $connector; + $this->access = $this->createMock(Access::class); - $access->userManager = $this->createMock(Manager::class); + $this->access->connection = $connector; - return $access; - } + $this->access->userManager = $this->createMock(Manager::class); - /** - * @return MockObject|GroupPluginManager - */ - private function getPluginManagerMock() { - return $this->createMock(GroupPluginManager::class); + return $this->access; } - private function enableGroups(Access $access) { - $access->connection = $this->createMock(Connection::class); - - $access->connection->expects($this->any()) + private function enableGroups() { + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($name) { if ($name === 'ldapDynamicGroupMemberURL') { @@ -139,18 +154,15 @@ private function enableGroups(Access $access) { } public function testCountWithSearchString() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturn('cn=group,dc=foo,dc=bar'); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('fetchListOfUsers') ->willReturn([]); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturnCallback(function ($name) { //the search operation will call readAttribute, thus we need @@ -163,301 +175,257 @@ public function testCountWithSearchString() { } return ['u11', 'u22', 'u33', 'u34']; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('dn2username') ->willReturnCallback(function () { return 'foobar' . \OC::$server->getSecureRandom()->generate(7); }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('escapeFilterPart') ->willReturnArgument(0); - $access->userManager->expects($this->any()) + $this->access->userManager->expects($this->any()) ->method('getAttributes') ->willReturn(['displayName', 'mail']); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('group', '3'); + $this->initBackend(); + $users = $this->groupBackend->countUsersInGroup('group', '3'); $this->assertSame(2, $users); } public function testCountUsersWithPlugin() { /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'countUsersInGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::COUNT_USERS) ->willReturn(true); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('countUsersInGroup') ->with('gid', 'search') ->willReturn(42); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->countUsersInGroup('gid', 'search'), 42); + $this->initBackend(); + $this->assertEquals($this->groupBackend->countUsersInGroup('gid', 'search'), 42); } public function testGidNumber2NameSuccess() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2groupname') ->with('cn=foo,dc=barfoo,dc=bar') ->willReturn('MyGroup'); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->gidNumber2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->gidNumber2Name('3117', $userDN); $this->assertSame('MyGroup', $group); } public function testGidNumberID2NameNoGroup() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') ->willReturn([]); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2groupname'); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->gidNumber2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->gidNumber2Name('3117', $userDN); $this->assertSame(false, $group); } public function testGidNumberID2NameNoName() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2groupname') ->willReturn(false); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->gidNumber2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->gidNumber2Name('3117', $userDN); $this->assertSame(false, $group); } public function testGetEntryGidNumberValue() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $attr = 'gidNumber'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('readAttribute') ->with($dn, $attr) ->willReturn(['3117']); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupGidNumber($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupGidNumber($dn); $this->assertSame('3117', $gid); } public function testGetEntryGidNumberNoValue() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $attr = 'gidNumber'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('readAttribute') ->with($dn, $attr) ->willReturn(false); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupGidNumber($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupGidNumber($dn); $this->assertSame(false, $gid); } public function testPrimaryGroupID2NameSuccessCache() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; $gid = '3117'; - $groupDN = 'cn=foo,dc=barfoo,dc=bar'; /** @var MockObject $connection */ - $connection = $access->connection; + $connection = $this->access->connection; $connection->expects($this->once()) ->method('getFromCache') ->with('primaryGroupIDtoName_' . $gid) ->willReturn('MyGroup'); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('getSID'); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('searchGroups'); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2groupname'); - $groupBackend = new GroupLDAP($access, $pluginManager); - $group = $groupBackend->primaryGroupID2Name($gid, $userDN); + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name($gid, $userDN); $this->assertSame('MyGroup', $group); } public function testPrimaryGroupID2NameSuccess() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2groupname') ->with('cn=foo,dc=barfoo,dc=bar') ->willReturn('MyGroup'); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN); $this->assertSame('MyGroup', $group); } public function testPrimaryGroupID2NameNoSID() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) ->willReturn(false); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('searchGroups'); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2groupname'); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN); $this->assertSame(false, $group); } public function testPrimaryGroupID2NameNoGroup() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') ->willReturn([]); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2groupname'); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN); $this->assertSame(false, $group); } public function testPrimaryGroupID2NameNoName() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2groupname') ->willReturn(false); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN); $this->assertSame(false, $group); } @@ -465,22 +433,18 @@ public function testPrimaryGroupID2NameNoName() { public function testGetEntryGroupIDValue() { //tests getEntryGroupID via getGroupPrimaryGroupID //which is basically identical to getUserPrimaryGroupIDs - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $attr = 'primaryGroupToken'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('readAttribute') ->with($dn, $attr) ->willReturn(['3117']); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupPrimaryGroupID($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupPrimaryGroupID($dn); $this->assertSame('3117', $gid); } @@ -488,22 +452,18 @@ public function testGetEntryGroupIDValue() { public function testGetEntryGroupIDNoValue() { //tests getEntryGroupID via getGroupPrimaryGroupID //which is basically identical to getUserPrimaryGroupIDs - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; $attr = 'primaryGroupToken'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('readAttribute') ->with($dn, $attr) ->willReturn(false); - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupPrimaryGroupID($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupPrimaryGroupID($dn); $this->assertSame(false, $gid); } @@ -513,25 +473,22 @@ public function testGetEntryGroupIDNoValue() { * is hit */ public function testInGroupHitsUidGidCache() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $uid = 'someUser'; $gid = 'someGroup'; $cacheKey = 'inGroup' . $uid . ':' . $gid; - $access->connection->expects($this->once()) + $this->access->connection->expects($this->once()) ->method('getFromCache') ->with($cacheKey) ->willReturn(true); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('username2dn'); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groupBackend->inGroup($uid, $gid); + $this->initBackend(); + $this->groupBackend->inGroup($uid, $gid); } public function groupWithMembersProvider() { @@ -553,15 +510,10 @@ public function groupWithMembersProvider() { * @dataProvider groupWithMembersProvider */ public function testInGroupMember(string $gid, string $groupDn, array $memberDNs) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $access->connection = $this->createMock(Connection::class); - $uid = 'someUser'; $userDn = $memberDNs[0]; - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($name) { switch ($name) { @@ -576,38 +528,33 @@ public function testInGroupMember(string $gid, string $groupDn, array $memberDNs return 1; } }); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') ->willReturn(null); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->with($uid) ->willReturn($userDn); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('groupname2dn') ->willReturn($groupDn); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturn($memberDNs); - $groupBackend = new GroupLDAP($access, $pluginManager); - $this->assertTrue($groupBackend->inGroup($uid, $gid)); + $this->initBackend(); + $this->assertTrue($this->groupBackend->inGroup($uid, $gid)); } /** * @dataProvider groupWithMembersProvider */ public function testInGroupMemberNot(string $gid, string $groupDn, array $memberDNs) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $access->connection = $this->createMock(Connection::class); - $uid = 'unelatedUser'; $userDn = 'uid=unrelatedUser,ou=unrelatedTeam,ou=unrelatedDepartment,dc=someDomain,dc=someTld'; - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($name) { switch ($name) { @@ -622,32 +569,29 @@ public function testInGroupMemberNot(string $gid, string $groupDn, array $member return 1; } }); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') ->willReturn(null); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->with($uid) ->willReturn($userDn); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('groupname2dn') ->willReturn($groupDn); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturn($memberDNs); - $groupBackend = new GroupLDAP($access, $pluginManager); - $this->assertFalse($groupBackend->inGroup($uid, $gid)); + $this->initBackend(); + $this->assertFalse($this->groupBackend->inGroup($uid, $gid)); } /** * @dataProvider groupWithMembersProvider */ public function testInGroupMemberUid(string $gid, string $groupDn, array $memberDNs) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - $memberUids = []; $userRecords = []; foreach ($memberDNs as $dn) { @@ -655,13 +599,10 @@ public function testInGroupMemberUid(string $gid, string $groupDn, array $member $userRecords[] = ['dn' => [$dn]]; } - - $access->connection = $this->createMock(Connection::class); - $uid = 'someUser'; $userDn = $memberDNs[0]; - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($name) { switch ($name) { @@ -678,47 +619,44 @@ public function testInGroupMemberUid(string $gid, string $groupDn, array $member return 1; } }); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') ->willReturn(null); - $access->userManager->expects($this->any()) + $this->access->userManager->expects($this->any()) ->method('getAttributes') ->willReturn(['uid', 'mail', 'displayname']); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->with($uid) ->willReturn($userDn); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('groupname2dn') ->willReturn($groupDn); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturn($memberUids); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('fetchListOfUsers') ->willReturn($userRecords); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('combineFilterWithOr') ->willReturn('(|(pseudo=filter)(filter=pseudo))'); - $groupBackend = new GroupLDAP($access, $pluginManager); - $this->assertTrue($groupBackend->inGroup($uid, $gid)); + $this->initBackend(); + $this->assertTrue($this->groupBackend->inGroup($uid, $gid)); } public function testGetGroupsWithOffset() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + $this->enableGroups(); - $this->enableGroups($access); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('nextcloudGroupNames') ->willReturn(['group1', 'group2']); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getGroups('', 2, 2); + $this->initBackend(); + $groups = $this->groupBackend->getGroups('', 2, 2); $this->assertSame(2, count($groups)); } @@ -728,15 +666,12 @@ public function testGetGroupsWithOffset() { * as their primary. */ public function testUsersInGroupPrimaryMembersOnly() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') ->willReturn(null); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturnCallback(function ($dn, $attr) { if ($attr === 'primaryGroupToken') { @@ -746,25 +681,25 @@ public function testUsersInGroupPrimaryMembersOnly() { } return []; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturn('cn=foobar,dc=foo,dc=bar'); - $access->expects($this->exactly(2)) + $this->access->expects($this->exactly(2)) ->method('nextcloudUserNames') ->willReturnOnConsecutiveCalls(['lisa', 'bart', 'kira', 'brad'], ['walle', 'dino', 'xenia']); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('combineFilterWithAnd') ->willReturn('pseudo=filter'); - $access->userManager->expects($this->any()) + $this->access->userManager->expects($this->any()) ->method('getAttributes') ->willReturn(['displayName', 'mail']); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->usersInGroup('foobar'); + $this->initBackend(); + $users = $this->groupBackend->usersInGroup('foobar'); $this->assertSame(7, count($users)); } @@ -774,15 +709,12 @@ public function testUsersInGroupPrimaryMembersOnly() { * as their primary. */ public function testUsersInGroupPrimaryAndUnixMembers() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + $this->enableGroups(); - $this->enableGroups($access); - - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') ->willReturn(null); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturnCallback(function ($dn, $attr) { if ($attr === 'primaryGroupToken') { @@ -790,25 +722,25 @@ public function testUsersInGroupPrimaryAndUnixMembers() { } return []; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturn('cn=foobar,dc=foo,dc=bar'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('nextcloudUserNames') ->willReturn(['lisa', 'bart', 'kira', 'brad']); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('combineFilterWithAnd') ->willReturn('pseudo=filter'); - $access->userManager->expects($this->any()) + $this->access->userManager->expects($this->any()) ->method('getAttributes') ->willReturn(['displayName', 'mail']); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->usersInGroup('foobar'); + $this->initBackend(); + $users = $this->groupBackend->usersInGroup('foobar'); $this->assertSame(4, count($users)); } @@ -818,16 +750,13 @@ public function testUsersInGroupPrimaryAndUnixMembers() { * as their primary. */ public function testCountUsersInGroupPrimaryMembersOnly() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') ->willReturn(null); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturnCallback(function ($dn, $attr) { if ($attr === 'primaryGroupToken') { @@ -835,65 +764,64 @@ public function testCountUsersInGroupPrimaryMembersOnly() { } return []; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturn('cn=foobar,dc=foo,dc=bar'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('countUsers') ->willReturn(4); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); - $access->userManager->expects($this->any()) + $this->access->userManager->expects($this->any()) ->method('getAttributes') ->willReturn(['displayName', 'mail']); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('foobar'); + $this->initBackend(); + $users = $this->groupBackend->countUsersInGroup('foobar'); $this->assertSame(4, $users); } public function testGetUserGroupsMemberOf() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + $this->enableGroups(); $dn = 'cn=userX,dc=foobar'; - $access->connection->hasPrimaryGroups = false; - $access->connection->hasGidNumber = false; + $this->access->connection->hasPrimaryGroups = false; + $this->access->connection->hasGidNumber = false; - $access->expects($this->any()) + $expectedGroups = ['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar']; + + $this->access->expects($this->any()) ->method('username2dn') ->willReturn($dn); - $access->expects($this->exactly(5)) + $this->access->expects($this->exactly(5)) ->method('readAttribute') - ->will($this->onConsecutiveCalls(['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar'], [], [], [], [])); - $access->expects($this->any()) + ->will($this->onConsecutiveCalls($expectedGroups, [], [], [], [])); + $this->access->expects($this->any()) ->method('dn2groupname') ->willReturnArgument(0); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturnArgument(0); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getUserGroups('userX'); + $this->config->expects($this->once()) + ->method('setUserValue') + ->with('userX', 'user_ldap', 'cached-group-memberships-', \json_encode($expectedGroups)); + + $this->initBackend(); + $groups = $this->groupBackend->getUserGroups('userX'); $this->assertSame(2, count($groups)); } public function testGetUserGroupsMemberOfDisabled() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($name) { if ($name === 'useMemberOfToDetectMembership') { @@ -906,21 +834,114 @@ public function testGetUserGroupsMemberOfDisabled() { $dn = 'cn=userX,dc=foobar'; - $access->connection->hasPrimaryGroups = false; - $access->connection->hasGidNumber = false; + $this->access->connection->hasPrimaryGroups = false; + $this->access->connection->hasGidNumber = false; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->willReturn($dn); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('readAttribute') ->with($dn, 'memberOf'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('nextcloudGroupNames') ->willReturn([]); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groupBackend->getUserGroups('userX'); + // empty group result should not be oer + $this->config->expects($this->once()) + ->method('setUserValue') + ->with('userX', 'user_ldap', 'cached-group-memberships-', '[]'); + + $ldapUser = $this->createMock(User::class); + + $this->access->userManager->expects($this->any()) + ->method('get') + ->with('userX') + ->willReturn($ldapUser); + + $userBackend = $this->createMock(User_Proxy::class); + $userBackend->expects($this->once()) + ->method('userExistsOnLDAP') + ->with('userX', true) + ->willReturn(true); + + $ncUser = $this->createMock(IUser::class); + $ncUser->expects($this->any()) + ->method('getBackend') + ->willReturn($userBackend); + + $this->ncUserManager->expects($this->once()) + ->method('get') + ->with('userX') + ->willReturn($ncUser); + + $this->initBackend(); + $this->groupBackend->getUserGroups('userX'); + } + + public function testGetUserGroupsOfflineUser() { + $this->enableGroups(); + + $offlineUser = $this->createMock(OfflineUser::class); + + $this->config->expects($this->any()) + ->method('getUserValue') + ->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything()) + ->willReturn(\json_encode(['groupB', 'groupF'])); + + $this->access->userManager->expects($this->any()) + ->method('get') + ->with('userX') + ->willReturn($offlineUser); + + $this->initBackend(); + $returnedGroups = $this->groupBackend->getUserGroups('userX'); + $this->assertCount(2, $returnedGroups); + $this->assertTrue(in_array('groupB', $returnedGroups)); + $this->assertTrue(in_array('groupF', $returnedGroups)); + } + + public function testGetUserGroupsUnrecognizedOfflineUser() { + $this->enableGroups(); + $dn = 'cn=userX,dc=foobar'; + + $ldapUser = $this->createMock(User::class); + + $userBackend = $this->createMock(User_Proxy::class); + $userBackend->expects($this->once()) + ->method('userExistsOnLDAP') + ->with('userX', true) + ->willReturn(false); + + $ncUser = $this->createMock(IUser::class); + $ncUser->expects($this->any()) + ->method('getBackend') + ->willReturn($userBackend); + + $this->config->expects($this->atLeastOnce()) + ->method('getUserValue') + ->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything()) + ->willReturn(\json_encode(['groupB', 'groupF'])); + + $this->access->expects($this->any()) + ->method('username2dn') + ->willReturn($dn); + + $this->access->userManager->expects($this->any()) + ->method('get') + ->with('userX') + ->willReturn($ldapUser); + + $this->ncUserManager->expects($this->once()) + ->method('get') + ->with('userX') + ->willReturn($ncUser); + + $this->initBackend(); + $returnedGroups = $this->groupBackend->getUserGroups('userX'); + $this->assertCount(2, $returnedGroups); + $this->assertTrue(in_array('groupB', $returnedGroups)); + $this->assertTrue(in_array('groupF', $returnedGroups)); } public function nestedGroupsProvider(): array { @@ -934,12 +955,8 @@ public function nestedGroupsProvider(): array { * @dataProvider nestedGroupsProvider */ public function testGetGroupsByMember(bool $nestedGroups) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - $groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))'; - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function (string $name) use ($nestedGroups, $groupFilter) { switch ($name) { @@ -963,16 +980,16 @@ public function testGetGroupsByMember(bool $nestedGroups) { $dn = 'cn=userX,dc=foobar'; - $access->connection->hasPrimaryGroups = false; - $access->connection->hasGidNumber = false; + $this->access->connection->hasPrimaryGroups = false; + $this->access->connection->hasGidNumber = false; - $access->expects($this->exactly(2)) + $this->access->expects($this->exactly(2)) ->method('username2dn') ->willReturn($dn); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturn([]); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('combineFilterWithAnd') ->willReturnCallback(function (array $filterParts) { // ⚠ returns a pseudo-filter only, not real LDAP Filter syntax @@ -998,11 +1015,11 @@ public function testGetGroupsByMember(bool $nestedGroups) { $expectedGroups = ($nestedGroups ? [$group1, $group2, $group3] : [$group1, $group2]); $expectedGroupsNames = ($nestedGroups ? ['group1', 'group2', 'group3'] : ['group1', 'group2']); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('nextcloudGroupNames') ->with($expectedGroups) ->willReturn($expectedGroupsNames); - $access->expects($nestedGroups ? $this->atLeastOnce() : $this->once()) + $this->access->expects($nestedGroups ? $this->atLeastOnce() : $this->once()) ->method('fetchListOfGroups') ->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2, $group3, $dn) { static $firstRun = true; @@ -1021,12 +1038,12 @@ public function testGetGroupsByMember(bool $nestedGroups) { return []; } }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('dn2groupname') ->willReturnCallback(function (string $dn) { return ldap_explode_dn($dn, 1)[0]; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturnCallback(function (string $gid) use ($group1, $group2, $group3) { if ($gid === $group1['cn']) { @@ -1039,76 +1056,65 @@ public function testGetGroupsByMember(bool $nestedGroups) { return $group3['dn'][0]; } }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('isDNPartOfBase') ->willReturn(true); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getUserGroups('userX'); + $this->initBackend(); + $groups = $this->groupBackend->getUserGroups('userX'); $this->assertEquals($expectedGroupsNames, $groups); - $groupsAgain = $groupBackend->getUserGroups('userX'); + $groupsAgain = $this->groupBackend->getUserGroups('userX'); $this->assertEquals($expectedGroupsNames, $groupsAgain); } public function testCreateGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'createGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::CREATE_GROUP) ->willReturn(true); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('createGroup') ->with('gid') ->willReturn('result'); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->createGroup('gid'), true); + $this->initBackend(); + $this->assertEquals($this->groupBackend->createGroup('gid'), true); } public function testCreateGroupFailing() { $this->expectException(\Exception::class); - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'createGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::CREATE_GROUP) ->willReturn(false); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->createGroup('gid'); + $this->initBackend(); + $this->groupBackend->createGroup('gid'); } public function testDeleteGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'deleteGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::DELETE_GROUP) ->willReturn(true); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('deleteGroup') ->with('gid') ->willReturn(true); @@ -1118,176 +1124,137 @@ public function testDeleteGroupWithPlugin() { ->disableOriginalConstructor() ->getMock(); - $access = $this->getAccessMock(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('getGroupMapper') ->willReturn($mapper); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertTrue($ldap->deleteGroup('gid')); + $this->initBackend(); + $this->assertTrue($this->groupBackend->deleteGroup('gid')); } public function testDeleteGroupFailing() { $this->expectException(\Exception::class); - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'deleteGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::DELETE_GROUP) ->willReturn(false); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->deleteGroup('gid'); + $this->initBackend(); + $this->groupBackend->deleteGroup('gid'); } public function testAddToGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'addToGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::ADD_TO_GROUP) ->willReturn(true); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('addToGroup') ->with('uid', 'gid') ->willReturn('result'); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->addToGroup('uid', 'gid'), 'result'); + $this->initBackend(); + $this->assertEquals($this->groupBackend->addToGroup('uid', 'gid'), 'result'); } public function testAddToGroupFailing() { $this->expectException(\Exception::class); - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'addToGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::ADD_TO_GROUP) ->willReturn(false); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->addToGroup('uid', 'gid'); + $this->initBackend(); + $this->groupBackend->addToGroup('uid', 'gid'); } public function testRemoveFromGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'removeFromGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::REMOVE_FROM_GROUP) ->willReturn(true); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('removeFromGroup') ->with('uid', 'gid') ->willReturn('result'); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->removeFromGroup('uid', 'gid'), 'result'); + $this->initBackend(); + $this->assertEquals($this->groupBackend->removeFromGroup('uid', 'gid'), 'result'); } public function testRemoveFromGroupFailing() { $this->expectException(\Exception::class); - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'removeFromGroup']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::REMOVE_FROM_GROUP) ->willReturn(false); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->removeFromGroup('uid', 'gid'); + $this->initBackend(); + $this->groupBackend->removeFromGroup('uid', 'gid'); } public function testGetGroupDetailsWithPlugin() { /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'getGroupDetails']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::GROUP_DETAILS) ->willReturn(true); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('getGroupDetails') ->with('gid') ->willReturn('result'); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->getGroupDetails('gid'), 'result'); + $this->initBackend(); + $this->assertEquals($this->groupBackend->getGroupDetails('gid'), 'result'); } - public function testGetGroupDetailsFailing() { $this->expectException(\Exception::class); - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) ->setMethods(['implementsActions', 'getGroupDetails']) ->getMock(); - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(GroupInterface::GROUP_DETAILS) ->willReturn(false); - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->getGroupDetails('gid'); + $this->initBackend(); + $this->groupBackend->getGroupDetails('gid'); } public function groupMemberProvider() { @@ -1363,8 +1330,7 @@ public function groupMemberProvider() { * @dataProvider groupMemberProvider */ public function testGroupMembers(array $expectedResult, array $groupsInfo = null) { - $access = $this->getAccessMock(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') ->willReturnCallback(function ($group) use ($groupsInfo) { if (isset($groupsInfo[$group])) { @@ -1373,8 +1339,7 @@ public function testGroupMembers(array $expectedResult, array $groupsInfo = null return []; }); - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function (string $name) { if ($name === 'ldapNestedGroups') { @@ -1385,12 +1350,9 @@ public function testGroupMembers(array $expectedResult, array $groupsInfo = null return null; }); - /** @var GroupPluginManager $pluginManager */ - $pluginManager = $this->createMock(GroupPluginManager::class); - - $ldap = new GroupLDAP($access, $pluginManager); + $this->initBackend(); foreach ($expectedResult as $groupDN => $expectedMembers) { - $resultingMembers = $this->invokePrivate($ldap, '_groupMembers', [$groupDN]); + $resultingMembers = $this->invokePrivate($this->groupBackend, '_groupMembers', [$groupDN]); $this->assertEqualsCanonicalizing($expectedMembers, $resultingMembers); } @@ -1409,13 +1371,11 @@ public function displayNameProvider() { public function testGetDisplayName(string $expected, $ldapResult) { $gid = 'graphic_novelists'; - $access = $this->getAccessMock(); - $access->expects($this->atLeastOnce()) + $this->access->expects($this->atLeastOnce()) ->method('readAttribute') ->willReturn($ldapResult); - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($name) { if ($name === 'ldapGroupMemberAssocAttr') { @@ -1428,14 +1388,11 @@ public function testGetDisplayName(string $expected, $ldapResult) { return null; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') ->willReturn('fakedn'); - /** @var GroupPluginManager $pluginManager */ - $pluginManager = $this->createMock(GroupPluginManager::class); - - $ldap = new GroupLDAP($access, $pluginManager); - $this->assertSame($expected, $ldap->getDisplayName($gid)); + $this->initBackend(); + $this->assertSame($expected, $this->groupBackend->getDisplayName($gid)); } } diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php index eb70c774e2573..15676c4cdc4ee 100644 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php +++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php @@ -30,6 +30,8 @@ use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; use OCA\User_LDAP\User_LDAP; use OCA\User_LDAP\UserPluginManager; +use OCP\IConfig; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../Bootstrap.php'; @@ -56,7 +58,7 @@ public function init() { $userManager->clearBackends(); $userManager->registerBackend($userBackend); - $groupBackend = new Group_LDAP($this->access, \OC::$server->query(GroupPluginManager::class)); + $groupBackend = new Group_LDAP($this->access, \OC::$server->query(GroupPluginManager::class), \OC::$server->get(IConfig::class)); $groupManger = \OC::$server->getGroupManager(); $groupManger->clearBackends(); $groupManger->addBackend($groupBackend);