diff options
Diffstat (limited to 'apps/user_ldap/tests')
55 files changed, 5183 insertions, 5483 deletions
diff --git a/apps/user_ldap/tests/.htaccess b/apps/user_ldap/tests/.htaccess index 6fde30e763a..e62a37927bf 100755 --- a/apps/user_ldap/tests/.htaccess +++ b/apps/user_ldap/tests/.htaccess @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors +# SPDX-FileCopyrightText: 2015 ownCloud, Inc. +# SPDX-License-Identifier: AGPL-3.0-only +# # Generated by ownCloud on 2015-06-18 14:16:40 # line below if for Apache 2.4 <ifModule mod_authz_core.c> diff --git a/apps/user_ldap/tests/AccessTest.php b/apps/user_ldap/tests/AccessTest.php index cbb695d779a..54be29d0f86 100644 --- a/apps/user_ldap/tests/AccessTest.php +++ b/apps/user_ldap/tests/AccessTest.php @@ -1,55 +1,37 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch> - * - * @author Andreas Fischer <bantu@owncloud.com> - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Roger Szabo <roger.szabo@web.de> - * @author root <root@localhost.localdomain> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Victor Dubiniuk <dubiniuk@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests; +use OC\ServerNotAvailableException; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Exceptions\ConstraintViolationException; -use OCA\User_LDAP\FilesystemHelper; use OCA\User_LDAP\Helper; use OCA\User_LDAP\ILDAPWrapper; use OCA\User_LDAP\LDAP; -use OCA\User_LDAP\LogWrapper; +use OCA\User_LDAP\Mapping\GroupMapping; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\User\Manager; +use OCA\User_LDAP\User\OfflineUser; use OCA\User_LDAP\User\User; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\HintException; +use OCP\IAppConfig; use OCP\IAvatarManager; use OCP\IConfig; -use OCP\IDBConnection; use OCP\Image; use OCP\IUserManager; use OCP\Notification\IManager as INotificationManager; +use OCP\Server; +use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; /** @@ -60,91 +42,109 @@ use Test\TestCase; * @package OCA\User_LDAP\Tests */ class AccessTest extends TestCase { - /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject */ - protected $userMapper; - /** @var Connection|\PHPUnit_Framework_MockObject_MockObject */ - private $connection; - /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */ - private $ldap; - /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ - private $userManager; - /** @var Helper|\PHPUnit_Framework_MockObject_MockObject */ - private $helper; - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - private $config; - /** @var Access */ - private $access; - - public function setUp() { - $this->connection = $this->createMock(Connection::class); + protected UserMapping&MockObject $userMapper; + protected IManager&MockObject $shareManager; + protected GroupMapping&MockObject $groupMapper; + private Connection&MockObject $connection; + private LDAP&MockObject $ldap; + private Manager&MockObject $userManager; + private Helper&MockObject $helper; + private IConfig&MockObject $config; + private IUserManager&MockObject $ncUserManager; + private LoggerInterface&MockObject $logger; + private IAppConfig&MockObject $appConfig; + private IEventDispatcher&MockObject $dispatcher; + private Access $access; + + protected function setUp(): void { $this->ldap = $this->createMock(LDAP::class); + $this->connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->ldap]) + ->getMock(); $this->userManager = $this->createMock(Manager::class); $this->helper = $this->createMock(Helper::class); - $this->config = $this->createMock(IConfig::class); + $this->config = $this->createMock(IConfig::class); $this->userMapper = $this->createMock(UserMapping::class); + $this->groupMapper = $this->createMock(GroupMapping::class); + $this->ncUserManager = $this->createMock(IUserManager::class); + $this->shareManager = $this->createMock(IManager::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->dispatcher = $this->createMock(IEventDispatcher::class); $this->access = new Access( - $this->connection, $this->ldap, + $this->connection, $this->userManager, $this->helper, - $this->config + $this->config, + $this->ncUserManager, + $this->logger, + $this->appConfig, + $this->dispatcher, ); + $this->dispatcher->expects($this->any())->method('dispatchTyped'); $this->access->setUserMapper($this->userMapper); + $this->access->setGroupMapper($this->groupMapper); } private function getConnectorAndLdapMock() { - $lw = $this->createMock(ILDAPWrapper::class); + /** @var ILDAPWrapper&MockObject */ + $lw = $this->createMock(ILDAPWrapper::class); + /** @var Connection&MockObject */ $connector = $this->getMockBuilder(Connection::class) - ->setConstructorArgs([$lw, null, null]) + ->setConstructorArgs([$lw, '', null]) ->getMock(); + $connector->expects($this->any()) + ->method('getConnectionResource') + ->willReturn(ldap_connect('ldap://example.com')); + /** @var Manager&MockObject */ $um = $this->getMockBuilder(Manager::class) ->setConstructorArgs([ $this->createMock(IConfig::class), - $this->createMock(FilesystemHelper::class), - $this->createMock(LogWrapper::class), + $this->createMock(LoggerInterface::class), $this->createMock(IAvatarManager::class), $this->createMock(Image::class), - $this->createMock(IDBConnection::class), $this->createMock(IUserManager::class), - $this->createMock(INotificationManager::class)]) + $this->createMock(INotificationManager::class), + $this->shareManager]) ->getMock(); - $helper = new Helper(\OC::$server->getConfig()); + $helper = Server::get(Helper::class); - return array($lw, $connector, $um, $helper); + return [$lw, $connector, $um, $helper]; } - public function testEscapeFilterPartValidChars() { + public function testEscapeFilterPartValidChars(): void { $input = 'okay'; - $this->assertTrue($input === $this->access->escapeFilterPart($input)); + $this->assertSame($input, $this->access->escapeFilterPart($input)); } - public function testEscapeFilterPartEscapeWildcard() { + public function testEscapeFilterPartEscapeWildcard(): void { $input = '*'; - $expected = '\\\\*'; - $this->assertTrue($expected === $this->access->escapeFilterPart($input)); + $expected = '\\2a'; + $this->assertSame($expected, $this->access->escapeFilterPart($input)); } - public function testEscapeFilterPartEscapeWildcard2() { + public function testEscapeFilterPartEscapeWildcard2(): void { $input = 'foo*bar'; - $expected = 'foo\\\\*bar'; - $this->assertTrue($expected === $this->access->escapeFilterPart($input)); + $expected = 'foo\\2abar'; + $this->assertSame($expected, $this->access->escapeFilterPart($input)); } /** - * @dataProvider convertSID2StrSuccessData * @param array $sidArray * @param $sidExpected */ - public function testConvertSID2StrSuccess(array $sidArray, $sidExpected) { + #[\PHPUnit\Framework\Attributes\DataProvider('convertSID2StrSuccessData')] + public function testConvertSID2StrSuccess(array $sidArray, $sidExpected): void { $sidBinary = implode('', $sidArray); $this->assertSame($sidExpected, $this->access->convertSID2Str($sidBinary)); } - public function convertSID2StrSuccessData() { - return array( - array( - array( + public static function convertSID2StrSuccessData(): array { + return [ + [ + [ "\x01", "\x04", "\x00\x00\x00\x00\x00\x05", @@ -152,130 +152,129 @@ class AccessTest extends TestCase { "\xa6\x81\xe5\x0e", "\x4d\x6c\x6c\x2b", "\xca\x32\x05\x5f", - ), + ], 'S-1-5-21-249921958-728525901-1594176202', - ), - array( - array( + ], + [ + [ "\x01", "\x02", "\xFF\xFF\xFF\xFF\xFF\xFF", "\xFF\xFF\xFF\xFF", "\xFF\xFF\xFF\xFF", - ), + ], 'S-1-281474976710655-4294967295-4294967295', - ), - ); + ], + ]; } - public function testConvertSID2StrInputError() { + public function testConvertSID2StrInputError(): void { $sidIllegal = 'foobar'; $sidExpected = ''; $this->assertSame($sidExpected, $this->access->convertSID2Str($sidIllegal)); } - public function testGetDomainDNFromDNSuccess() { + public function testGetDomainDNFromDNSuccess(): void { $inputDN = 'uid=zaphod,cn=foobar,dc=my,dc=server,dc=com'; $domainDN = 'dc=my,dc=server,dc=com'; $this->ldap->expects($this->once()) ->method('explodeDN') ->with($inputDN, 0) - ->will($this->returnValue(explode(',', $inputDN))); + ->willReturn(explode(',', $inputDN)); $this->assertSame($domainDN, $this->access->getDomainDNFromDN($inputDN)); } - public function testGetDomainDNFromDNError() { + public function testGetDomainDNFromDNError(): void { $inputDN = 'foobar'; $expected = ''; $this->ldap->expects($this->once()) ->method('explodeDN') ->with($inputDN, 0) - ->will($this->returnValue(false)); + ->willReturn(false); $this->assertSame($expected, $this->access->getDomainDNFromDN($inputDN)); } - public function dnInputDataProvider() { - return [[ + public static function dnInputDataProvider(): array { + return [ [ - 'input' => 'foo=bar,bar=foo,dc=foobar', - 'interResult' => array( + 'foo=bar,bar=foo,dc=foobar', + [ 'count' => 3, 0 => 'foo=bar', 1 => 'bar=foo', 2 => 'dc=foobar' - ), - 'expectedResult' => true + ], + true ], [ - 'input' => 'foobarbarfoodcfoobar', - 'interResult' => false, - 'expectedResult' => false + 'foobarbarfoodcfoobar', + false, + false ] - ]]; + ]; } - /** - * @dataProvider dnInputDataProvider - * @param array $case - */ - public function testStringResemblesDN($case) { - list($lw, $con, $um, $helper) = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject $config */ + #[\PHPUnit\Framework\Attributes\DataProvider('dnInputDataProvider')] + public function testStringResemblesDN(string $input, array|bool $interResult, bool $expectedResult): void { + [$lw, $con, $um, $helper] = $this->getConnectorAndLdapMock(); + /** @var IConfig&MockObject $config */ $config = $this->createMock(IConfig::class); - $access = new Access($con, $lw, $um, $helper, $config); + $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig, $this->dispatcher); $lw->expects($this->exactly(1)) ->method('explodeDN') - ->will($this->returnCallback(function ($dn) use ($case) { - if($dn === $case['input']) { - return $case['interResult']; + ->willReturnCallback(function ($dn) use ($input, $interResult) { + if ($dn === $input) { + return $interResult; } return null; - })); + }); - $this->assertSame($case['expectedResult'], $access->stringResemblesDN($case['input'])); + $this->assertSame($expectedResult, $access->stringResemblesDN($input)); } - /** - * @dataProvider dnInputDataProvider - * @param $case - */ - public function testStringResemblesDNLDAPmod($case) { - list(, $con, $um, $helper) = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject $config */ + #[\PHPUnit\Framework\Attributes\DataProvider('dnInputDataProvider')] + public function testStringResemblesDNLDAPmod(string $input, array|bool $interResult, bool $expectedResult): void { + [, $con, $um, $helper] = $this->getConnectorAndLdapMock(); + /** @var IConfig&MockObject $config */ $config = $this->createMock(IConfig::class); $lw = new LDAP(); - $access = new Access($con, $lw, $um, $helper, $config); + $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig, $this->dispatcher); - if(!function_exists('ldap_explode_dn')) { + if (!function_exists('ldap_explode_dn')) { $this->markTestSkipped('LDAP Module not available'); } - $this->assertSame($case['expectedResult'], $access->stringResemblesDN($case['input'])); + $this->assertSame($expectedResult, $access->stringResemblesDN($input)); } - public function testCacheUserHome() { + public function testCacheUserHome(): void { $this->connection->expects($this->once()) ->method('writeToCache'); $this->access->cacheUserHome('foobar', '/foobars/path'); } - public function testBatchApplyUserAttributes() { + public function testBatchApplyUserAttributes(): void { $this->ldap->expects($this->any()) ->method('isResource') ->willReturn(true); + $this->connection + ->expects($this->any()) + ->method('getConnectionResource') + ->willReturn(ldap_connect('ldap://example.com')); + $this->ldap->expects($this->any()) ->method('getAttributes') ->willReturn(['displayname' => ['bar', 'count' => 1]]); - /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */ + /** @var UserMapping&MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -289,7 +288,7 @@ class AccessTest extends TestCase { // also returns for userUuidAttribute $this->access->connection->expects($this->any()) ->method('__get') - ->will($this->returnValue('displayName')); + ->willReturn('displayName'); $this->access->setUserMapper($mapperMock); @@ -312,25 +311,25 @@ class AccessTest extends TestCase { $userMock->expects($this->exactly(count($data))) ->method('processAttributes'); - $this->userManager->expects($this->exactly(count($data))) + $this->userManager->expects($this->exactly(count($data) * 2)) ->method('get') - ->will($this->returnValue($userMock)); + ->willReturn($userMock); $this->access->batchApplyUserAttributes($data); } - public function testBatchApplyUserAttributesSkipped() { - /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */ + public function testBatchApplyUserAttributesSkipped(): void { + /** @var UserMapping&MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') - ->will($this->returnValue('a_username')); + ->willReturn('a_username'); $userMock = $this->createMock(User::class); $this->access->connection->expects($this->any()) ->method('__get') - ->will($this->returnValue('displayName')); + ->willReturn('displayName'); $this->access->setUserMapper($mapperMock); @@ -360,18 +359,18 @@ class AccessTest extends TestCase { $this->access->batchApplyUserAttributes($data); } - public function testBatchApplyUserAttributesDontSkip() { - /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject $mapperMock */ + public function testBatchApplyUserAttributesDontSkip(): void { + /** @var UserMapping&MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') - ->will($this->returnValue('a_username')); + ->willReturn('a_username'); $userMock = $this->createMock(User::class); $this->access->connection->expects($this->any()) ->method('__get') - ->will($this->returnValue('displayName')); + ->willReturn('displayName'); $this->access->setUserMapper($mapperMock); @@ -394,53 +393,50 @@ class AccessTest extends TestCase { $userMock->expects($this->exactly(count($data))) ->method('processAttributes'); - $this->userManager->expects($this->exactly(count($data))) + $this->userManager->expects($this->exactly(count($data) * 2)) ->method('get') - ->will($this->returnValue($userMock)); + ->willReturn($userMock); $this->access->batchApplyUserAttributes($data); } - public function dNAttributeProvider() { + public static function dNAttributeProvider(): array { // corresponds to Access::resemblesDN() - return array( - 'dn' => array('dn'), - 'uniqueMember' => array('uniquemember'), - 'member' => array('member'), - 'memberOf' => array('memberof') - ); + return [ + 'dn' => ['dn'], + 'uniqueMember' => ['uniquemember'], + 'member' => ['member'], + 'memberOf' => ['memberof'] + ]; } - /** - * @dataProvider dNAttributeProvider - * @param $attribute - */ - public function testSanitizeDN($attribute) { - list($lw, $con, $um, $helper) = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject $config */ + #[\PHPUnit\Framework\Attributes\DataProvider('dNAttributeProvider')] + public function testSanitizeDN(string $attribute): void { + [$lw, $con, $um, $helper] = $this->getConnectorAndLdapMock(); + /** @var IConfig&MockObject $config */ $config = $this->createMock(IConfig::class); $dnFromServer = 'cn=Mixed Cases,ou=Are Sufficient To,ou=Test,dc=example,dc=org'; $lw->expects($this->any()) ->method('isResource') - ->will($this->returnValue(true)); + ->willReturn(true); $lw->expects($this->any()) ->method('getAttributes') - ->will($this->returnValue(array( - $attribute => array('count' => 1, $dnFromServer) - ))); + ->willReturn([ + $attribute => ['count' => 1, $dnFromServer] + ]); - $access = new Access($con, $lw, $um, $helper, $config); + $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig, $this->dispatcher); $values = $access->readAttribute('uid=whoever,dc=example,dc=org', $attribute); $this->assertSame($values[0], strtolower($dnFromServer)); } - /** - * @expectedException \Exception - * @expectedExceptionMessage LDAP password changes are disabled - */ - public function testSetPasswordWithDisabledChanges() { + + public function testSetPasswordWithDisabledChanges(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('LDAP password changes are disabled'); + $this->connection ->method('__get') ->willReturn(false); @@ -449,45 +445,39 @@ class AccessTest extends TestCase { $this->access->setPassword('CN=foo', 'MyPassword'); } - public function testSetPasswordWithLdapNotAvailable() { + public function testSetPasswordWithLdapNotAvailable(): void { $this->connection ->method('__get') ->willReturn(true); - $connection = $this->createMock(LDAP::class); + $connection = ldap_connect('ldap://example.com'); $this->connection ->expects($this->once()) ->method('getConnectionResource') - ->willReturn($connection); + ->willThrowException(new ServerNotAvailableException('Connection to LDAP server could not be established')); $this->ldap - ->expects($this->once()) - ->method('isResource') - ->with($connection) - ->willReturn(false); + ->expects($this->never()) + ->method('isResource'); - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertFalse($this->access->setPassword('CN=foo', 'MyPassword')); + $this->expectException(ServerNotAvailableException::class); + $this->expectExceptionMessage('Connection to LDAP server could not be established'); + $this->access->setPassword('CN=foo', 'MyPassword'); } - /** - * @expectedException \OC\HintException - * @expectedExceptionMessage Password change rejected. - */ - public function testSetPasswordWithRejectedChange() { + + public function testSetPasswordWithRejectedChange(): void { + $this->expectException(HintException::class); + $this->expectExceptionMessage('Password change rejected.'); + $this->connection ->method('__get') ->willReturn(true); - $connection = $this->createMock(LDAP::class); + $connection = ldap_connect('ldap://example.com'); $this->connection - ->expects($this->once()) + ->expects($this->any()) ->method('getConnectionResource') ->willReturn($connection); $this->ldap ->expects($this->once()) - ->method('isResource') - ->with($connection) - ->willReturn(true); - $this->ldap - ->expects($this->once()) ->method('modReplace') ->with($connection, 'CN=foo', 'MyPassword') ->willThrowException(new ConstraintViolationException()); @@ -496,22 +486,17 @@ class AccessTest extends TestCase { $this->access->setPassword('CN=foo', 'MyPassword'); } - public function testSetPassword() { + public function testSetPassword(): void { $this->connection ->method('__get') ->willReturn(true); - $connection = $this->createMock(LDAP::class); + $connection = ldap_connect('ldap://example.com'); $this->connection - ->expects($this->once()) + ->expects($this->any()) ->method('getConnectionResource') ->willReturn($connection); $this->ldap ->expects($this->once()) - ->method('isResource') - ->with($connection) - ->willReturn(true); - $this->ldap - ->expects($this->once()) ->method('modReplace') ->with($connection, 'CN=foo', 'MyPassword') ->willReturn(true); @@ -524,7 +509,7 @@ class AccessTest extends TestCase { $base, $fakeConnection, $fakeSearchResultResource, - $fakeLdapEntries + $fakeLdapEntries, ) { $this->connection ->expects($this->any()) @@ -532,9 +517,9 @@ class AccessTest extends TestCase { ->willReturn($fakeConnection); $this->connection->expects($this->any()) ->method('__get') - ->willReturnCallback(function($key) use ($base) { - if(stripos($key, 'base') !== false) { - return $base; + ->willReturnCallback(function ($key) use ($base) { + if (stripos($key, 'base') !== false) { + return [$base]; } return null; }); @@ -542,8 +527,8 @@ class AccessTest extends TestCase { $this->ldap ->expects($this->any()) ->method('isResource') - ->willReturnCallback(function ($resource) use ($fakeConnection) { - return $resource === $fakeConnection; + ->willReturnCallback(function ($resource) { + return is_object($resource); }); $this->ldap ->expects($this->any()) @@ -552,9 +537,9 @@ class AccessTest extends TestCase { $this->ldap ->expects($this->once()) ->method('search') - ->willReturn([$fakeSearchResultResource]); + ->willReturn($fakeSearchResultResource); $this->ldap - ->expects($this->exactly(count($base))) + ->expects($this->exactly(1)) ->method('getEntries') ->willReturn($fakeLdapEntries); @@ -563,20 +548,20 @@ class AccessTest extends TestCase { ->willReturnArgument(0); } - public function testSearchNoPagedSearch() { + public function testSearchNoPagedSearch(): void { // scenario: no pages search, 1 search base $filter = 'objectClass=nextcloudUser'; - $base = ['ou=zombies,dc=foobar,dc=nextcloud,dc=com']; + $base = 'ou=zombies,dc=foobar,dc=nextcloud,dc=com'; - $fakeConnection = new \stdClass(); - $fakeSearchResultResource = new \stdClass(); + $fakeConnection = ldap_connect(); + $fakeSearchResultResource = ldap_connect(); $fakeLdapEntries = [ 'count' => 2, [ - 'dn' => 'uid=sgarth,' . $base[0], + 'dn' => 'uid=sgarth,' . $base, ], [ - 'dn' => 'uid=wwilson,' . $base[0], + 'dn' => 'uid=wwilson,' . $base, ] ]; @@ -590,40 +575,41 @@ class AccessTest extends TestCase { $this->assertSame($expected, $result); } - public function testFetchListOfUsers() { + public function testFetchListOfUsers(): void { $filter = 'objectClass=nextcloudUser'; - $base = ['ou=zombies,dc=foobar,dc=nextcloud,dc=com']; + $base = 'ou=zombies,dc=foobar,dc=nextcloud,dc=com'; $attrs = ['dn', 'uid']; - $fakeConnection = new \stdClass(); - $fakeSearchResultResource = new \stdClass(); + $fakeConnection = ldap_connect(); + $fakeSearchResultResource = ldap_connect(); $fakeLdapEntries = [ 'count' => 2, [ - 'dn' => 'uid=sgarth,' . $base[0], + 'dn' => 'uid=sgarth,' . $base, 'uid' => [ 'sgarth' ], ], [ - 'dn' => 'uid=wwilson,' . $base[0], + 'dn' => 'uid=wwilson,' . $base, 'uid' => [ 'wwilson' ], ] ]; $expected = $fakeLdapEntries; unset($expected['count']); - array_walk($expected, function(&$v) { + array_walk($expected, function (&$v): void { $v['dn'] = [$v['dn']]; // dn is translated into an array internally for consistency }); $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries); - $this->connection->expects($this->exactly($fakeLdapEntries['count'])) + // Called twice per user, for userExists and userExistsOnLdap + $this->connection->expects($this->exactly(2 * $fakeLdapEntries['count'])) ->method('writeToCache') ->with($this->stringStartsWith('userExists'), true); $this->userMapper->expects($this->exactly($fakeLdapEntries['count'])) ->method('getNameByDN') - ->willReturnCallback(function($fdn) { - $parts = ldap_explode_dn($fdn, false); + ->willReturnCallback(function ($fdn) { + $parts = ldap_explode_dn($fdn, 0); return $parts[0]; }); @@ -632,5 +618,128 @@ class AccessTest extends TestCase { $this->assertSame($expected, $list); } + public function testFetchListOfGroupsKnown(): void { + $filter = 'objectClass=nextcloudGroup'; + $attributes = ['cn', 'gidNumber', 'dn']; + $base = 'ou=SomeGroups,dc=my,dc=directory'; + + $fakeConnection = ldap_connect(); + $fakeSearchResultResource = ldap_connect(); + $fakeLdapEntries = [ + 'count' => 2, + [ + 'dn' => 'cn=Good Team,' . $base, + 'cn' => ['Good Team'], + ], + [ + 'dn' => 'cn=Another Good Team,' . $base, + 'cn' => ['Another Good Team'], + ] + ]; + + $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries); + + $this->groupMapper->expects($this->any()) + ->method('getListOfIdsByDn') + ->willReturn([ + 'cn=Good Team,' . $base => 'Good_Team', + 'cn=Another Good Team,' . $base => 'Another_Good_Team', + ]); + $this->groupMapper->expects($this->never()) + ->method('getNameByDN'); + + $this->connection->expects($this->exactly(1)) + ->method('writeToCache'); + + $groups = $this->access->fetchListOfGroups($filter, $attributes); + $this->assertSame(2, count($groups)); + $this->assertSame('Good Team', $groups[0]['cn'][0]); + $this->assertSame('Another Good Team', $groups[1]['cn'][0]); + } + + public static function intUsernameProvider(): array { + return [ + ['alice', 'alice'], + ['b/ob', 'bob'], + ['charly🐬', 'charly'], + ['debo rah', 'debo_rah'], + ['epost@poste.test', 'epost@poste.test'], + ['fränk', 'frank'], + [' UPPÉR Case/[\]^`', 'UPPER_Case'], + [' gerda ', 'gerda'], + ['🕱🐵🐘🐑', null], + [ + 'OneNameToRuleThemAllOneNameToFindThemOneNameToBringThemAllAndInTheDarknessBindThem', + '81ff71b5dd0f0092e2dc977b194089120093746e273f2ef88c11003762783127' + ] + ]; + } + public static function groupIDCandidateProvider(): array { + return [ + ['alice', 'alice'], + ['b/ob', 'b/ob'], + ['charly🐬', 'charly🐬'], + ['debo rah', 'debo rah'], + ['epost@poste.test', 'epost@poste.test'], + ['fränk', 'fränk'], + [' gerda ', 'gerda'], + ['🕱🐵🐘🐑', '🕱🐵🐘🐑'], + [ + 'OneNameToRuleThemAllOneNameToFindThemOneNameToBringThemAllAndInTheDarknessBindThem', + '81ff71b5dd0f0092e2dc977b194089120093746e273f2ef88c11003762783127' + ] + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('intUsernameProvider')] + public function testSanitizeUsername(string $name, ?string $expected): void { + if ($expected === null) { + $this->expectException(\InvalidArgumentException::class); + } + $sanitizedName = $this->access->sanitizeUsername($name); + $this->assertSame($expected, $sanitizedName); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('groupIDCandidateProvider')] + public function testSanitizeGroupIDCandidate(string $name, string $expected): void { + $sanitizedName = $this->access->sanitizeGroupIDCandidate($name); + $this->assertSame($expected, $sanitizedName); + } + + public function testUserStateUpdate(): void { + $this->connection->expects($this->any()) + ->method('__get') + ->willReturnMap([ + [ 'ldapUserDisplayName', 'displayName' ], + [ 'ldapUserDisplayName2', null], + ]); + + $offlineUserMock = $this->createMock(OfflineUser::class); + $offlineUserMock->expects($this->once()) + ->method('unmark'); + + $regularUserMock = $this->createMock(User::class); + + $this->userManager->expects($this->atLeastOnce()) + ->method('get') + ->with('detta') + ->willReturnOnConsecutiveCalls($offlineUserMock, $regularUserMock); + + /** @var UserMapping&MockObject $mapperMock */ + $mapperMock = $this->createMock(UserMapping::class); + $mapperMock->expects($this->any()) + ->method('getNameByDN') + ->with('uid=detta,ou=users,dc=hex,dc=ample') + ->willReturn('detta'); + $this->access->setUserMapper($mapperMock); + + $records = [ + [ + 'dn' => ['uid=detta,ou=users,dc=hex,dc=ample'], + 'displayName' => ['Detta Detkova'], + ] + ]; + $this->access->nextcloudUserNames($records); + } } diff --git a/apps/user_ldap/tests/ConfigurationTest.php b/apps/user_ldap/tests/ConfigurationTest.php index 797d2598be4..db92598fcfd 100644 --- a/apps/user_ldap/tests/ConfigurationTest.php +++ b/apps/user_ldap/tests/ConfigurationTest.php @@ -1,100 +1,118 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests; +use OCA\User_LDAP\Configuration; + class ConfigurationTest extends \Test\TestCase { + protected Configuration $configuration; - public function configurationDataProvider() { - $inputWithDN = array( + protected function setUp(): void { + parent::setUp(); + $this->configuration = new Configuration('t01', false); + } + + public static function configurationDataProvider(): array { + $inputWithDN = [ 'cn=someUsers,dc=example,dc=org', ' ', ' cn=moreUsers,dc=example,dc=org ' - ); - $expectWithDN = array( + ]; + $expectWithDN = [ 'cn=someUsers,dc=example,dc=org', 'cn=moreUsers,dc=example,dc=org' - ); + ]; - $inputNames = array( + $inputNames = [ ' uid ', 'cn ', ' ', '', ' whats my name', - ' ' - ); - $expectedNames = array('uid', 'cn', 'whats my name'); + ' ' + ]; + $expectedNames = ['uid', 'cn', 'whats my name']; $inputString = ' alea iacta est '; $expectedString = 'alea iacta est'; - $inputHomeFolder = array( + $inputHomeFolder = [ ' homeDirectory ', ' attr:homeDirectory ', ' ' - ); + ]; - $expectedHomeFolder = array( + $expectedHomeFolder = [ 'attr:homeDirectory', 'attr:homeDirectory', '' - ); + ]; $password = ' such a passw0rd '; - return array( - 'set general base' => array('ldapBase', $inputWithDN, $expectWithDN), - 'set user base' => array('ldapBaseUsers', $inputWithDN, $expectWithDN), - 'set group base' => array('ldapBaseGroups', $inputWithDN, $expectWithDN), + return [ + 'set general base' => ['ldapBase', $inputWithDN, $expectWithDN], + 'set user base' => ['ldapBaseUsers', $inputWithDN, $expectWithDN], + 'set group base' => ['ldapBaseGroups', $inputWithDN, $expectWithDN], - 'set search attributes users' => array('ldapAttributesForUserSearch', $inputNames, $expectedNames), - 'set search attributes groups' => array('ldapAttributesForGroupSearch', $inputNames, $expectedNames), + 'set search attributes users' => ['ldapAttributesForUserSearch', $inputNames, $expectedNames], + 'set search attributes groups' => ['ldapAttributesForGroupSearch', $inputNames, $expectedNames], - 'set user filter objectclasses' => array('ldapUserFilterObjectclass', $inputNames, $expectedNames), - 'set user filter groups' => array('ldapUserFilterGroups', $inputNames, $expectedNames), - 'set group filter objectclasses' => array('ldapGroupFilterObjectclass', $inputNames, $expectedNames), - 'set group filter groups' => array('ldapGroupFilterGroups', $inputNames, $expectedNames), - 'set login filter attributes' => array('ldapLoginFilterAttributes', $inputNames, $expectedNames), + 'set user filter objectclasses' => ['ldapUserFilterObjectclass', $inputNames, $expectedNames], + 'set user filter groups' => ['ldapUserFilterGroups', $inputNames, $expectedNames], + 'set group filter objectclasses' => ['ldapGroupFilterObjectclass', $inputNames, $expectedNames], + 'set group filter groups' => ['ldapGroupFilterGroups', $inputNames, $expectedNames], + 'set login filter attributes' => ['ldapLoginFilterAttributes', $inputNames, $expectedNames], - 'set agent password' => array('ldapAgentPassword', $password, $password), + 'set agent password' => ['ldapAgentPassword', $password, $password], - 'set home folder, variant 1' => array('homeFolderNamingRule', $inputHomeFolder[0], $expectedHomeFolder[0]), - 'set home folder, variant 2' => array('homeFolderNamingRule', $inputHomeFolder[1], $expectedHomeFolder[1]), - 'set home folder, empty' => array('homeFolderNamingRule', $inputHomeFolder[2], $expectedHomeFolder[2]), + 'set home folder, variant 1' => ['homeFolderNamingRule', $inputHomeFolder[0], $expectedHomeFolder[0]], + 'set home folder, variant 2' => ['homeFolderNamingRule', $inputHomeFolder[1], $expectedHomeFolder[1]], + 'set home folder, empty' => ['homeFolderNamingRule', $inputHomeFolder[2], $expectedHomeFolder[2]], // default behaviour, one case is enough, special needs must be tested // individually - 'set string value' => array('ldapHost', $inputString, $expectedString), - ); + 'set string value' => ['ldapHost', $inputString, $expectedString], + + 'set avatar rule, default' => ['ldapUserAvatarRule', 'default', 'default'], + 'set avatar rule, none' => ['ldapUserAvatarRule', 'none', 'none'], + 'set avatar rule, data attribute' => ['ldapUserAvatarRule', 'data:jpegPhoto', 'data:jpegPhoto'], + + 'set external storage home attribute' => ['ldapExtStorageHomeAttribute', 'homePath', 'homePath'], + ]; } - /** - * @dataProvider configurationDataProvider - */ - public function testSetValue($key, $input, $expected) { - $configuration = new \OCA\User_LDAP\Configuration('t01', false); + #[\PHPUnit\Framework\Attributes\DataProvider('configurationDataProvider')] + public function testSetValue(string $key, string|array $input, string|array $expected): void { + $this->configuration->setConfiguration([$key => $input]); + $this->assertSame($this->configuration->$key, $expected); + } - $configuration->setConfiguration([$key => $input]); - $this->assertSame($configuration->$key, $expected); + public static function avatarRuleValueProvider(): array { + return [ + ['none', []], + ['data:selfie', ['selfie']], + ['data:sELFie', ['selfie']], + ['data:', ['jpegphoto', 'thumbnailphoto']], + ['default', ['jpegphoto', 'thumbnailphoto']], + ['invalid#', ['jpegphoto', 'thumbnailphoto']], + ]; } + #[\PHPUnit\Framework\Attributes\DataProvider('avatarRuleValueProvider')] + public function testGetAvatarAttributes(string $setting, array $expected): void { + $this->configuration->setConfiguration(['ldapUserAvatarRule' => $setting]); + $this->assertSame($expected, $this->configuration->getAvatarAttributes()); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('avatarRuleValueProvider')] + public function testResolveRule(string $setting, array $expected): void { + $this->configuration->setConfiguration(['ldapUserAvatarRule' => $setting]); + // so far the only thing that can get resolved :) + $this->assertSame($expected, $this->configuration->resolveRule('avatar')); + } } diff --git a/apps/user_ldap/tests/ConnectionTest.php b/apps/user_ldap/tests/ConnectionTest.php index c0f91d25d39..7116e15898f 100644 --- a/apps/user_ldap/tests/ConnectionTest.php +++ b/apps/user_ldap/tests/ConnectionTest.php @@ -1,34 +1,17 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Jarkko Lehtoranta <devel@jlranta.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Victor Dubiniuk <dubiniuk@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests; + +use OC\ServerNotAvailableException; use OCA\User_LDAP\Connection; use OCA\User_LDAP\ILDAPWrapper; +use PHPUnit\Framework\MockObject\MockObject; /** * Class Test_Connection @@ -38,45 +21,42 @@ use OCA\User_LDAP\ILDAPWrapper; * @package OCA\User_LDAP\Tests */ class ConnectionTest extends \Test\TestCase { - /** @var \OCA\User_LDAP\ILDAPWrapper */ - protected $ldap; - - /** @var Connection */ - protected $connection; + protected ILDAPWrapper&MockObject $ldap; + protected Connection $connection; - public function setUp() { + protected function setUp(): void { parent::setUp(); - $this->ldap = $this->createMock(ILDAPWrapper::class); + $this->ldap = $this->createMock(ILDAPWrapper::class); // we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend. - $this->connection = $this->getMockBuilder('OCA\User_LDAP\Connection') - ->setMethods(['getFromCache', 'writeToCache']) + $this->connection = $this->getMockBuilder(Connection::class) + ->onlyMethods(['getFromCache', 'writeToCache']) ->setConstructorArgs([$this->ldap, '', null]) ->getMock(); $this->ldap->expects($this->any()) ->method('areLDAPFunctionsAvailable') - ->will($this->returnValue(true)); + ->willReturn(true); } - public function testOriginalAgentUnchangedOnClone() { + public function testOriginalAgentUnchangedOnClone(): void { //background: upon login a bind is done with the user credentials //which is valid for the whole LDAP resource. It needs to be reset //to the agent's credentials - $lw = $this->createMock(ILDAPWrapper::class); + $lw = $this->createMock(ILDAPWrapper::class); $connection = new Connection($lw, '', null); - $agent = array( + $agent = [ 'ldapAgentName' => 'agent', 'ldapAgentPassword' => '123456', - ); + ]; $connection->setConfiguration($agent); $testConnection = clone $connection; - $user = array( + $user = [ 'ldapAgentName' => 'user', 'ldapAgentPassword' => 'password', - ); + ]; $testConnection->setConfiguration($user); $agentName = $connection->ldapAgentName; @@ -86,7 +66,7 @@ class ConnectionTest extends \Test\TestCase { $this->assertSame($agentPawd, $agent['ldapAgentPassword']); } - public function testUseBackupServer() { + public function testUseBackupServer(): void { $mainHost = 'ldap://nixda.ldap'; $backupHost = 'ldap://fallback.ldap'; $config = [ @@ -104,25 +84,24 @@ class ConnectionTest extends \Test\TestCase { $this->ldap->expects($this->any()) ->method('isResource') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->any()) ->method('setOption') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->exactly(3)) ->method('connect') - ->will($this->returnValue('ldapResource')); + ->willReturn(ldap_connect('ldap://example.com')); $this->ldap->expects($this->any()) ->method('errno') - ->will($this->returnValue(0)); + ->willReturn(0); // Not called often enough? Then, the fallback to the backup server is broken. - $this->connection->expects($this->exactly(4)) + $this->connection->expects($this->exactly(2)) ->method('getFromCache') - ->with('overrideMainServer') - ->will($this->onConsecutiveCalls(false, false, true, true)); + ->with('overrideMainServer')->willReturnOnConsecutiveCalls(false, false, true, true); $this->connection->expects($this->once()) ->method('writeToCache') @@ -131,13 +110,13 @@ class ConnectionTest extends \Test\TestCase { $isThrown = false; $this->ldap->expects($this->exactly(3)) ->method('bind') - ->will($this->returnCallback(function () use (&$isThrown) { - if(!$isThrown) { + ->willReturnCallback(function () use (&$isThrown) { + if (!$isThrown) { $isThrown = true; - throw new \OC\ServerNotAvailableException(); + throw new ServerNotAvailableException(); } return true; - })); + }); $this->connection->init(); $this->connection->resetConnectionResource(); @@ -145,7 +124,54 @@ class ConnectionTest extends \Test\TestCase { $this->connection->init(); } - public function testBindWithInvalidCredentials() { + public function testDontUseBackupServerOnFailedAuth(): void { + $mainHost = 'ldap://nixda.ldap'; + $backupHost = 'ldap://fallback.ldap'; + $config = [ + 'ldapConfigurationActive' => true, + 'ldapHost' => $mainHost, + 'ldapPort' => 389, + 'ldapBackupHost' => $backupHost, + 'ldapBackupPort' => 389, + 'ldapAgentName' => 'uid=agent', + 'ldapAgentPassword' => 'SuchASecret' + ]; + + $this->connection->setIgnoreValidation(true); + $this->connection->setConfiguration($config); + + $this->ldap->expects($this->any()) + ->method('isResource') + ->willReturn(true); + + $this->ldap->expects($this->any()) + ->method('setOption') + ->willReturn(true); + + $this->ldap->expects($this->once()) + ->method('connect') + ->willReturn(ldap_connect('ldap://example.com')); + + $this->ldap->expects($this->any()) + ->method('errno') + ->willReturn(49); + + $this->connection->expects($this->any()) + ->method('getFromCache') + ->with('overrideMainServer') + ->willReturn(false); + + $this->connection->expects($this->never()) + ->method('writeToCache'); + + $this->ldap->expects($this->exactly(1)) + ->method('bind') + ->willReturn(false); + + $this->connection->init(); + } + + public function testBindWithInvalidCredentials(): void { // background: Bind with invalid credentials should return false // and not throw a ServerNotAvailableException. @@ -164,33 +190,33 @@ class ConnectionTest extends \Test\TestCase { $this->ldap->expects($this->any()) ->method('isResource') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->any()) ->method('setOption') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->any()) ->method('connect') - ->will($this->returnValue('ldapResource')); + ->willReturn(ldap_connect('ldap://example.com')); - $this->ldap->expects($this->exactly(2)) + $this->ldap->expects($this->once()) ->method('bind') - ->will($this->returnValue(false)); + ->willReturn(false); // LDAP_INVALID_CREDENTIALS $this->ldap->expects($this->any()) ->method('errno') - ->will($this->returnValue(0x31)); + ->willReturn(0x31); try { $this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.'); - } catch (\OC\ServerNotAvailableException $e) { + } catch (ServerNotAvailableException $e) { $this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.'); } } - public function testStartTlsNegotiationFailure() { + public function testStartTlsNegotiationFailure(): void { // background: If Start TLS negotiation fails, // a ServerNotAvailableException should be thrown. @@ -211,32 +237,31 @@ class ConnectionTest extends \Test\TestCase { $this->ldap->expects($this->any()) ->method('isResource') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->any()) ->method('connect') - ->will($this->returnValue('ldapResource')); + ->willReturn(ldap_connect('ldap://example.com')); $this->ldap->expects($this->any()) ->method('setOption') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->any()) ->method('bind') - ->will($this->returnValue(true)); + ->willReturn(true); $this->ldap->expects($this->any()) ->method('errno') - ->will($this->returnValue(0)); + ->willReturn(0); $this->ldap->expects($this->any()) ->method('startTls') - ->will($this->returnValue(false)); + ->willReturn(false); - $this->expectException(\OC\ServerNotAvailableException::class); + $this->expectException(ServerNotAvailableException::class); $this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.'); $this->connection->init(); } - } diff --git a/apps/user_ldap/tests/GroupLDAPPluginTest.php b/apps/user_ldap/tests/GroupLDAPPluginTest.php index 9b13e37bc97..9f4cff64d6b 100644 --- a/apps/user_ldap/tests/GroupLDAPPluginTest.php +++ b/apps/user_ldap/tests/GroupLDAPPluginTest.php @@ -1,54 +1,33 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br) - * - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; - -use OCP\GroupInterface; use OCA\User_LDAP\GroupPluginManager; +use OCP\GroupInterface; class GroupLDAPPluginTest extends \Test\TestCase { - - /** - * @return GroupPluginManager - */ - private function getGroupPluginManager() { + private function getGroupPluginManager(): GroupPluginManager { return new GroupPluginManager(); } - public function testImplementsActions() { + public function testImplementsActions(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions']) ->getMock(); $plugin->expects($this->any()) ->method('respondToActions') ->willReturn(GroupInterface::CREATE_GROUP); - $plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions']) + $plugin2 = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions']) ->getMock(); $plugin2->expects($this->any()) @@ -63,11 +42,11 @@ class GroupLDAPPluginTest extends \Test\TestCase { $this->assertTrue($pluginManager->implementsActions(GroupInterface::ADD_TO_GROUP)); } - public function testCreateGroup() { + public function testCreateGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'createGroup']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions', 'createGroup']) ->getMock(); $plugin->expects($this->any()) @@ -84,20 +63,20 @@ class GroupLDAPPluginTest extends \Test\TestCase { $pluginManager->createGroup('group'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements createGroup in this LDAP Backend. - */ - public function testCreateGroupNotRegistered() { + + public function testCreateGroupNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements createGroup in this LDAP Backend.'); + $pluginManager = $this->getGroupPluginManager(); $pluginManager->createGroup('foo'); } - public function testDeleteGroup() { + public function testDeleteGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'deleteGroup']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions', 'deleteGroup']) ->getMock(); $plugin->expects($this->any()) @@ -108,26 +87,26 @@ class GroupLDAPPluginTest extends \Test\TestCase { ->method('deleteGroup') ->with( $this->equalTo('group') - ); + )->willReturn(true); $pluginManager->register($plugin); - $pluginManager->deleteGroup('group'); + $this->assertTrue($pluginManager->deleteGroup('group')); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements deleteGroup in this LDAP Backend. - */ - public function testDeleteGroupNotRegistered() { + + public function testDeleteGroupNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements deleteGroup in this LDAP Backend.'); + $pluginManager = $this->getGroupPluginManager(); $pluginManager->deleteGroup('foo'); } - public function testAddToGroup() { + public function testAddToGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'addToGroup']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions', 'addToGroup']) ->getMock(); $plugin->expects($this->any()) @@ -145,20 +124,20 @@ class GroupLDAPPluginTest extends \Test\TestCase { $pluginManager->addToGroup('uid', 'gid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements addToGroup in this LDAP Backend. - */ - public function testAddToGroupNotRegistered() { + + public function testAddToGroupNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements addToGroup in this LDAP Backend.'); + $pluginManager = $this->getGroupPluginManager(); $pluginManager->addToGroup('foo', 'bar'); - } + } - public function testRemoveFromGroup() { + public function testRemoveFromGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'removeFromGroup']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions', 'removeFromGroup']) ->getMock(); $plugin->expects($this->any()) @@ -176,20 +155,20 @@ class GroupLDAPPluginTest extends \Test\TestCase { $pluginManager->removeFromGroup('uid', 'gid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements removeFromGroup in this LDAP Backend. - */ - public function testRemoveFromGroupNotRegistered() { + + public function testRemoveFromGroupNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements removeFromGroup in this LDAP Backend.'); + $pluginManager = $this->getGroupPluginManager(); $pluginManager->removeFromGroup('foo', 'bar'); } - public function testCountUsersInGroup() { + public function testCountUsersInGroup(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'countUsersInGroup']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions', 'countUsersInGroup']) ->getMock(); $plugin->expects($this->any()) @@ -207,20 +186,20 @@ class GroupLDAPPluginTest extends \Test\TestCase { $pluginManager->countUsersInGroup('gid', 'search'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements countUsersInGroup in this LDAP Backend. - */ - public function testCountUsersInGroupNotRegistered() { + + public function testCountUsersInGroupNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements countUsersInGroup in this LDAP Backend.'); + $pluginManager = $this->getGroupPluginManager(); $pluginManager->countUsersInGroup('foo', 'bar'); - } + } - public function testgetGroupDetails() { + public function testgetGroupDetails(): void { $pluginManager = $this->getGroupPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'getGroupDetails']) + $plugin = $this->getMockBuilder(LDAPGroupPluginDummy::class) + ->onlyMethods(['respondToActions', 'getGroupDetails']) ->getMock(); $plugin->expects($this->any()) @@ -237,11 +216,11 @@ class GroupLDAPPluginTest extends \Test\TestCase { $pluginManager->getGroupDetails('gid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements getGroupDetails in this LDAP Backend. - */ - public function testgetGroupDetailsNotRegistered() { + + public function testgetGroupDetailsNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements getGroupDetails in this LDAP Backend.'); + $pluginManager = $this->getGroupPluginManager(); $pluginManager->getGroupDetails('foo'); } diff --git a/apps/user_ldap/tests/Group_LDAPTest.php b/apps/user_ldap/tests/Group_LDAPTest.php index 03fd73f261f..10182111768 100644 --- a/apps/user_ldap/tests/Group_LDAPTest.php +++ b/apps/user_ldap/tests/Group_LDAPTest.php @@ -1,44 +1,31 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Frédéric Fortier <frederic.fortier@oronospolytechnique.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Victor Dubiniuk <dubiniuk@owncloud.com> - * @author Vincent Petry <pvince81@owncloud.com> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * @author Xuanwo <xuanwo@yunify.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests; -use OCA\User_LDAP\GroupPluginManager; -use OCP\GroupInterface; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; use OCA\User_LDAP\Group_LDAP as GroupLDAP; +use OCA\User_LDAP\GroupPluginManager; 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 OCP\Security\ISecureRandom; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; /** * Class GroupLDAPTest @@ -47,405 +34,405 @@ use OCA\User_LDAP\User\Manager; * * @package OCA\User_LDAP\Tests */ -class Group_LDAPTest extends \Test\TestCase { - /** - * @return \PHPUnit_Framework_MockObject_MockObject|Access - */ - private function getAccessMock() { - static $conMethods; - static $accMethods; - - if(is_null($conMethods) || is_null($accMethods)) { - $conMethods = get_class_methods('\OCA\User_LDAP\Connection'); - $accMethods = get_class_methods('\OCA\User_LDAP\Access'); - } - $lw = $this->createMock(ILDAPWrapper::class); - $connector = $this->getMockBuilder('\OCA\User_LDAP\Connection') - ->setMethods($conMethods) - ->setConstructorArgs([$lw, null, null]) - ->getMock(); - - $access = $this->createMock(Access::class); - - $access->expects($this->any()) - ->method('getConnection') - ->will($this->returnValue($connector)); - - return $access; +class Group_LDAPTest extends TestCase { + private Access&MockObject $access; + private GroupPluginManager&MockObject $pluginManager; + private IConfig&MockObject $config; + private IUserManager&MockObject $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); } - private function getPluginManagerMock() { - return $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager')->getMock(); - } - - /** - * @param Access|\PHPUnit_Framework_MockObject_MockObject $access - */ - private function enableGroups($access) { - $access->connection = $this->createMock(Connection::class); - - $access->connection->expects($this->any()) - ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapDynamicGroupMemberURL') { - return ''; - } - return 1; - })); + 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(); + public function testCountEmptySearchString(): void { + $groupDN = 'cn=group,dc=foo,dc=bar'; - $this->enableGroups($access); + $this->enableGroups(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('groupname2dn') - ->will($this->returnValue('cn=group,dc=foo,dc=bar')); - - $access->expects($this->any()) + ->willReturn($groupDN); + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnValue(array('u11', 'u22', 'u33', 'u34'))); - + ->willReturnCallback(function ($dn) use ($groupDN) { + if ($dn === $groupDN) { + return [ + 'uid=u11,ou=users,dc=foo,dc=bar', + 'uid=u22,ou=users,dc=foo,dc=bar', + 'uid=u33,ou=users,dc=foo,dc=bar', + 'uid=u34,ou=users,dc=foo,dc=bar' + ]; + } + return []; + }); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); // for primary groups - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('countUsers') - ->will($this->returnValue(2)); + ->willReturn(2); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('group'); + $this->access->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['displayName', 'mail']); + + $this->initBackend(); + $users = $this->groupBackend->countUsersInGroup('group'); $this->assertSame(6, $users); } - public function testCountWithSearchString() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + /** + * @return MockObject|Access + */ + private function getAccessMock() { + $lw = $this->createMock(ILDAPWrapper::class); + $connector = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$lw, '', null]) + ->getMock(); - $this->enableGroups($access); + $this->access = $this->createMock(Access::class); + $this->access->connection = $connector; + $this->access->userManager = $this->createMock(Manager::class); - $access->expects($this->any()) - ->method('groupname2dn') - ->will($this->returnValue('cn=group,dc=foo,dc=bar')); + return $this->access; + } - $access->expects($this->any()) - ->method('fetchListOfUsers') - ->will($this->returnValue(array())); + private function enableGroups(): void { + $this->access->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + if ($name === 'ldapDynamicGroupMemberURL') { + return ''; + } elseif ($name === 'ldapBaseGroups') { + return []; + } + return 1; + }); + } - $access->expects($this->any()) + public function testCountWithSearchString(): void { + $this->enableGroups(); + + $this->access->expects($this->any()) + ->method('groupname2dn') + ->willReturn('cn=group,dc=foo,dc=bar'); + $this->access->expects($this->any()) + ->method('fetchListOfUsers') + ->willReturn([]); + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($name) { + ->willReturnCallback(function ($name) { //the search operation will call readAttribute, thus we need - //to anaylze the "dn". All other times we just need to return + //to analyze the "dn". All other times we just need to return //something that is neither null or false, but once an array //with the users in the group – so we do so all other times for - //simplicicity. - if(strpos($name, 'u') === 0) { + //simplicity. + if (str_starts_with($name, 'u')) { return strpos($name, '3'); } - return array('u11', 'u22', 'u33', 'u34'); - })); - - $access->expects($this->any()) + return ['u11', 'u22', 'u33', 'u34']; + }); + $this->access->expects($this->any()) ->method('dn2username') - ->will($this->returnCallback(function() { - return 'foobar' . \OC::$server->getSecureRandom()->generate(7); - })); + ->willReturnCallback(function () { + return 'foobar' . Server::get(ISecureRandom::class)->generate(7); + }); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); + $this->access->expects($this->any()) + ->method('escapeFilterPart') + ->willReturnArgument(0); + + $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|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions','countUsersInGroup']) + public function testCountUsersWithPlugin(): void { + /** @var GroupPluginManager|MockObject $pluginManager */ + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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); - } - - public function testGidNumber2NameSuccess() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + $this->initBackend(); + $this->assertEquals($this->groupBackend->countUsersInGroup('gid', 'search'), 42); + } - $this->enableGroups($access); + public function testGidNumber2NameSuccess(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') - ->will($this->returnValue([['dn' => ['cn=foo,dc=barfoo,dc=bar']]])); + ->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') - ->will($this->returnValue('MyGroup')); + ->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); + public function testGidNumberID2NameNoGroup(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') - ->will($this->returnValue(array())); + ->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); + public function testGidNumberID2NameNoName(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') - ->will($this->returnValue([['dn' => ['cn=foo,dc=barfoo,dc=bar']]])); + ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2groupname') - ->will($this->returnValue(false)); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn(false); - $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); + public function testGetEntryGidNumberValue(): void { + $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) - ->will($this->returnValue(array('3117'))); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn(['3117']); - $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); + public function testGetEntryGidNumberNoValue(): void { + $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) - ->will($this->returnValue(false)); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn(false); - $gid = $groupBackend->getGroupGidNumber($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupGidNumber($dn); $this->assertSame(false, $gid); } - public function testPrimaryGroupID2NameSuccess() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + public function testPrimaryGroupID2NameSuccessCache(): void { + $this->enableGroups(); + + $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; + $gid = '3117'; + + /** @var MockObject $connection */ + $connection = $this->access->connection; + $connection->expects($this->once()) + ->method('getFromCache') + ->with('primaryGroupIDtoName_' . $gid) + ->willReturn('MyGroup'); - $this->enableGroups($access); + $this->access->expects($this->never()) + ->method('getSID'); + + $this->access->expects($this->never()) + ->method('searchGroups'); + + $this->access->expects($this->never()) + ->method('dn2groupname'); + + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name($gid, $userDN); + + $this->assertSame('MyGroup', $group); + } + + public function testPrimaryGroupID2NameSuccess(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) - ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202')); + ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') - ->will($this->returnValue([['dn' => ['cn=foo,dc=barfoo,dc=bar']]])); + ->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') - ->will($this->returnValue('MyGroup')); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn('MyGroup'); - $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); + public function testPrimaryGroupID2NameNoSID(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) - ->will($this->returnValue(false)); + ->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); + public function testPrimaryGroupID2NameNoGroup(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) - ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202')); + ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') - ->will($this->returnValue(array())); + ->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); + public function testPrimaryGroupID2NameNoName(): void { + $this->enableGroups(); $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('getSID') ->with($userDN) - ->will($this->returnValue('S-1-5-21-249921958-728525901-1594176202')); + ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('searchGroups') - ->will($this->returnValue([['dn' => ['cn=foo,dc=barfoo,dc=bar']]])); + ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('dn2groupname') - ->will($this->returnValue(false)); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn(false); - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); + $this->initBackend(); + $group = $this->groupBackend->primaryGroupID2Name('3117', $userDN); $this->assertSame(false, $group); } - public function testGetEntryGroupIDValue() { + public function testGetEntryGroupIDValue(): void { //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) - ->will($this->returnValue(array('3117'))); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn(['3117']); - $gid = $groupBackend->getGroupPrimaryGroupID($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupPrimaryGroupID($dn); $this->assertSame('3117', $gid); } - public function testGetEntryGroupIDNoValue() { + public function testGetEntryGroupIDNoValue(): void { //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) - ->will($this->returnValue(false)); - - $groupBackend = new GroupLDAP($access, $pluginManager); + ->willReturn(false); - $gid = $groupBackend->getGroupPrimaryGroupID($dn); + $this->initBackend(); + $gid = $this->groupBackend->getGroupPrimaryGroupID($dn); $this->assertSame(false, $gid); } @@ -454,517 +441,942 @@ class Group_LDAPTest extends \Test\TestCase { * tests whether Group Backend behaves correctly when cache with uid and gid * is hit */ - public function testInGroupHitsUidGidCache() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + public function testInGroupHitsUidGidCache(): void { + $this->enableGroups(); $uid = 'someUser'; $gid = 'someGroup'; - $cacheKey = 'inGroup'.$uid.':'.$gid; + $cacheKey = 'inGroup' . $uid . ':' . $gid; - $access->connection->expects($this->once()) + $this->access->connection->expects($this->once()) ->method('getFromCache') ->with($cacheKey) - ->will($this->returnValue(true)); + ->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 static function groupWithMembersProvider(): array { + return [ + [ + 'someGroup', + 'cn=someGroup,ou=allTheGroups,ou=someDepartment,dc=someDomain,dc=someTld', + [ + 'uid=oneUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', + 'uid=someUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', + 'uid=anotherUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', + 'uid=differentUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', + ], + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')] + public function testInGroupMember(string $gid, string $groupDn, array $memberDNs): void { + $uid = 'someUser'; + $userDn = $memberDNs[0]; + + $this->access->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + switch ($name) { + case 'ldapGroupMemberAssocAttr': + return 'member'; + case 'ldapDynamicGroupMemberURL': + return ''; + case 'hasPrimaryGroups': + case 'ldapNestedGroups': + return 0; + default: + return 1; + } + }); + $this->access->connection->expects($this->any()) + ->method('getFromCache') + ->willReturn(null); + + $this->access->expects($this->once()) + ->method('username2dn') + ->with($uid) + ->willReturn($userDn); + $this->access->expects($this->once()) + ->method('groupname2dn') + ->willReturn($groupDn); + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturn($memberDNs); + + $this->initBackend(); + $this->assertTrue($this->groupBackend->inGroup($uid, $gid)); } - public function testGetGroupsWithOffset() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + #[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')] + public function testInGroupMemberNot(string $gid, string $groupDn, array $memberDNs): void { + $uid = 'unelatedUser'; + $userDn = 'uid=unrelatedUser,ou=unrelatedTeam,ou=unrelatedDepartment,dc=someDomain,dc=someTld'; + + $this->access->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + switch ($name) { + case 'ldapGroupMemberAssocAttr': + return 'member'; + case 'ldapDynamicGroupMemberURL': + return ''; + case 'hasPrimaryGroups': + case 'ldapNestedGroups': + return 0; + default: + return 1; + } + }); + $this->access->connection->expects($this->any()) + ->method('getFromCache') + ->willReturn(null); + + $this->access->expects($this->once()) + ->method('username2dn') + ->with($uid) + ->willReturn($userDn); + $this->access->expects($this->once()) + ->method('groupname2dn') + ->willReturn($groupDn); + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturn($memberDNs); + + $this->initBackend(); + $this->assertFalse($this->groupBackend->inGroup($uid, $gid)); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('groupWithMembersProvider')] + public function testInGroupMemberUid(string $gid, string $groupDn, array $memberDNs): void { + $memberUids = []; + $userRecords = []; + foreach ($memberDNs as $dn) { + $memberUids[] = ldap_explode_dn($dn, 0)[0]; + $userRecords[] = ['dn' => [$dn]]; + } + + $uid = 'someUser'; + $userDn = $memberDNs[0]; + + $this->access->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + switch ($name) { + case 'ldapGroupMemberAssocAttr': + return 'memberUid'; + case 'ldapDynamicGroupMemberURL': + return ''; + case 'ldapLoginFilter': + return 'uid=%uid'; + case 'hasPrimaryGroups': + case 'ldapNestedGroups': + return 0; + default: + return 1; + } + }); + $this->access->connection->expects($this->any()) + ->method('getFromCache') + ->willReturn(null); + + $this->access->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['uid', 'mail', 'displayname']); + + $this->access->expects($this->once()) + ->method('username2dn') + ->with($uid) + ->willReturn($userDn); + $this->access->expects($this->once()) + ->method('groupname2dn') + ->willReturn($groupDn); + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturn($memberUids); + $this->access->expects($this->any()) + ->method('fetchListOfUsers') + ->willReturn($userRecords); + $this->access->expects($this->any()) + ->method('combineFilterWithOr') + ->willReturn('(|(pseudo=filter)(filter=pseudo))'); + + $this->initBackend(); + $this->assertTrue($this->groupBackend->inGroup($uid, $gid)); + } - $this->enableGroups($access); + public function testGetGroupsWithOffset(): void { + $this->enableGroups(); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('nextcloudGroupNames') - ->will($this->returnValue(array('group1', 'group2'))); + ->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)); } /** - * tests that a user listing is complete, if all it's members have the group + * tests that a user listing is complete, if all its members have the group * as their primary. */ - public function testUsersInGroupPrimaryMembersOnly() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + public function testUsersInGroupPrimaryMembersOnly(): void { + $this->enableGroups(); - $this->enableGroups($access); - - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') - ->will($this->returnValue(null)); - $access->expects($this->any()) + ->willReturn(null); + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { - if($attr === 'primaryGroupToken') { - return array(1337); - } else if($attr === 'gidNumber') { + ->willReturnCallback(function ($dn, $attr) { + if ($attr === 'primaryGroupToken') { + return [1337]; + } elseif ($attr === 'gidNumber') { return [4211]; } - return array(); - })); - $access->expects($this->any()) + return []; + }); + $this->access->expects($this->any()) ->method('groupname2dn') - ->will($this->returnValue('cn=foobar,dc=foo,dc=bar')); - $access->expects($this->exactly(2)) + ->willReturn('cn=foobar,dc=foo,dc=bar'); + $this->access->expects($this->exactly(2)) ->method('nextcloudUserNames') ->willReturnOnConsecutiveCalls(['lisa', 'bart', 'kira', 'brad'], ['walle', 'dino', 'xenia']); - $access->userManager = $this->createMock(Manager::class); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); + $this->access->expects($this->any()) + ->method('combineFilterWithAnd') + ->willReturn('pseudo=filter'); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->usersInGroup('foobar'); + $this->access->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['displayName', 'mail']); + + $this->initBackend(); + $users = $this->groupBackend->usersInGroup('foobar'); $this->assertSame(7, count($users)); } /** - * tests that a user listing is complete, if all it's members have the group + * tests that a user listing is complete, if all its members have the group * as their primary. */ - public function testUsersInGroupPrimaryAndUnixMembers() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + public function testUsersInGroupPrimaryAndUnixMembers(): void { + $this->enableGroups(); - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') - ->will($this->returnValue(null)); - $access->expects($this->any()) + ->willReturn(null); + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { - if($attr === 'primaryGroupToken') { - return array(1337); + ->willReturnCallback(function ($dn, $attr) { + if ($attr === 'primaryGroupToken') { + return [1337]; } - return array(); - })); - $access->expects($this->any()) + return []; + }); + $this->access->expects($this->any()) ->method('groupname2dn') - ->will($this->returnValue('cn=foobar,dc=foo,dc=bar')); - $access->expects($this->once()) + ->willReturn('cn=foobar,dc=foo,dc=bar'); + $this->access->expects($this->once()) ->method('nextcloudUserNames') - ->will($this->returnValue(array('lisa', 'bart', 'kira', 'brad'))); - $access->userManager = $this->createMock(Manager::class); + ->willReturn(['lisa', 'bart', 'kira', 'brad']); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); + $this->access->expects($this->any()) + ->method('combineFilterWithAnd') + ->willReturn('pseudo=filter'); + + $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)); } /** - * tests that a user counting is complete, if all it's members have the group + * tests that a user counting is complete, if all its members have the group * as their primary. */ - public function testCountUsersInGroupPrimaryMembersOnly() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + public function testCountUsersInGroupPrimaryMembersOnly(): void { + $this->enableGroups(); - $this->enableGroups($access); - - $access->connection->expects($this->any()) + $this->access->connection->expects($this->any()) ->method('getFromCache') - ->will($this->returnValue(null)); + ->willReturn(null); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { - if($attr === 'primaryGroupToken') { - return array(1337); + ->willReturnCallback(function ($dn, $attr) { + if ($attr === 'primaryGroupToken') { + return [1337]; } - return array(); - })); - - $access->expects($this->any()) + return []; + }); + $this->access->expects($this->any()) ->method('groupname2dn') - ->will($this->returnValue('cn=foobar,dc=foo,dc=bar')); - - $access->expects($this->once()) + ->willReturn('cn=foobar,dc=foo,dc=bar'); + $this->access->expects($this->once()) ->method('countUsers') - ->will($this->returnValue(4)); + ->willReturn(4); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('foobar'); + $this->access->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['displayName', 'mail']); + + $this->initBackend(); + $users = $this->groupBackend->countUsersInGroup('foobar'); $this->assertSame(4, $users); } - public function testGetUserGroupsMemberOf() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); + public function testGetUserGroupsMemberOf(): void { + $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()) - ->method('username2dn') - ->will($this->returnValue($dn)); - - $access->expects($this->exactly(3)) - ->method('readAttribute') - ->will($this->onConsecutiveCalls(['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar'], [], [])); + $expectedGroups = ['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar']; - $access->expects($this->exactly(2)) + $this->access->expects($this->any()) + ->method('username2dn') + ->willReturn($dn); + $this->access->expects($this->exactly(5)) + ->method('readAttribute')->willReturnOnConsecutiveCalls($expectedGroups, [], [], [], []); + $this->access->expects($this->any()) ->method('dn2groupname') - ->will($this->returnArgument(0)); + ->willReturnArgument(0); + $this->access->expects($this->any()) + ->method('groupname2dn') + ->willReturnArgument(0); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); - $access->expects($this->exactly(3)) - ->method('groupsMatchFilter') - ->will($this->returnArgument(0)); + $this->config->expects($this->once()) + ->method('setUserValue') + ->with('userX', 'user_ldap', 'cached-group-memberships-', \json_encode($expectedGroups)); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getUserGroups('userX'); + $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()) + public function testGetUserGroupsMemberOfDisabled(): void { + $this->access->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'useMemberOfToDetectMembership') { + ->willReturnCallback(function ($name) { + if ($name === 'useMemberOfToDetectMembership') { return 0; - } else if($name === 'ldapDynamicGroupMemberURL') { + } elseif ($name === 'ldapDynamicGroupMemberURL') { return ''; } return 1; - })); + }); $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') - ->will($this->returnValue($dn)); - - $access->expects($this->never()) + ->willReturn($dn); + $this->access->expects($this->never()) ->method('readAttribute') ->with($dn, 'memberOf'); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('nextcloudGroupNames') - ->will($this->returnValue([])); + ->willReturn([]); + + // 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); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groupBackend->getUserGroups('userX'); + $this->initBackend(); + $this->groupBackend->getUserGroups('userX'); } - public function testGetGroupsByMember() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); + public function testGetUserGroupsOfflineUser(): void { + $this->enableGroups(); - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) + $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->assertContains('groupB', $returnedGroups); + $this->assertContains('groupF', $returnedGroups); + } + + /** + * regression tests against a case where a json object was stored instead of expected list + * @see https://github.com/nextcloud/server/issues/42374 + */ + public function testGetUserGroupsOfflineUserUnexpectedJson(): void { + $this->enableGroups(); + + $offlineUser = $this->createMock(OfflineUser::class); + + $this->config->expects($this->any()) + ->method('getUserValue') + ->with('userX', 'user_ldap', 'cached-group-memberships-', $this->anything()) + // results in a json object: {"0":"groupB","2":"groupF"} + ->willReturn(\json_encode([0 => 'groupB', 2 => '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->assertContains('groupB', $returnedGroups); + $this->assertContains('groupF', $returnedGroups); + } + + public function testGetUserGroupsUnrecognizedOfflineUser(): void { + $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->assertContains('groupB', $returnedGroups); + $this->assertContains('groupF', $returnedGroups); + } + + public static function nestedGroupsProvider(): array { + return [ + [true], + [false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('nestedGroupsProvider')] + public function testGetGroupsByMember(bool $nestedGroups): void { + $groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))'; + $this->access->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'useMemberOfToDetectMembership') { - return 0; - } else if($name === 'ldapDynamicGroupMemberURL') { - return ''; - } else if($name === 'ldapNestedGroups') { - return false; + ->willReturnCallback(function (string $name) use ($nestedGroups, $groupFilter) { + switch ($name) { + case 'useMemberOfToDetectMembership': + return 0; + case 'ldapDynamicGroupMemberURL': + return ''; + case 'ldapNestedGroups': + return (int)$nestedGroups; + case 'ldapGroupMemberAssocAttr': + return 'member'; + case 'ldapGroupFilter': + return $groupFilter; + case 'ldapBaseGroups': + return []; + case 'ldapGroupDisplayName': + return 'cn'; } return 1; - })); + }); $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') - ->will($this->returnValue($dn)); - - $access->expects($this->never()) + ->willReturn($dn); + $this->access->expects($this->any()) ->method('readAttribute') - ->with($dn, 'memberOf'); + ->willReturn([]); + $this->access->expects($this->any()) + ->method('combineFilterWithAnd') + ->willReturnCallback(function (array $filterParts) { + // ⚠ returns a pseudo-filter only, not real LDAP Filter syntax + return implode('&', $filterParts); + }); $group1 = [ 'cn' => 'group1', 'dn' => ['cn=group1,ou=groups,dc=domain,dc=com'], + 'member' => [$dn], ]; $group2 = [ 'cn' => 'group2', 'dn' => ['cn=group2,ou=groups,dc=domain,dc=com'], + 'member' => [$dn], + ]; + $group3 = [ + 'cn' => 'group3', + 'dn' => ['cn=group3,ou=groups,dc=domain,dc=com'], + 'member' => [$group2['dn'][0]], ]; - $access->expects($this->once()) - ->method('nextcloudGroupNames') - ->with([$group1, $group2]) - ->will($this->returnValue(['group1', 'group2'])); + $expectedGroups = ($nestedGroups ? [$group1, $group2, $group3] : [$group1, $group2]); + $expectedGroupsNames = ($nestedGroups ? ['group1', 'group2', 'group3'] : ['group1', 'group2']); - $access->expects($this->once()) + $this->access->expects($this->any()) + ->method('nextcloudGroupNames') + ->with($expectedGroups) + ->willReturn($expectedGroupsNames); + $this->access->expects($nestedGroups ? $this->atLeastOnce() : $this->once()) ->method('fetchListOfGroups') - ->will($this->returnValue([$group1, $group2])); + ->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2, $group3, $dn) { + static $firstRun = true; + if (!$nestedGroups) { + // When nested groups are enabled, groups cannot be filtered early as it would + // exclude intermediate groups. But we can, and should, when working with flat groups. + $this->assertTrue(str_contains($filter, $groupFilter)); + } + [$memberFilter] = explode('&', $filter); + if ($memberFilter === 'member=' . $dn) { + return [$group1, $group2]; + return []; + } elseif ($memberFilter === 'member=' . $group2['dn'][0]) { + return [$group3]; + } else { + return []; + } + }); + $this->access->expects($this->any()) + ->method('dn2groupname') + ->willReturnCallback(function (string $dn) { + return ldap_explode_dn($dn, 1)[0]; + }); + $this->access->expects($this->any()) + ->method('groupname2dn') + ->willReturnCallback(function (string $gid) use ($group1, $group2, $group3) { + if ($gid === $group1['cn']) { + return $group1['dn'][0]; + } + if ($gid === $group2['cn']) { + return $group2['dn'][0]; + } + if ($gid === $group3['cn']) { + return $group3['dn'][0]; + } + }); + $this->access->expects($this->any()) + ->method('isDNPartOfBase') + ->willReturn(true); - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getUserGroups('userX'); - $this->assertEquals(['group1', 'group2'], $groups); + $this->initBackend(); + $groups = $this->groupBackend->getUserGroups('userX'); + $this->assertEquals($expectedGroupsNames, $groups); - $groupsAgain = $groupBackend->getUserGroups('userX'); - $this->assertEquals(['group1', 'group2'], $groupsAgain); + $groupsAgain = $this->groupBackend->getUserGroups('userX'); + $this->assertEquals($expectedGroupsNames, $groupsAgain); } - public function testCreateGroupWithPlugin() { - /** @var GroupPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions','createGroup']) + public function testCreateGroupWithPlugin(): void { + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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); + $this->initBackend(); + $this->assertTrue($this->groupBackend->createGroup('gid')); + } - $ldap = new GroupLDAP($access, $pluginManager); - $this->assertEquals($ldap->createGroup('gid'),true); - } + public function testCreateGroupFailing(): void { + $this->expectException(\Exception::class); - /** - * @expectedException \Exception - */ - public function testCreateGroupFailing() { - /** @var GroupPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions', 'createGroup']) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions','deleteGroup']) + public function testDeleteGroupWithPlugin(): void { + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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('result'); + ->willReturn(true); - $mapper = $this->getMockBuilder('\OCA\User_LDAP\Mapping\GroupMapping') - ->setMethods(['unmap']) + $mapper = $this->getMockBuilder(GroupMapping::class) + ->onlyMethods(['unmap']) ->disableOriginalConstructor() ->getMock(); - $access = $this->getAccessMock(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('getGroupMapper') - ->will($this->returnValue($mapper)); + ->willReturn($mapper); - $access->connection = $this->createMock(Connection::class); + $this->initBackend(); + $this->assertTrue($this->groupBackend->deleteGroup('gid')); + } - $ldap = new GroupLDAP($access, $pluginManager); - $this->assertEquals($ldap->deleteGroup('gid'),'result'); - } + public function testDeleteGroupFailing(): void { + $this->expectException(\Exception::class); - /** - * @expectedException \Exception - */ - public function testDeleteGroupFailing() { - /** @var GroupPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions', 'deleteGroup']) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions','addToGroup']) + public function testAddToGroupWithPlugin(): void { + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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); + $this->initBackend(); + $this->assertEquals('result', $this->groupBackend->addToGroup('uid', 'gid')); + } - $ldap = new GroupLDAP($access, $pluginManager); - $this->assertEquals($ldap->addToGroup('uid', 'gid'),'result'); - } + public function testAddToGroupFailing(): void { + $this->expectException(\Exception::class); - /** - * @expectedException \Exception - */ - public function testAddToGroupFailing() { - /** @var GroupPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions', 'addToGroup']) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions','removeFromGroup']) + public function testRemoveFromGroupWithPlugin(): void { + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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); + $this->initBackend(); + $this->assertEquals('result', $this->groupBackend->removeFromGroup('uid', 'gid')); + } - $ldap = new GroupLDAP($access, $pluginManager); - $this->assertEquals($ldap->removeFromGroup('uid', 'gid'),'result'); - } + public function testRemoveFromGroupFailing(): void { + $this->expectException(\Exception::class); - /** - * @expectedException \Exception - */ - public function testRemoveFromGroupFailing() { - /** @var GroupPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions', 'removeFromGroup']) + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions','getGroupDetails']) + public function testGetGroupDetailsWithPlugin(): void { + /** @var GroupPluginManager|MockObject $pluginManager */ + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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('result', $this->groupBackend->getGroupDetails('gid')); } - /** - * @expectedException \Exception - */ - public function testGetGroupDetailsFailing() { - /** @var GroupPluginManager|\PHPUnit_Framework_MockObject_MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\GroupPluginManager') - ->setMethods(['implementsActions', 'getGroupDetails']) + public function testGetGroupDetailsFailing(): void { + $this->expectException(\Exception::class); + + $this->pluginManager = $this->getMockBuilder(GroupPluginManager::class) + ->onlyMethods(['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); + $this->initBackend(); + $this->groupBackend->getGroupDetails('gid'); + } - $ldap = new GroupLDAP($access, $pluginManager); + public static function groupMemberProvider(): array { + $base = 'dc=species,dc=earth'; + + $birdsDn = [ + 'uid=3723,' . $base, + 'uid=8372,' . $base, + 'uid=8427,' . $base, + 'uid=2333,' . $base, + 'uid=4754,' . $base, + ]; + $birdsUid = [ + '3723', + '8372', + '8427', + '2333', + '4754', + ]; + $animalsDn = [ + 'uid=lion,' . $base, + 'uid=tiger,' . $base, + ]; + $plantsDn = [ + 'uid=flower,' . $base, + 'uid=tree,' . $base, + ]; + $thingsDn = [ + 'uid=thing1,' . $base, + 'uid=thing2,' . $base, + ]; - $ldap->getGroupDetails('gid'); - } + return [ + [ #0 – test DNs + ['cn=Birds,' . $base => $birdsDn], + ['cn=Birds,' . $base => $birdsDn] + ], + [ #1 – test uids + ['cn=Birds,' . $base => $birdsUid], + ['cn=Birds,' . $base => $birdsUid] + ], + [ #2 – test simple nested group + ['cn=Animals,' . $base => array_merge($birdsDn, $animalsDn)], + [ + 'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn), + 'cn=Birds,' . $base => $birdsDn, + ] + ], + [ #3 – test recursive nested group + [ + 'cn=Animals,' . $base => array_merge($birdsDn, $animalsDn), + 'cn=Birds,' . $base => array_merge($birdsDn, $animalsDn), + ], + [ + 'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base,'cn=Birds,' . $base,'cn=Animals,' . $base], $animalsDn), + 'cn=Birds,' . $base => array_merge(['cn=Animals,' . $base,'cn=Birds,' . $base], $birdsDn), + ] + ], + [ #4 – Complicated nested group + ['cn=Things,' . $base => array_merge($birdsDn, $animalsDn, $thingsDn, $plantsDn)], + [ + 'cn=Animals,' . $base => array_merge(['cn=Birds,' . $base], $animalsDn), + 'cn=Birds,' . $base => $birdsDn, + 'cn=Plants,' . $base => $plantsDn, + 'cn=Things,' . $base => array_merge(['cn=Animals,' . $base,'cn=Plants,' . $base], $thingsDn), + ] + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('groupMemberProvider')] + public function testGroupMembers(array $expectedResult, array $groupsInfo): void { + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturnCallback(function ($group) use ($groupsInfo) { + if (isset($groupsInfo[$group])) { + return $groupsInfo[$group]; + } + return []; + }); + + $this->access->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function (string $name) { + if ($name === 'ldapNestedGroups') { + return 1; + } elseif ($name === 'ldapGroupMemberAssocAttr') { + return 'attr'; + } + return null; + }); + $this->initBackend(); + foreach ($expectedResult as $groupDN => $expectedMembers) { + $resultingMembers = $this->invokePrivate($this->groupBackend, '_groupMembers', [$groupDN]); + + sort($expectedMembers); + sort($resultingMembers); + $this->assertEquals($expectedMembers, $resultingMembers); + } + } + + public static function displayNameProvider(): array { + return [ + ['Graphic Novelists', ['Graphic Novelists']], + ['', false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('displayNameProvider')] + public function testGetDisplayName(string $expected, bool|array $ldapResult): void { + $gid = 'graphic_novelists'; + + $this->access->expects($this->atLeastOnce()) + ->method('readAttribute') + ->willReturn($ldapResult); + + $this->access->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + if ($name === 'ldapGroupMemberAssocAttr') { + return 'member'; + } elseif ($name === 'ldapGroupFilter') { + return 'objectclass=nextcloudGroup'; + } elseif ($name === 'ldapGroupDisplayName') { + return 'cn'; + } + return null; + }); + + $this->access->expects($this->any()) + ->method('groupname2dn') + ->willReturn('fakedn'); + + $this->initBackend(); + $this->assertSame($expected, $this->groupBackend->getDisplayName($gid)); + } } diff --git a/apps/user_ldap/tests/HelperTest.php b/apps/user_ldap/tests/HelperTest.php index 31d17cbaede..adea600d900 100644 --- a/apps/user_ldap/tests/HelperTest.php +++ b/apps/user_ldap/tests/HelperTest.php @@ -1,101 +1,132 @@ <?php + +declare(strict_types=1); /** - * - * - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\User_LDAP\Tests; - use OCA\User_LDAP\Helper; -use OCP\IConfig; +use OCP\IAppConfig; +use OCP\IDBConnection; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +/** + * @group DB + */ class HelperTest extends \Test\TestCase { + private IAppConfig&MockObject $appConfig; - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - private $config; + private Helper $helper; - /** @var Helper */ - private $helper; - - public function setUp() { + protected function setUp(): void { parent::setUp(); - $this->config = $this->createMock(IConfig::class); - $this->helper = new Helper($this->config); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->helper = new Helper( + $this->appConfig, + Server::get(IDBConnection::class) + ); } - public function testGetServerConfigurationPrefixes() { - $this->config->method('getAppKeys') - ->with($this->equalTo('user_ldap')) + public function testGetServerConfigurationPrefixes(): void { + $this->appConfig->method('getKeys') + ->with('user_ldap') ->willReturn([ 'foo', 'ldap_configuration_active', 's1ldap_configuration_active', ]); + $this->appConfig->method('getValueArray') + ->with('user_ldap', 'configuration_prefixes') + -> willReturnArgument(2); + $result = $this->helper->getServerConfigurationPrefixes(false); $this->assertEquals(['', 's1'], $result); } - public function testGetServerConfigurationPrefixesActive() { - $this->config->method('getAppKeys') - ->with($this->equalTo('user_ldap')) + public function testGetServerConfigurationPrefixesActive(): void { + $this->appConfig->method('getKeys') + ->with('user_ldap') ->willReturn([ 'foo', 'ldap_configuration_active', 's1ldap_configuration_active', ]); - $this->config->method('getAppValue') - ->will($this->returnCallback(function($app, $key, $default) { - if ($app !== 'user_ldap') { - $this->fail('wrong app'); - } + $this->appConfig->method('getValueArray') + ->with('user_ldap', 'configuration_prefixes') + -> willReturnArgument(2); + + $this->appConfig->method('getValueString') + ->willReturnCallback(function ($app, $key, $default) { if ($key === 's1ldap_configuration_active') { return '1'; } return $default; - })); + }); $result = $this->helper->getServerConfigurationPrefixes(true); $this->assertEquals(['s1'], $result); } - public function testGetServerConfigurationHost() { - $this->config->method('getAppKeys') - ->with($this->equalTo('user_ldap')) + public function testGetServerConfigurationHostFromAppKeys(): void { + $this->appConfig->method('getKeys') + ->with('user_ldap') ->willReturn([ 'foo', 'ldap_host', 's1ldap_host', 's02ldap_host', + 'ldap_configuration_active', + 's1ldap_configuration_active', + 's02ldap_configuration_active', ]); - $this->config->method('getAppValue') - ->will($this->returnCallback(function($app, $key, $default) { - if ($app !== 'user_ldap') { - $this->fail('wrong app'); + $this->appConfig->method('getValueArray') + ->with('user_ldap', 'configuration_prefixes') + -> willReturnArgument(2); + + $this->appConfig->method('getValueString') + ->willReturnCallback(function ($app, $key, $default) { + if ($key === 'ldap_host') { + return 'example.com'; } + if ($key === 's1ldap_host') { + return 'foo.bar.com'; + } + return $default; + }); + + $result = $this->helper->getServerConfigurationHosts(); + + $this->assertEquals([ + '' => 'example.com', + 's1' => 'foo.bar.com', + 's02' => '', + ], $result); + } + + public function testGetServerConfigurationHost(): void { + $this->appConfig + ->expects(self::never()) + ->method('getKeys'); + + $this->appConfig->method('getValueArray') + ->with('user_ldap', 'configuration_prefixes') + -> willReturn([ + '', + 's1', + 's02', + ]); + + $this->appConfig->method('getValueString') + ->willReturnCallback(function ($app, $key, $default) { if ($key === 'ldap_host') { return 'example.com'; } @@ -103,7 +134,7 @@ class HelperTest extends \Test\TestCase { return 'foo.bar.com'; } return $default; - })); + }); $result = $this->helper->getServerConfigurationHosts(); diff --git a/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php b/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php index 8d29df6ede6..00f8be18586 100644 --- a/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php +++ b/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php @@ -1,44 +1,32 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author root <root@localhost.localdomain> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\LDAP; +use OCA\User_LDAP\GroupPluginManager; use OCA\User_LDAP\Helper; -use OCA\User_LDAP\LogWrapper; +use OCA\User_LDAP\LDAP; use OCA\User_LDAP\User\Manager; +use OCA\User_LDAP\UserPluginManager; +use OCP\IAvatarManager; +use OCP\IConfig; +use OCP\Image; +use OCP\IUserManager; +use OCP\Server; +use OCP\Share\IManager; +use Psr\Log\LoggerInterface; abstract class AbstractIntegrationTest { - /** @var LDAP */ + /** @var LDAP */ protected $ldap; - /** @var Connection */ + /** @var Connection */ protected $connection; /** @var Access */ @@ -46,23 +34,28 @@ abstract class AbstractIntegrationTest { /** @var Manager */ protected $userManager; - + /** @var Helper */ protected $helper; - /** @var string */ - protected $base; - /** @var string[] */ protected $server; - public function __construct($host, $port, $bind, $pwd, $base) { - $this->base = $base; + /** + * @param string $base + */ + public function __construct( + $host, + $port, + $bind, + $pwd, + protected $base, + ) { $this->server = [ 'host' => $host, 'port' => $port, - 'dn' => $bind, - 'pwd' => $pwd + 'dn' => $bind, + 'pwd' => $pwd ]; } @@ -71,11 +64,11 @@ abstract class AbstractIntegrationTest { * the LDAP backend. */ public function init() { - \OC::$server->registerService('LDAPUserPluginManager', function() { - return new \OCA\User_LDAP\UserPluginManager(); + \OC::$server->registerService(UserPluginManager::class, function () { + return new UserPluginManager(); }); - \OC::$server->registerService('LDAPGroupPluginManager', function() { - return new \OCA\User_LDAP\GroupPluginManager(); + \OC::$server->registerService(GroupPluginManager::class, function () { + return new GroupPluginManager(); }); $this->initLDAPWrapper(); @@ -83,7 +76,6 @@ abstract class AbstractIntegrationTest { $this->initUserManager(); $this->initHelper(); $this->initAccess(); - } /** @@ -118,29 +110,28 @@ abstract class AbstractIntegrationTest { */ protected function initUserManager() { $this->userManager = new Manager( - \OC::$server->getConfig(), - new FilesystemHelper(), - new LogWrapper(), - \OC::$server->getAvatarManager(), - new \OCP\Image(), - \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getNotificationManager() + Server::get(IConfig::class), + Server::get(LoggerInterface::class), + Server::get(IAvatarManager::class), + new Image(), + Server::get(IUserManager::class), + Server::get(\OCP\Notification\IManager::class), + Server::get(IManager::class) ); } - + /** * initializes the test Helper */ protected function initHelper() { - $this->helper = new Helper(\OC::$server->getConfig()); + $this->helper = Server::get(Helper::class); } /** * initializes the Access test instance */ protected function initAccess() { - $this->access = new Access($this->connection, $this->ldap, $this->userManager, $this->helper, \OC::$server->getConfig()); + $this->access = new Access($this->connection, $this->ldap, $this->userManager, $this->helper, Server::get(IConfig::class), Server::get(LoggerInterface::class)); } /** @@ -151,23 +142,23 @@ abstract class AbstractIntegrationTest { public function run() { $methods = get_class_methods($this); $atLeastOneCaseRan = false; - foreach($methods as $method) { - if(strpos($method, 'case') === 0) { + foreach ($methods as $method) { + if (str_starts_with($method, 'case')) { print("running $method " . PHP_EOL); try { - if(!$this->$method()) { + if (!$this->$method()) { print(PHP_EOL . '>>> !!! Test ' . $method . ' FAILED !!! <<<' . PHP_EOL . PHP_EOL); exit(1); } $atLeastOneCaseRan = true; - } catch(\Exception $e) { + } catch (\Exception $e) { print(PHP_EOL . '>>> !!! Test ' . $method . ' RAISED AN EXCEPTION !!! <<<' . PHP_EOL); print($e->getMessage() . PHP_EOL . PHP_EOL); exit(1); } } } - if($atLeastOneCaseRan) { + if ($atLeastOneCaseRan) { print('Tests succeeded' . PHP_EOL); } else { print('No Test was available.' . PHP_EOL); diff --git a/apps/user_ldap/tests/Integration/Bootstrap.php b/apps/user_ldap/tests/Integration/Bootstrap.php index 46299098ab2..ef0909d4bea 100644 --- a/apps/user_ldap/tests/Integration/Bootstrap.php +++ b/apps/user_ldap/tests/Integration/Bootstrap.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - define('CLI_TEST_RUN', true); -require_once __DIR__ . '/../../../../lib/base.php'; +require_once __DIR__ . '/../../../../lib/base.php'; require_once __DIR__ . '/setup-scripts/config.php'; diff --git a/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php b/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php index 32dfb72d9c1..3eec3df675a 100644 --- a/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php +++ b/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php @@ -1,32 +1,16 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration; - use OC\ServerNotAvailableException; use OCA\User_LDAP\LDAP; +use OCP\App\IAppManager; +use OCP\Server; /** * Class ExceptionOnLostConnection @@ -35,48 +19,33 @@ use OCA\User_LDAP\LDAP; * * LDAP must be available via toxiproxy. * - * This test must be run manually. + * This test must be run manually. * */ class ExceptionOnLostConnection { - /** @var string */ - private $toxiProxyHost; - - /** @var string */ - private $toxiProxyName; - - /** @var string */ - private $ldapBase; - - /** @var string|null */ - private $ldapBindDN; - - /** @var string|null */ - private $ldapBindPwd; - - /** @var string */ + /** @var string */ private $ldapHost; - /** @var \OCA\User_LDAP\LDAP */ + /** @var LDAP */ private $ldap; - /** @var bool */ + /** @var bool */ private $originalProxyState; /** - * @param string $proxyHost host of toxiproxy as url, like http://localhost:8474 - * @param string $proxyName name of the LDAP proxy service as configured in toxiProxy + * @param string $toxiProxyHost host of toxiproxy as url, like http://localhost:8474 + * @param string $toxiProxyName name of the LDAP proxy service as configured in toxiProxy * @param string $ldapBase any valid LDAP base DN - * @param null $bindDN optional, bind DN if anonymous bind is not possible - * @param null $bindPwd optional + * @param null $ldapBindDN optional, bind DN if anonymous bind is not possible + * @param null $ldapBindPwd optional */ - public function __construct($proxyHost, $proxyName, $ldapBase, $bindDN = null, $bindPwd = null) { - $this->toxiProxyHost = $proxyHost; - $this->toxiProxyName = $proxyName; - $this->ldapBase = $ldapBase; - $this->ldapBindDN = $bindDN; - $this->ldapBindPwd = $bindPwd; - + public function __construct( + private $toxiProxyHost, + private $toxiProxyName, + private $ldapBase, + private $ldapBindDN = null, + private $ldapBindPwd = null, + ) { $this->setUp(); } @@ -94,9 +63,9 @@ class ExceptionOnLostConnection { * * @throws \Exception */ - public function setUp() { - require_once __DIR__ . '/../../../../lib/base.php'; - \OC_App::loadApps('user_ldap'); + public function setUp(): void { + require_once __DIR__ . '/../../../../lib/base.php'; + Server::get(IAppManager::class)->loadApps(['user_ldap']); $ch = $this->getCurl(); $proxyInfoJson = curl_exec($ch); @@ -112,7 +81,7 @@ class ExceptionOnLostConnection { * restores original state of the LDAP proxy, if necessary */ public function cleanUp() { - if($this->originalProxyState === true) { + if ($this->originalProxyState === true) { $this->setProxyState(true); } } @@ -122,23 +91,23 @@ class ExceptionOnLostConnection { * fail */ public function run() { - if($this->originalProxyState === false) { + if ($this->originalProxyState === false) { $this->setProxyState(true); } //host contains port, 2nd parameter will be ignored $cr = $this->ldap->connect($this->ldapHost, 0); $this->ldap->bind($cr, $this->ldapBindDN, $this->ldapBindPwd); - $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', array('dn'), true, 5); + $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', ['dn'], true, 5); // disable LDAP, will cause lost connection $this->setProxyState(false); try { - $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', array('dn'), true, 5); + $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', ['dn'], true, 5); } catch (ServerNotAvailableException $e) { - print("Test PASSED" . PHP_EOL); + print('Test PASSED' . PHP_EOL); exit(0); } - print("Test FAILED" . PHP_EOL); + print('Test FAILED' . PHP_EOL); exit(1); } @@ -146,12 +115,12 @@ class ExceptionOnLostConnection { * tests whether a curl operation ran successfully. If not, an exception * is thrown * - * @param resource $ch + * @param resource|\CurlHandle $ch * @param mixed $result * @throws \Exception */ private function checkCurlResult($ch, $result) { - if($result === false) { + if ($result === false) { $error = curl_error($ch); curl_close($ch); throw new \Exception($error); @@ -165,16 +134,16 @@ class ExceptionOnLostConnection { * @throws \Exception */ private function setProxyState($isEnabled) { - if(!is_bool($isEnabled)) { + if (!is_bool($isEnabled)) { throw new \InvalidArgumentException('Bool expected'); } $postData = json_encode(['enabled' => $isEnabled]); $ch = $this->getCurl(); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); - curl_setopt($ch, CURLOPT_HTTPHEADER, array( - 'Content-Type: application/json', - 'Content-Length: ' . strlen($postData)) + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($postData)] ); $recvd = curl_exec($ch); $this->checkCurlResult($ch, $recvd); @@ -182,7 +151,7 @@ class ExceptionOnLostConnection { /** * initializes a curl handler towards the toxiproxy LDAP proxy service - * @return resource + * @return resource|\CurlHandle */ private function getCurl() { $ch = curl_init(); @@ -195,4 +164,3 @@ class ExceptionOnLostConnection { $test = new ExceptionOnLostConnection('http://localhost:8474', 'ldap', 'dc=owncloud,dc=bzoc'); $test->run(); - diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAccessGroupsMatchFilter.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAccessGroupsMatchFilter.php deleted file mode 100644 index 87c2e408424..00000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAccessGroupsMatchFilter.php +++ /dev/null @@ -1,127 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestAccessGroupsMatchFilter extends AbstractIntegrationTest { - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - require(__DIR__ . '/../setup-scripts/createExplicitGroups.php'); - require(__DIR__ . '/../setup-scripts/createExplicitGroupsDifferentOU.php'); - parent::init(); - } - - /** - * tests whether the group filter works with one specific group, while the - * input is the same. - * - * @return bool - */ - protected function case1() { - $this->connection->setConfiguration(['ldapGroupFilter' => 'cn=RedGroup']); - - $dns = ['cn=RedGroup,ou=Groups,' . $this->base]; - $result = $this->access->groupsMatchFilter($dns); - return ($dns === $result); - } - - /** - * Tests whether a filter for limited groups is effective when more existing - * groups were passed for validation. - * - * @return bool - */ - protected function case2() { - $this->connection->setConfiguration(['ldapGroupFilter' => '(|(cn=RedGroup)(cn=PurpleGroup))']); - - $dns = [ - 'cn=RedGroup,ou=Groups,' . $this->base, - 'cn=BlueGroup,ou=Groups,' . $this->base, - 'cn=PurpleGroup,ou=Groups,' . $this->base - ]; - $result = $this->access->groupsMatchFilter($dns); - - $status = - count($result) === 2 - && in_array('cn=RedGroup,ou=Groups,' . $this->base, $result) - && in_array('cn=PurpleGroup,ou=Groups,' . $this->base, $result); - - return $status; - } - - /** - * Tests whether a filter for limited groups is effective when more existing - * groups were passed for validation. - * - * @return bool - */ - protected function case3() { - $this->connection->setConfiguration(['ldapGroupFilter' => '(objectclass=groupOfNames)']); - - $dns = [ - 'cn=RedGroup,ou=Groups,' . $this->base, - 'cn=PurpleGroup,ou=Groups,' . $this->base, - 'cn=SquaredCircleGroup,ou=SpecialGroups,' . $this->base - ]; - $result = $this->access->groupsMatchFilter($dns); - - $status = - count($result) === 2 - && in_array('cn=RedGroup,ou=Groups,' . $this->base, $result) - && in_array('cn=PurpleGroup,ou=Groups,' . $this->base, $result); - - return $status; - } - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - parent::initConnection(); - $this->connection->setConfiguration([ - 'ldapBaseGroups' => 'ou=Groups,' . $this->base, - 'ldapUserFilter' => 'objectclass=inetOrgPerson', - 'ldapUserDisplayName' => 'displayName', - 'ldapGroupDisplayName' => 'cn', - 'ldapLoginFilter' => 'uid=%uid', - ]); - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestAccessGroupsMatchFilter($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php index 0238d68f59f..e1529384239 100644 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php +++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php @@ -1,34 +1,25 @@ <?php + /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - -namespace OCA\user_ldap\tests\Integration\Lib; +namespace OCA\User_LDAP\Tests\Integration\Lib; use OCA\User_LDAP\Group_LDAP; +use OCA\User_LDAP\GroupPluginManager; use OCA\User_LDAP\Mapping\GroupMapping; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User_LDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUserManager; +use OCP\Server; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../Bootstrap.php'; @@ -42,28 +33,28 @@ class IntegrationTestAttributeDetection extends AbstractIntegrationTest { $this->connection->setConfiguration(['ldapGroupFilter' => 'objectClass=groupOfNames']); $this->connection->setConfiguration(['ldapGroupMemberAssocAttr' => 'member']); - $userMapper = new UserMapping(\OC::$server->getDatabaseConnection()); + $userMapper = new UserMapping(Server::get(IDBConnection::class)); $userMapper->clear(); $this->access->setUserMapper($userMapper); - $groupMapper = new GroupMapping(\OC::$server->getDatabaseConnection()); + $groupMapper = new GroupMapping(Server::get(IDBConnection::class)); $groupMapper->clear(); $this->access->setGroupMapper($groupMapper); - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); - $userManager = \OC::$server->getUserManager(); + $userBackend = new User_LDAP($this->access, Server::get(\OCP\Notification\IManager::class), Server::get(UserPluginManager::class), Server::get(LoggerInterface::class), Server::get(DeletedUsersIndex::class)); + $userManager = Server::get(IUserManager::class); $userManager->clearBackends(); $userManager->registerBackend($userBackend); - $groupBackend = new Group_LDAP($this->access, \OC::$server->query('LDAPGroupPluginManager')); - $groupManger = \OC::$server->getGroupManager(); + $groupBackend = new Group_LDAP($this->access, Server::get(GroupPluginManager::class), Server::get(IConfig::class)); + $groupManger = Server::get(IGroupManager::class); $groupManger->clearBackends(); $groupManger->addBackend($groupBackend); } protected function caseNativeUUIDAttributeUsers() { // trigger importing of users which also triggers UUID attribute detection - \OC::$server->getUserManager()->search('', 5, 0); + Server::get(IUserManager::class)->search('', 5, 0); return $this->connection->ldapUuidUserAttribute === 'entryuuid'; } @@ -72,7 +63,7 @@ class IntegrationTestAttributeDetection extends AbstractIntegrationTest { // are similar, but we take no chances. // trigger importing of users which also triggers UUID attribute detection - \OC::$server->getGroupManager()->search('', 5, 0); + Server::get(IGroupManager::class)->search('', 5, 0); return $this->connection->ldapUuidGroupAttribute === 'entryuuid'; } } diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestBackupServer.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestBackupServer.php deleted file mode 100644 index 0eef5507538..00000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestBackupServer.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OC\ServerNotAvailableException; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User_LDAP; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestBackupServer extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** @var User_LDAP */ - protected $backend; - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - parent::initConnection(); - $originalHost = $this->connection->ldapHost; - $originalPort = $this->connection->ldapPort; - $this->connection->setConfiguration([ - 'ldapHost' => 'qwertz.uiop', - 'ldapPort' => '32123', - 'ldap_backup_host' => $originalHost, - 'ldap_backup_port' => $originalPort, - ]); - } - - /** - * tests that a backup connection is being used when the main LDAP server - * is offline - * - * Beware: after starting docker, the LDAP host might not be ready yet, thus - * causing a false positive. Retry in that case… or increase the sleep time - * in run-test.sh - * - * @return bool - */ - protected function case1() { - try { - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return false; - } - return true; - } - - /** - * ensures that an exception is thrown if LDAP main server and LDAP backup - * server are not available - * - * @return bool - */ - protected function case2() { - // reset possible LDAP connection - $this->initConnection(); - try { - $this->connection->setConfiguration([ - 'ldap_backup_host' => 'qwertz.uiop', - 'ldap_backup_port' => '32123', - ]); - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return true; - } - return false; - } - - /** - * ensures that an exception is thrown if main LDAP server is down and a - * backup server is not given - * - * @return bool - */ - protected function case3() { - // reset possible LDAP connection - $this->initConnection(); - try { - $this->connection->setConfiguration([ - 'ldap_backup_host' => '', - 'ldap_backup_port' => '', - ]); - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return true; - } - return false; - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestBackupServer($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestBatchApplyUserAttributes.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestBatchApplyUserAttributes.php deleted file mode 100644 index 24476c9a868..00000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestBatchApplyUserAttributes.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestBatchApplyUserAttributes extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - require(__DIR__ . '/../setup-scripts/createUsersWithoutDisplayName.php'); - parent::init(); - - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); - $this->mapping->clear(); - $this->access->setUserMapper($this->mapping); - } - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - parent::initConnection(); - $this->connection->setConfiguration([ - 'ldapUserDisplayName' => 'displayname', - ]); - } - - /** - * indirectly tests whether batchApplyUserAttributes does it job properly, - * when a user without display name is included in the result set from LDAP. - * - * @return bool - */ - protected function case1() { - $result = $this->access->fetchListOfUsers('objectclass=person', 'dn'); - // on the original issue, PHP would emit a fatal error - // – cannot catch it here, but will render the test as unsuccessful - return is_array($result) && !empty($result); - } - -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestBatchApplyUserAttributes($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestConnect.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestConnect.php deleted file mode 100644 index f4fc0f189b4..00000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestConnect.php +++ /dev/null @@ -1,172 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OC\ServerNotAvailableException; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User_LDAP; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestConnect extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** @var User_LDAP */ - protected $backend; - - /** @var string */ - protected $host; - - /** @var int */ - protected $port; - - public function __construct($host, $port, $bind, $pwd, $base) { - // make sure host is a simple host name - if(strpos($host, '://') !== false) { - $host = substr_replace($host, '', 0, strpos($host, '://') + 3); - } - if(strpos($host, ':') !== false) { - $host = substr_replace($host, '', strpos($host, ':')); - } - $this->host = $host; - $this->port = $port; - parent::__construct($host, $port, $bind, $pwd, $base); - } - - /** - * test that a faulty host will does not connect successfully - * - * @return bool - */ - protected function case1() { - // reset possible LDAP connection - $this->initConnection(); - $this->connection->setConfiguration([ - 'ldapHost' => 'qwertz.uiop', - ]); - try { - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return true; - } - return false; - } - - /** - * tests that a connect succeeds when only a hostname is provided - * - * @return bool - */ - protected function case2() { - // reset possible LDAP connection - $this->initConnection(); - $this->connection->setConfiguration([ - 'ldapHost' => $this->host, - ]); - try { - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return false; - } - return true; - } - - /** - * tests that a connect succeeds when an LDAP URL is provided - * - * @return bool - */ - protected function case3() { - // reset possible LDAP connection - $this->initConnection(); - $this->connection->setConfiguration([ - 'ldapHost' => 'ldap://' . $this->host, - ]); - try { - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return false; - } - return true; - } - - /** - * tests that a connect succeeds when an LDAP URL with port is provided - * - * @return bool - */ - protected function case4() { - // reset possible LDAP connection - $this->initConnection(); - $this->connection->setConfiguration([ - 'ldapHost' => 'ldap://' . $this->host . ':' . $this->port, - ]); - try { - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return false; - } - return true; - } - - /** - * tests that a connect succeeds when a hostname with port is provided - * - * @return bool - */ - protected function case5() { - // reset possible LDAP connection - $this->initConnection(); - $this->connection->setConfiguration([ - 'ldapHost' => $this->host . ':' . $this->port, - ]); - try { - $this->connection->getConnectionResource(); - } catch (ServerNotAvailableException $e) { - return false; - } - return true; - } - - /** - * repeat case1, only to make sure that not a connection was reused by - * accident. - * - * @return bool - */ - protected function case6() { - return $this->case1(); - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestConnect($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php index ebbe2197504..8a1093e4304 100644 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php +++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php @@ -1,26 +1,10 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration\Lib; use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php index cab5f6196fd..1c2d7145ddf 100644 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php +++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php @@ -1,37 +1,25 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration\Lib; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User_LDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\IDBConnection; +use OCP\Server; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../Bootstrap.php'; class IntegrationTestFetchUsersByLoginName extends AbstractIntegrationTest { - /** @var UserMapping */ + /** @var UserMapping */ protected $mapping; /** @var User_LDAP */ @@ -45,10 +33,10 @@ class IntegrationTestFetchUsersByLoginName extends AbstractIntegrationTest { require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); + $this->mapping = new UserMapping(Server::get(IDBConnection::class)); $this->mapping->clear(); $this->access->setUserMapper($this->mapping); - $this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); + $this->backend = new User_LDAP($this->access, Server::get(\OCP\Notification\IManager::class), Server::get(UserPluginManager::class), Server::get(LoggerInterface::class), Server::get(DeletedUsersIndex::class)); } /** @@ -72,7 +60,6 @@ class IntegrationTestFetchUsersByLoginName extends AbstractIntegrationTest { $result = $this->access->fetchUsersByLoginName('alice'); return count($result) === 1; } - } /** @var string $host */ diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php index d54d001c4ad..3e21d22fca3 100644 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php +++ b/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php @@ -1,37 +1,24 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration\Lib; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User_LDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\Server; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../Bootstrap.php'; class IntegrationTestPaging extends AbstractIntegrationTest { - /** @var UserMapping */ + /** @var UserMapping */ protected $mapping; /** @var User_LDAP */ @@ -48,7 +35,7 @@ class IntegrationTestPaging extends AbstractIntegrationTest { require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); parent::init(); - $this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); + $this->backend = new User_LDAP($this->access, Server::get(\OCP\Notification\IManager::class), Server::get(UserPluginManager::class), Server::get(LoggerInterface::class), Server::get(DeletedUsersIndex::class)); } public function initConnection() { @@ -59,29 +46,11 @@ class IntegrationTestPaging extends AbstractIntegrationTest { } /** - * tests that paging works properly against a simple example (reading all - * of few users in small steps) - * - * @return bool - */ - protected function case1() { - $filter = 'objectclass=inetorgperson'; - $attributes = ['cn', 'dn']; - - $result = $this->access->searchUsers($filter, $attributes); - if(count($result) === 7) { - return true; - } - - return false; - } - - /** * fetch first three, afterwards all users * * @return bool */ - protected function case2() { + protected function case1() { $filter = 'objectclass=inetorgperson'; $attributes = ['cn', 'dn']; @@ -91,34 +60,17 @@ class IntegrationTestPaging extends AbstractIntegrationTest { // the result will be 4, because the highest possible paging size // is 2 (as configured). // But also with more than one search base, the limit can be outpaced. - if(count($result) !== 4) { + if (count($result) !== 4) { return false; } $result = $this->access->searchUsers($filter, $attributes); - if(count($result) !== 7) { + if (count($result) !== 7) { return false; } return true; } - - /** - * reads all remaining users starting first page - * - * @return bool - */ - protected function case3() { - $filter = 'objectclass=inetorgperson'; - $attributes = ['cn', 'dn']; - - $result = $this->access->searchUsers($filter, $attributes, null, $this->pagingSize); - if(count($result) === (7 - $this->pagingSize)) { - return true; - } - - return false; - } } /** @var string $host */ diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php deleted file mode 100644 index 9ee5a7efac2..00000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestUserHome.php +++ /dev/null @@ -1,186 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\Manager as LDAPUserManager; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User_LDAP; -use OCP\Image; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestUserHome extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** @var User_LDAP */ - protected $backend; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - parent::init(); - - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); - $this->mapping->clear(); - $this->access->setUserMapper($this->mapping); - $this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); - } - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - parent::initConnection(); - $this->connection->setConfiguration([ - 'homeFolderNamingRule' => 'homeDirectory', - ]); - } - - /** - * initializes an LDAP user manager instance - * @return LDAPUserManager - */ - protected function initUserManager() { - $this->userManager = new LDAPUserManager( - \OC::$server->getConfig(), - new FilesystemHelper(), - new LogWrapper(), - \OC::$server->getAvatarManager(), - new Image(), - \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getNotificationManager() - ); - } - - /** - * homeDirectory on LDAP is empty. Return values of getHome should be - * identical to user name, following Nextcloud default. - * - * @return bool - */ - protected function case1() { - \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', false); - $userManager = \OC::$server->getUserManager(); - $userManager->clearBackends(); - $userManager->registerBackend($this->backend); - $users = $userManager->search('', 5, 0); - - foreach($users as $user) { - $home = $user->getHome(); - $uid = $user->getUID(); - $posFound = strpos($home, '/' . $uid); - $posExpected = strlen($home) - (strlen($uid) + 1); - if($posFound === false || $posFound !== $posExpected) { - print('"' . $user->getUID() . '" was not found in "' . $home . '" or does not end with it.' . PHP_EOL); - return false; - } - } - - return true; - } - - /** - * homeDirectory on LDAP is empty. Having the attributes set is enforced. - * - * @return bool - */ - protected function case2() { - \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', true); - $userManager = \OC::$server->getUserManager(); - // clearing backends is critical, otherwise the userManager will have - // the user objects cached and the value from case1 returned - $userManager->clearBackends(); - $userManager->registerBackend($this->backend); - $users = $userManager->search('', 5, 0); - - try { - foreach ($users as $user) { - $user->getHome(); - print('User home was retrieved without throwing an Exception!' . PHP_EOL); - return false; - } - } catch (\Exception $e) { - if(strpos($e->getMessage(), 'Home dir attribute') === 0) { - return true; - } - } - - return false; - } - - /** - * homeDirectory on LDAP is set to "attr:" which is effectively empty. - * Return values of getHome should be Nextcloud default. - * - * @return bool - */ - protected function case3() { - \OC::$server->getConfig()->setAppValue('user_ldap', 'enforce_home_folder_naming_rule', true); - $this->connection->setConfiguration([ - 'homeFolderNamingRule' => 'attr:', - ]); - $userManager = \OC::$server->getUserManager(); - $userManager->clearBackends(); - $userManager->registerBackend($this->backend); - $users = $userManager->search('', 5, 0); - - try { - foreach ($users as $user) { - $home = $user->getHome(); - $uid = $user->getUID(); - $posFound = strpos($home, '/' . $uid); - $posExpected = strlen($home) - (strlen($uid) + 1); - if ($posFound === false || $posFound !== $posExpected) { - print('"' . $user->getUID() . '" was not found in "' . $home . '" or does not end with it.' . PHP_EOL); - return false; - } - } - } catch (\Exception $e) { - print("Unexpected Exception: " . $e->getMessage() . PHP_EOL); - return false; - } - - return true; - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestUserHome($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php index 599458a9721..6726143a449 100644 --- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php +++ b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php @@ -1,45 +1,31 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roger Szabo <roger.szabo@web.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration\Lib\User; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\Manager; -use OCA\User_LDAP\User\User; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; +use OCA\User_LDAP\User\DeletedUsersIndex; +use OCA\User_LDAP\User\Manager; +use OCA\User_LDAP\User\User; use OCA\User_LDAP\User_LDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\IAvatarManager; +use OCP\IConfig; +use OCP\IDBConnection; use OCP\Image; +use OCP\IUserManager; +use OCP\Server; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../../Bootstrap.php'; class IntegrationTestUserAvatar extends AbstractIntegrationTest { - /** @var UserMapping */ + /** @var UserMapping */ protected $mapping; /** @@ -49,11 +35,11 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest { public function init() { require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php'); parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); + $this->mapping = new UserMapping(Server::get(IDBConnection::class)); $this->mapping->clear(); $this->access->setUserMapper($this->mapping); - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); - \OC_User::useBackend($userBackend); + $userBackend = new User_LDAP($this->access, Server::get(\OCP\Notification\IManager::class), Server::get(UserPluginManager::class), Server::get(LoggerInterface::class), Server::get(DeletedUsersIndex::class)); + Server::get(IUserManager::class)->registerBackend($userBackend); } /** @@ -75,9 +61,9 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest { \OC_Util::tearDownFS(); \OC_Util::setupFS($username); \OC::$server->getUserFolder($username); - \OC::$server->getConfig()->deleteUserValue($username, 'user_ldap', User::USER_PREFKEY_LASTREFRESH); - if(\OC::$server->getAvatarManager()->getAvatar($username)->exists()) { - \OC::$server->getAvatarManager()->getAvatar($username)->remove(); + Server::get(IConfig::class)->deleteUserValue($username, 'user_ldap', User::USER_PREFKEY_LASTREFRESH); + if (Server::get(IAvatarManager::class)->getAvatar($username)->exists()) { + Server::get(IAvatarManager::class)->getAvatar($username)->remove(); } // finally attempt to get the avatar set @@ -97,7 +83,7 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest { $this->execFetchTest($dn, $username, $image); - return \OC::$server->getAvatarManager()->getAvatar($username)->exists(); + return Server::get(IAvatarManager::class)->getAvatar($username)->exists(); } /** @@ -114,7 +100,7 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest { $this->execFetchTest($dn, $username, $image); - return !\OC::$server->getAvatarManager()->getAvatar($username)->exists(); + return !Server::get(IAvatarManager::class)->getAvatar($username)->exists(); } /** @@ -131,14 +117,13 @@ class IntegrationTestUserAvatar extends AbstractIntegrationTest { protected function initUserManager() { $this->userManager = new Manager( - \OC::$server->getConfig(), - new FilesystemHelper(), - new LogWrapper(), - \OC::$server->getAvatarManager(), + Server::get(IConfig::class), + Server::get(LoggerInterface::class), + Server::get(IAvatarManager::class), new Image(), - \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getNotificationManager() + Server::get(IDBConnection::class), + Server::get(IUserManager::class), + Server::get(\OCP\Notification\IManager::class) ); } diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php index 0d072bcf973..9b05298a151 100644 --- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php +++ b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php @@ -1,38 +1,27 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration\Lib\User; -use OC\User\NoUserException; use OCA\User_LDAP\Jobs\CleanUp; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User_LDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\Server; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../../Bootstrap.php'; class IntegrationTestUserCleanUp extends AbstractIntegrationTest { - /** @var UserMapping */ + /** @var UserMapping */ protected $mapping; /** @@ -42,12 +31,12 @@ class IntegrationTestUserCleanUp extends AbstractIntegrationTest { public function init() { require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php'); parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); + $this->mapping = new UserMapping(Server::get(IDBConnection::class)); $this->mapping->clear(); $this->access->setUserMapper($this->mapping); - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); - \OC_User::useBackend($userBackend); + $userBackend = new User_LDAP($this->access, Server::get(\OCP\Notification\IManager::class), Server::get(UserPluginManager::class), Server::get(LoggerInterface::class), Server::get(DeletedUsersIndex::class)); + Server::get(IUserManager::class)->registerBackend($userBackend); } /** @@ -84,13 +73,13 @@ class IntegrationTestUserCleanUp extends AbstractIntegrationTest { // user instance must not be requested from global user manager, before // it is deleted from the LDAP server. The instance will be returned // from cache and may false-positively confirm the correctness. - $user = \OC::$server->getUserManager()->get($username); - if($user === null) { + $user = Server::get(IUserManager::class)->get($username); + if ($user === null) { return false; } $user->delete(); - return null === \OC::$server->getUserManager()->get($username); + return Server::get(IUserManager::class)->get($username) === null; } } diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php index 476bc8e7596..6fbfd9ba51b 100644 --- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php +++ b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php @@ -1,37 +1,26 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Integration\Lib\User; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User_LDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\Server; +use Psr\Log\LoggerInterface; require_once __DIR__ . '/../../Bootstrap.php'; class IntegrationTestUserDisplayName extends AbstractIntegrationTest { - /** @var UserMapping */ + /** @var UserMapping */ protected $mapping; /** @@ -41,11 +30,11 @@ class IntegrationTestUserDisplayName extends AbstractIntegrationTest { public function init() { require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php'); parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); + $this->mapping = new UserMapping(Server::get(IDBConnection::class)); $this->mapping->clear(); $this->access->setUserMapper($this->mapping); - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query('LDAPUserPluginManager')); - \OC_User::useBackend($userBackend); + $userBackend = new User_LDAP($this->access, Server::get(\OCP\Notification\IManager::class), Server::get(UserPluginManager::class), Server::get(LoggerInterface::class), Server::get(DeletedUsersIndex::class)); + Server::get(IUserManager::class)->registerBackend($userBackend); } /** @@ -68,9 +57,9 @@ class IntegrationTestUserDisplayName extends AbstractIntegrationTest { $username = 'alice1337'; $dn = 'uid=alice,ou=Users,' . $this->base; $this->prepareUser($dn, $username); - $displayName = \OC::$server->getUserManager()->get($username)->getDisplayName(); + $displayName = Server::get(IUserManager::class)->get($username)->getDisplayName(); - return strpos($displayName, '(Alice@example.com)') !== false; + return str_contains($displayName, '(Alice@example.com)'); } /** @@ -85,9 +74,9 @@ class IntegrationTestUserDisplayName extends AbstractIntegrationTest { $username = 'boris23421'; $dn = 'uid=boris,ou=Users,' . $this->base; $this->prepareUser($dn, $username); - $displayName = \OC::$server->getUserManager()->get($username)->getDisplayName(); + $displayName = Server::get(IUserManager::class)->get($username)->getDisplayName(); - return strpos($displayName, '(Boris@example.com)') === false; + return !str_contains($displayName, '(Boris@example.com)'); } /** diff --git a/apps/user_ldap/tests/Integration/data/avatar-valid.jpg b/apps/user_ldap/tests/Integration/data/avatar-valid.jpg Binary files differindex 61b5ec2e730..451b631eea6 100644 --- a/apps/user_ldap/tests/Integration/data/avatar-valid.jpg +++ b/apps/user_ldap/tests/Integration/data/avatar-valid.jpg diff --git a/apps/user_ldap/tests/Integration/readme.md b/apps/user_ldap/tests/Integration/readme.md index e20efef8fdc..d551387c903 100644 --- a/apps/user_ldap/tests/Integration/readme.md +++ b/apps/user_ldap/tests/Integration/readme.md @@ -1,3 +1,8 @@ +<!-- + - SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + - SPDX-FileCopyrightText: 2015 ownCloud, Inc. + - SPDX-License-Identifier: AGPL-3.0-only + --> # Requirements # Have (as in do copy if not already done) the following files from https://github.com/owncloud/administration/tree/master/ldap-testing copied into the directory "setup-scripts": diff --git a/apps/user_ldap/tests/Integration/run-all.sh b/apps/user_ldap/tests/Integration/run-all.sh index 02bab97e45f..a0739a019eb 100755 --- a/apps/user_ldap/tests/Integration/run-all.sh +++ b/apps/user_ldap/tests/Integration/run-all.sh @@ -1,5 +1,8 @@ #!/bin/bash - +# +# SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +# trigger_notification() { which notify-send 1>/dev/null if [[ $? == 1 ]] ; then diff --git a/apps/user_ldap/tests/Integration/run-test.sh b/apps/user_ldap/tests/Integration/run-test.sh index 7a29db25670..1b674aa04f3 100755 --- a/apps/user_ldap/tests/Integration/run-test.sh +++ b/apps/user_ldap/tests/Integration/run-test.sh @@ -1,5 +1,8 @@ #!/bin/sh - +# +# SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +# if [ $1 ] ; then TESTSCRIPT=$1 else diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php index 597b85020c8..819c4c6e860 100644 --- a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php +++ b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php @@ -1,26 +1,11 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ -if(php_sapi_name() !== 'cli') { +if (php_sapi_name() !== 'cli') { print('Only via CLI, please.'); exit(1); } diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php index b99115074a4..b0a3cd46b4f 100644 --- a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php +++ b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php @@ -1,26 +1,11 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ -if(php_sapi_name() !== 'cli') { +if (php_sapi_name() !== 'cli') { print('Only via CLI, please.'); exit(1); } diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php index b01c498f859..7137bd18a58 100644 --- a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php +++ b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php @@ -1,26 +1,11 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Morris Jobke <hey@morrisjobke.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ -if(php_sapi_name() !== 'cli') { +if (php_sapi_name() !== 'cli') { print('Only via CLI, please.'); exit(1); } diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php b/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php index e08dd798341..18584fbe748 100644 --- a/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php +++ b/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php @@ -1,25 +1,11 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ -if(php_sapi_name() !== 'cli') { +if (php_sapi_name() !== 'cli') { print('Only via CLI, please.'); exit(1); } diff --git a/apps/user_ldap/tests/Jobs/CleanUpTest.php b/apps/user_ldap/tests/Jobs/CleanUpTest.php index 1f30af3a58a..5a1e563a1e8 100644 --- a/apps/user_ldap/tests/Jobs/CleanUpTest.php +++ b/apps/user_ldap/tests/Jobs/CleanUpTest.php @@ -1,68 +1,56 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Jobs; +use Exception; use OCA\User_LDAP\Helper; +use OCA\User_LDAP\Jobs\CleanUp; +use OCA\User_LDAP\User\DeletedUsersIndex; +use OCA\User_LDAP\User_Proxy; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use OCP\IDBConnection; +use Test\TestCase; + +class CleanUpTest extends TestCase { + protected CleanUp $bgJob; + protected array $mocks; + + public function setUp(): void { + parent::setUp(); + $this->createMocks(); + $this->bgJob = new CleanUp($this->mocks['timeFactory'], $this->mocks['userBackend'], $this->mocks['deletedUsersIndex']); + $this->bgJob->setArguments($this->mocks); + } -class CleanUpTest extends \Test\TestCase { - public function getMocks() { - $mocks = array(); - $mocks['userBackend'] = - $this->getMockBuilder('\OCA\User_LDAP\User_Proxy') - ->disableOriginalConstructor() - ->getMock(); - $mocks['deletedUsersIndex'] = - $this->getMockBuilder('\OCA\User_LDAP\User\DeletedUsersIndex') - ->disableOriginalConstructor() - ->getMock(); - $mocks['ocConfig'] = $this->createMock(IConfig::class); - $mocks['db'] = $this->createMock(IDBConnection::class); - $mocks['helper'] = $this->createMock(Helper::class); - - return $mocks; + protected function createMocks(): void { + $this->mocks = []; + $this->mocks['userBackend'] = $this->createMock(User_Proxy::class); + $this->mocks['deletedUsersIndex'] = $this->createMock(DeletedUsersIndex::class); + $this->mocks['ocConfig'] = $this->createMock(IConfig::class); + $this->mocks['db'] = $this->createMock(IDBConnection::class); + $this->mocks['helper'] = $this->createMock(Helper::class); + $this->mocks['timeFactory'] = $this->createMock(ITimeFactory::class); } /** * clean up job must not run when there are disabled configurations */ - public function test_runNotAllowedByDisabledConfigurations() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) + public function test_runNotAllowedByDisabledConfigurations(): void { + $this->mocks['helper']->expects($this->once()) ->method('haveDisabledConfigurations') - ->will($this->returnValue(true) ); + ->willReturn(true); - $args['ocConfig']->expects($this->never()) + $this->mocks['ocConfig']->expects($this->never()) ->method('getSystemValue'); - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); + $result = $this->bgJob->isCleanUpAllowed(); $this->assertSame(false, $result); } @@ -70,87 +58,63 @@ class CleanUpTest extends \Test\TestCase { * clean up job must not run when LDAP Helper is broken i.e. * returning unexpected results */ - public function test_runNotAllowedByBrokenHelper() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) + public function test_runNotAllowedByBrokenHelper(): void { + $this->mocks['helper']->expects($this->once()) ->method('haveDisabledConfigurations') - ->will($this->throwException(new \Exception())); + ->willThrowException(new Exception()); - $args['ocConfig']->expects($this->never()) + $this->mocks['ocConfig']->expects($this->never()) ->method('getSystemValue'); - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); + $result = $this->bgJob->isCleanUpAllowed(); $this->assertSame(false, $result); } /** * clean up job must not run when it is not enabled */ - public function test_runNotAllowedBySysConfig() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) + public function test_runNotAllowedBySysConfig(): void { + $this->mocks['helper']->expects($this->once()) ->method('haveDisabledConfigurations') - ->will($this->returnValue(false)); + ->willReturn(false); - $args['ocConfig']->expects($this->once()) + $this->mocks['ocConfig']->expects($this->once()) ->method('getSystemValue') - ->will($this->returnValue(false)); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); + ->willReturn(false); - $result = $bgJob->isCleanUpAllowed(); + $result = $this->bgJob->isCleanUpAllowed(); $this->assertSame(false, $result); } /** * clean up job is allowed to run */ - public function test_runIsAllowed() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) + public function test_runIsAllowed(): void { + $this->mocks['helper']->expects($this->once()) ->method('haveDisabledConfigurations') - ->will($this->returnValue(false)); + ->willReturn(false); - $args['ocConfig']->expects($this->once()) + $this->mocks['ocConfig']->expects($this->once()) ->method('getSystemValue') - ->will($this->returnValue(true)); + ->willReturn(true); - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); + $result = $this->bgJob->isCleanUpAllowed(); $this->assertSame(true, $result); } /** * check whether offset will be reset when it needs to */ - public function test_OffsetResetIsNecessary() { - $args = $this->getMocks(); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize() - 1); + public function test_OffsetResetIsNecessary(): void { + $result = $this->bgJob->isOffsetResetNecessary($this->bgJob->getChunkSize() - 1); $this->assertSame(true, $result); } /** * make sure offset is not reset when it is not due */ - public function test_OffsetResetIsNotNecessary() { - $args = $this->getMocks(); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize()); + public function test_OffsetResetIsNotNecessary(): void { + $result = $this->bgJob->isOffsetResetNecessary($this->bgJob->getChunkSize()); $this->assertSame(false, $result); } - } - diff --git a/apps/user_ldap/tests/Jobs/SyncTest.php b/apps/user_ldap/tests/Jobs/SyncTest.php index 75ffd0e8280..f6ecf984ab0 100644 --- a/apps/user_ldap/tests/Jobs/SyncTest.php +++ b/apps/user_ldap/tests/Jobs/SyncTest.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests\Jobs; use OCA\User_LDAP\Access; @@ -32,44 +15,37 @@ use OCA\User_LDAP\Jobs\Sync; use OCA\User_LDAP\LDAP; use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\User\Manager; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUserManager; use OCP\Notification\IManager; -use function Sodium\memcmp; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; +/** + * @group DB + */ class SyncTest extends TestCase { - - /** @var array */ - protected $arguments; - /** @var Helper|\PHPUnit_Framework_MockObject_MockObject */ - protected $helper; - /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */ - protected $ldapWrapper; - /** @var Manager|\PHPUnit_Framework_MockObject_MockObject */ - protected $userManager; - /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject */ - protected $mapper; - /** @var Sync */ - protected $sync; - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - protected $config; - /** @var IAvatarManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $avatarManager; - /** @var IDBConnection|\PHPUnit_Framework_MockObject_MockObject */ - protected $dbc; - /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $ncUserManager; - /** @var IManager|\PHPUnit_Framework_MockObject_MockObject */ - protected $notificationManager; - /** @var ConnectionFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $connectionFactory; - /** @var AccessFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $accessFactory; - - public function setUp() { + protected Helper&MockObject $helper; + protected LDAP&MockObject $ldapWrapper; + protected Manager&MockObject $userManager; + protected UserMapping&MockObject $mapper; + protected IConfig&MockObject $config; + protected IAvatarManager&MockObject $avatarManager; + protected IDBConnection&MockObject $dbc; + protected IUserManager&MockObject $ncUserManager; + protected IManager&MockObject $notificationManager; + protected ConnectionFactory&MockObject $connectionFactory; + protected AccessFactory&MockObject $accessFactory; + protected array $arguments = []; + protected Sync $sync; + + protected function setUp(): void { parent::setUp(); $this->helper = $this->createMock(Helper::class); @@ -81,27 +57,32 @@ class SyncTest extends TestCase { $this->dbc = $this->createMock(IDBConnection::class); $this->ncUserManager = $this->createMock(IUserManager::class); $this->notificationManager = $this->createMock(IManager::class); - $this->connectionFactory = $this->createMock(ConnectionFactory::class); + $this->connectionFactory = $this->getMockBuilder(ConnectionFactory::class) + ->setConstructorArgs([ + $this->ldapWrapper, + ]) + ->getMock(); $this->accessFactory = $this->createMock(AccessFactory::class); - $this->arguments = [ - 'helper' => $this->helper, - 'ldapWrapper' => $this->ldapWrapper, - 'userManager' => $this->userManager, - 'mapper' => $this->mapper, - 'config' => $this->config, - 'avatarManager' => $this->avatarManager, - 'dbc' => $this->dbc, - 'ncUserManager' => $this->ncUserManager, - 'notificationManager' => $this->notificationManager, - 'connectionFactory' => $this->connectionFactory, - 'accessFactory' => $this->accessFactory, - ]; - - $this->sync = new Sync(); + $this->sync = new Sync( + Server::get(ITimeFactory::class), + Server::get(IEventDispatcher::class), + $this->config, + $this->dbc, + $this->avatarManager, + $this->ncUserManager, + Server::get(LoggerInterface::class), + $this->notificationManager, + $this->mapper, + $this->helper, + $this->connectionFactory, + $this->accessFactory, + ); + + $this->sync->overwritePropertiesForTest($this->ldapWrapper); } - public function intervalDataProvider() { + public static function intervalDataProvider(): array { return [ [ 0, 1000, 750 @@ -121,14 +102,12 @@ class SyncTest extends TestCase { ]; } - /** - * @dataProvider intervalDataProvider - */ - public function testUpdateInterval($userCount, $pagingSize1, $pagingSize2) { + #[\PHPUnit\Framework\Attributes\DataProvider('intervalDataProvider')] + public function testUpdateInterval(int $userCount, int $pagingSize1, int $pagingSize2): void { $this->config->expects($this->once()) ->method('setAppValue') ->with('user_ldap', 'background_sync_interval', $this->anything()) - ->willReturnCallback(function($a, $k, $interval) { + ->willReturnCallback(function ($a, $k, $interval) { $this->assertTrue($interval >= SYNC::MIN_INTERVAL); $this->assertTrue($interval <= SYNC::MAX_INTERVAL); return true; @@ -154,7 +133,7 @@ class SyncTest extends TestCase { $this->sync->updateInterval(); } - public function moreResultsProvider() { + public static function moreResultsProvider(): array { return [ [ 3, 3, true ], [ 3, 5, true ], @@ -164,33 +143,42 @@ class SyncTest extends TestCase { ]; } - /** - * @dataProvider moreResultsProvider - */ - public function testMoreResults($pagingSize, $results, $expected) { - $connection = $this->createMock(Connection::class); + #[\PHPUnit\Framework\Attributes\DataProvider('moreResultsProvider')] + public function testMoreResults($pagingSize, $results, $expected): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([ + $this->ldapWrapper, + ]) + ->getMock(); $this->connectionFactory->expects($this->any()) ->method('get') ->willReturn($connection); $connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($key) use ($pagingSize) { - if($key === 'ldapPagingSize') { + if ($key === 'ldapPagingSize') { return $pagingSize; } return null; }); - /** @var Access|\PHPUnit_Framework_MockObject_MockObject $access */ + /** @var Access&MockObject $access */ $access = $this->createMock(Access::class); $this->accessFactory->expects($this->any()) ->method('get') ->with($connection) ->willReturn($access); + $this->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); + $access->expects($this->once()) ->method('fetchListOfUsers') ->willReturn(array_pad([], $results, 'someUser')); + $access->expects($this->any()) + ->method('combineFilterWithAnd') + ->willReturn('pseudo=filter'); $access->connection = $connection; $access->userManager = $this->userManager; @@ -199,7 +187,7 @@ class SyncTest extends TestCase { $this->assertSame($expected, $hasMoreResults); } - public function cycleDataProvider() { + public static function cycleDataProvider(): array { $lastCycle = ['prefix' => 's01', 'offset' => 1000]; $lastCycle2 = ['prefix' => '', 'offset' => 1000]; return [ @@ -212,22 +200,24 @@ class SyncTest extends TestCase { ]; } - /** - * @dataProvider cycleDataProvider - */ - public function testDetermineNextCycle($cycleData, $prefixes, $expectedCycle) { + #[\PHPUnit\Framework\Attributes\DataProvider('cycleDataProvider')] + public function testDetermineNextCycle(?array $cycleData, array $prefixes, ?array $expectedCycle): void { $this->helper->expects($this->any()) ->method('getServerConfigurationPrefixes') ->with(true) ->willReturn($prefixes); - if(is_array($expectedCycle)) { + if (is_array($expectedCycle)) { + $calls = [ + ['user_ldap', 'background_sync_prefix', $expectedCycle['prefix']], + ['user_ldap', 'background_sync_offset', $expectedCycle['offset']], + ]; $this->config->expects($this->exactly(2)) ->method('setAppValue') - ->withConsecutive( - ['user_ldap', 'background_sync_prefix', $expectedCycle['prefix']], - ['user_ldap', 'background_sync_offset', $expectedCycle['offset']] - ); + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); } else { $this->config->expects($this->never()) ->method('setAppValue'); @@ -236,7 +226,7 @@ class SyncTest extends TestCase { $this->sync->setArgument($this->arguments); $nextCycle = $this->sync->determineNextCycle($cycleData); - if($expectedCycle === null) { + if ($expectedCycle === null) { $this->assertNull($nextCycle); } else { $this->assertSame($expectedCycle['prefix'], $nextCycle['prefix']); @@ -244,19 +234,19 @@ class SyncTest extends TestCase { } } - public function testQualifiesToRun() { + public function testQualifiesToRun(): void { $cycleData = ['prefix' => 's01']; $this->config->expects($this->exactly(2)) ->method('getAppValue') - ->willReturnOnConsecutiveCalls(time() - 60*40, time() - 60*20); + ->willReturnOnConsecutiveCalls(time() - 60 * 40, time() - 60 * 20); $this->sync->setArgument($this->arguments); $this->assertTrue($this->sync->qualifiesToRun($cycleData)); $this->assertFalse($this->sync->qualifiesToRun($cycleData)); } - public function runDataProvider() { + public static function runDataProvider(): array { return [ #0 - one LDAP server, reset [[ @@ -288,43 +278,46 @@ class SyncTest extends TestCase { ]; } - /** - * @dataProvider runDataProvider - */ - public function testRun($runData) { + #[\PHPUnit\Framework\Attributes\DataProvider('runDataProvider')] + public function testRun(array $runData): void { $this->config->expects($this->any()) ->method('getAppValue') - ->willReturnCallback(function($app, $key, $default) use ($runData) { - if($app === 'core' && $key === 'backgroundjobs_mode') { + ->willReturnCallback(function ($app, $key, $default) use ($runData) { + if ($app === 'core' && $key === 'backgroundjobs_mode') { return 'cron'; } - if($app = 'user_ldap') { + if ($app = 'user_ldap') { // for getCycle() - if($key === 'background_sync_prefix') { + if ($key === 'background_sync_prefix') { return $runData['scheduledCycle']['prefix']; } - if($key === 'background_sync_offset') { + if ($key === 'background_sync_offset') { return $runData['scheduledCycle']['offset']; } // for qualifiesToRun() - if($key === $runData['scheduledCycle']['prefix'] . '_lastChange') { - return time() - 60*40; + if ($key === $runData['scheduledCycle']['prefix'] . '_lastChange') { + return time() - 60 * 40; } // for getMinPagingSize - if($key === $runData['scheduledCycle']['prefix'] . 'ldap_paging_size') { + if ($key === $runData['scheduledCycle']['prefix'] . 'ldap_paging_size') { return $runData['pagingSize']; } } return $default; }); + + $calls = [ + ['user_ldap', 'background_sync_prefix', $runData['expectedNextCycle']['prefix']], + ['user_ldap', 'background_sync_offset', $runData['expectedNextCycle']['offset']], + ['user_ldap', 'background_sync_interval', '43200'], + ]; $this->config->expects($this->exactly(3)) ->method('setAppValue') - ->withConsecutive( - ['user_ldap', 'background_sync_prefix', $runData['expectedNextCycle']['prefix']], - ['user_ldap', 'background_sync_offset', $runData['expectedNextCycle']['offset']], - ['user_ldap', 'background_sync_interval', $this->anything()] - ); + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); $this->config->expects($this->any()) ->method('getAppKeys') ->with('user_ldap') @@ -335,29 +328,40 @@ class SyncTest extends TestCase { ->with(true) ->willReturn($runData['prefixes']); - $connection = $this->createMock(Connection::class); + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([ + $this->ldapWrapper, + ]) + ->getMock(); $this->connectionFactory->expects($this->any()) ->method('get') ->willReturn($connection); $connection->expects($this->any()) ->method('__get') ->willReturnCallback(function ($key) use ($runData) { - if($key === 'ldapPagingSize') { + if ($key === 'ldapPagingSize') { return $runData['pagingSize']; } return null; }); - /** @var Access|\PHPUnit_Framework_MockObject_MockObject $access */ + /** @var Access&MockObject $access */ $access = $this->createMock(Access::class); $this->accessFactory->expects($this->any()) ->method('get') ->with($connection) ->willReturn($access); + $this->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); + $access->expects($this->once()) ->method('fetchListOfUsers') ->willReturn(array_pad([], $runData['usersThisCycle'], 'someUser')); + $access->expects($this->any()) + ->method('combineFilterWithAnd') + ->willReturn('pseudo=filter'); $access->connection = $connection; $access->userManager = $this->userManager; @@ -367,5 +371,4 @@ class SyncTest extends TestCase { $this->sync->run($this->arguments); } - } diff --git a/apps/user_ldap/tests/LDAPGroupPluginDummy.php b/apps/user_ldap/tests/LDAPGroupPluginDummy.php index ac67b526571..5ea1a491f14 100644 --- a/apps/user_ldap/tests/LDAPGroupPluginDummy.php +++ b/apps/user_ldap/tests/LDAPGroupPluginDummy.php @@ -1,34 +1,15 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br) - * - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; - use OCA\User_LDAP\ILDAPGroupPlugin; class LDAPGroupPluginDummy implements ILDAPGroupPlugin { - - public function respondToActions() { return null; } diff --git a/apps/user_ldap/tests/LDAPProviderTest.php b/apps/user_ldap/tests/LDAPProviderTest.php index f3a27dec2c4..57323e374aa 100644 --- a/apps/user_ldap/tests/LDAPProviderTest.php +++ b/apps/user_ldap/tests/LDAPProviderTest.php @@ -1,34 +1,29 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, Roger Szabo (roger.szabo@web.de) - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author root <root@localhost.localdomain> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; +use OC\Config; +use OC\User\Manager; +use OCA\User_LDAP\Access; +use OCA\User_LDAP\Connection; +use OCA\User_LDAP\Group_LDAP; +use OCA\User_LDAP\Helper; use OCA\User_LDAP\IGroupLDAP; +use OCA\User_LDAP\ILDAPWrapper; +use OCA\User_LDAP\IUserLDAP; +use OCA\User_LDAP\LDAPProviderFactory; +use OCA\User_LDAP\User_LDAP; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\IServerContainer; -use OCA\User_LDAP\IUserLDAP; +use OCP\Server; +use Psr\Log\LoggerInterface; /** * Class LDAPProviderTest @@ -38,46 +33,40 @@ use OCA\User_LDAP\IUserLDAP; * @package OCA\User_LDAP\Tests */ class LDAPProviderTest extends \Test\TestCase { - - protected function setUp() { - parent::setUp(); - } - private function getServerMock(IUserLDAP $userBackend, IGroupLDAP $groupBackend) { $server = $this->getMockBuilder('OC\Server') - ->setMethods(['getUserManager', 'getBackends', 'getGroupManager']) - ->setConstructorArgs(['', new \OC\Config(\OC::$configDir)]) - ->getMock(); - $server->expects($this->at(1)) - ->method('getBackends') - ->willReturn([$userBackend]); + ->onlyMethods(['getUserManager', 'getGroupManager']) + ->setConstructorArgs(['', new Config(\OC::$configDir)]) + ->getMock(); $server->expects($this->any()) ->method('getUserManager') ->willReturn($this->getUserManagerMock($userBackend)); $server->expects($this->any()) ->method('getGroupManager') ->willReturn($this->getGroupManagerMock($groupBackend)); - $server->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - + return $server; } private function getUserManagerMock(IUserLDAP $userBackend) { - $userManager = $this->getMockBuilder('OC\User\Manager') - ->setMethods(['getBackends']) - ->setConstructorArgs([$this->createMock(IConfig::class)]) + $userManager = $this->getMockBuilder(Manager::class) + ->onlyMethods(['getBackends']) + ->setConstructorArgs([ + $this->createMock(IConfig::class), + $this->createMock(ICacheFactory::class), + $this->createMock(IEventDispatcher::class), + $this->createMock(LoggerInterface::class), + ]) ->getMock(); $userManager->expects($this->any()) ->method('getBackends') ->willReturn([$userBackend]); return $userManager; } - + private function getGroupManagerMock(IGroupLDAP $groupBackend) { $groupManager = $this->getMockBuilder('OC\Group\Manager') - ->setMethods(['getBackends']) + ->onlyMethods(['getBackends']) ->disableOriginalConstructor() ->getMock(); $groupManager->expects($this->any()) @@ -88,67 +77,69 @@ class LDAPProviderTest extends \Test\TestCase { private function getDefaultGroupBackendMock() { $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->disableOriginalConstructor() + ->disableOriginalConstructor() ->getMock(); - + return $groupBackend; } private function getLDAPProvider(IServerContainer $serverContainer) { - $factory = new \OCA\User_LDAP\LDAPProviderFactory($serverContainer); + $factory = new LDAPProviderFactory($serverContainer); return $factory->getLDAPProvider(); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testGetUserDNUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); + + + public function testGetUserDNUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any())->method('userExists')->willReturn(false); - + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->getUserDN('nonexisting_user'); } - - public function testGetUserDN() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(2)) - ->method('username2dn') - ->willReturn('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); + + + public function testGetUserDN(): void { + $userAccess = $this->getMockBuilder(Access::class) + ->onlyMethods(['username2dn']) + ->disableOriginalConstructor() + ->getMock(); + $userAccess->expects($this->once()) + ->method('username2dn') + ->willReturn('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getLDAPAccess']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->once()) + ->method('userExists') + ->willReturn(true); $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - + ->method('getLDAPAccess') + ->willReturn($userAccess); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org', + $this->assertEquals('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org', $ldapProvider->getUserDN('existing_user')); } - /** - * @expectedException \Exception - * @expectedExceptionMessage Group id not found in LDAP - */ - public function testGetGroupDNGroupIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) + public function testGetGroupDNGroupIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->createMock(User_LDAP::class); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists']) ->disableOriginalConstructor() ->getMock(); @@ -160,128 +151,115 @@ class LDAPProviderTest extends \Test\TestCase { $ldapProvider->getGroupDN('nonexisting_group'); } - public function testGetGroupDN() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) - ->disableOriginalConstructor() - ->getMock(); + public function testGetGroupDN(): void { + $userBackend = $this->createMock(User_LDAP::class); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'groupname2dn']) + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists', 'getLDAPAccess']) ->disableOriginalConstructor() ->getMock(); - $groupBackend->expects($this->at(0)) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->at(2)) + $groupAccess = $this->createMock(Access::class); + $groupAccess->expects($this->once()) ->method('groupname2dn') ->willReturn('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); + $groupBackend->expects($this->once()) + ->method('groupExists') + ->willReturn(true); $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); + ->method('getLDAPAccess') + ->willReturn($groupAccess); $server = $this->getServerMock($userBackend, $groupBackend); $ldapProvider = $this->getLDAPProvider($server); $this->assertEquals('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org', $ldapProvider->getGroupDN('existing_group')); - } + } - public function testGetUserName() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['dn2UserName']) - ->disableOriginalConstructor() - ->getMock(); + public function testGetUserName(): void { + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['dn2UserName']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any()) - ->method('dn2UserName') - ->willReturn('existing_user'); - + ->method('dn2UserName') + ->willReturn('existing_user'); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('existing_user', + $this->assertEquals('existing_user', $ldapProvider->getUserName('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); } - - public function testDNasBaseParameter() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - + + public function testDNasBaseParameter(): void { + $userBackend = $this->createMock(User_LDAP::class); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig()); - + + $helper = Server::get(Helper::class); + $ldapProvider = $this->getLDAPProvider($server); $this->assertEquals( - $helper->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), + $helper->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), $ldapProvider->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); } - public function testSanitizeDN() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - + public function testSanitizeDN(): void { + $userBackend = $this->createMock(User_LDAP::class); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig()); - + + $helper = Server::get(Helper::class); + $ldapProvider = $this->getLDAPProvider($server); $this->assertEquals( - $helper->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), + $helper->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), $ldapProvider->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testGetLDAPConnectionUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); + + + public function testGetLDAPConnectionUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->createMock(User_LDAP::class); $userBackend->expects($this->any())->method('userExists')->willReturn(false); - + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->getLDAPConnection('nonexisting_user'); } - - public function testGetLDAPConnection() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getNewLDAPConnection']) - ->disableOriginalConstructor() - ->getMock(); + + public function testGetLDAPConnection(): void { + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getNewLDAPConnection']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any()) - ->method('userExists') - ->willReturn(true); + ->method('userExists') + ->willReturn(true); + $ldapConnection = ldap_connect('ldap://example.com'); $userBackend->expects($this->any()) - ->method('getNewLDAPConnection') - ->willReturn(true); - + ->method('getNewLDAPConnection') + ->willReturn($ldapConnection); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); - $this->assertTrue($ldapProvider->getLDAPConnection('existing_user')); + $this->assertEquals($ldapConnection, $ldapProvider->getLDAPConnection('existing_user')); } - /** - * @expectedException \Exception - * @expectedExceptionMessage Group id not found in LDAP - */ - public function testGetGroupLDAPConnectionGroupIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) + public function testGetGroupLDAPConnectionGroupIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->createMock(User_LDAP::class); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists']) ->disableOriginalConstructor() ->getMock(); @@ -293,13 +271,10 @@ class LDAPProviderTest extends \Test\TestCase { $ldapProvider->getGroupLDAPConnection('nonexisting_group'); } - public function testGetGroupLDAPConnection() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists','getNewLDAPConnection']) + public function testGetGroupLDAPConnection(): void { + $userBackend = $this->createMock(User_LDAP::class); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists','getNewLDAPConnection']) ->disableOriginalConstructor() ->getMock(); @@ -307,141 +282,195 @@ class LDAPProviderTest extends \Test\TestCase { ->method('groupExists') ->willReturn(true); + $ldapConnection = ldap_connect('ldap://example.com'); $groupBackend->expects($this->any()) ->method('getNewLDAPConnection') - ->willReturn(true); + ->willReturn($ldapConnection); $server = $this->getServerMock($userBackend, $groupBackend); $ldapProvider = $this->getLDAPProvider($server); - $this->assertTrue($ldapProvider->getGroupLDAPConnection('existing_group')); + $this->assertEquals($ldapConnection, $ldapProvider->getGroupLDAPConnection('existing_group')); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testGetLDAPBaseUsersUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); + + + public function testGetLDAPBaseUsersUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any())->method('userExists')->willReturn(false); - + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->getLDAPBaseUsers('nonexisting_user'); } - - public function testGetLDAPBaseUsers() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('getConfiguration') - ->willReturn(array('ldap_base_users'=>'ou=users,dc=example,dc=org')); + + public function testGetLDAPBaseUsers(): void { + $bases = [ + 'ou=users,ou=foobar,dc=example,dc=org', + 'ou=users,ou=barfoo,dc=example,dc=org', + ]; + $dn = 'uid=malik,' . $bases[1]; + + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($key) use ($bases) { + switch ($key) { + case 'ldapBaseUsers': + return $bases; + } + return null; + }); + + $access = $this->createMock(Access::class); + $access->expects($this->any()) + ->method('getConnection') + ->willReturn($connection); + $access->expects($this->exactly(2)) + ->method('isDNPartOfBase') + ->willReturnOnConsecutiveCalls(false, true); + $access->expects($this->atLeastOnce()) + ->method('username2dn') + ->willReturn($dn); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getLDAPAccess']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->atLeastOnce()) + ->method('userExists') + ->willReturn(true); $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - + ->method('getLDAPAccess') + ->willReturn($access); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('ou=users,dc=example,dc=org', $ldapProvider->getLDAPBaseUsers('existing_user')); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testGetLDAPBaseGroupsUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals($bases[1], $ldapProvider->getLDAPBaseUsers('existing_user')); + } + + + public function testGetLDAPBaseGroupsUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any())->method('userExists')->willReturn(false); - + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->getLDAPBaseGroups('nonexisting_user'); } - - public function testGetLDAPBaseGroups() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('getConfiguration') - ->willReturn(array('ldap_base_groups'=>'ou=groups,dc=example,dc=org')); + + public function testGetLDAPBaseGroups(): void { + $bases = [ + 'ou=groupd,ou=foobar,dc=example,dc=org', + 'ou=groups,ou=barfoo,dc=example,dc=org', + ]; + + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($key) use ($bases) { + switch ($key) { + case 'ldapBaseGroups': + return $bases; + } + return null; + }); + + $access = $this->createMock(Access::class); + $access->expects($this->any()) + ->method('getConnection') + ->willReturn($connection); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getLDAPAccess']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - + ->method('userExists') + ->willReturn(true); + $userBackend->expects($this->any()) + ->method('getLDAPAccess') + ->willReturn($access); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('ou=groups,dc=example,dc=org', $ldapProvider->getLDAPBaseGroups('existing_user')); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testClearCacheUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); + + $ldapProvider = $this->getLDAPProvider($server); + $this->assertEquals($bases[0], $ldapProvider->getLDAPBaseGroups('existing_user')); + } + + + public function testClearCacheUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any())->method('userExists')->willReturn(false); - + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->clearCache('nonexisting_user'); } - - public function testClearCache() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'clearCache']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('clearCache') - ->willReturn(true); + + public function testClearCache(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects($this->once()) + ->method('clearCache') + ->willReturn(true); + $access = $this->createMock(Access::class); + $access->method('getConnection') + ->willReturn($connection); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getLDAPAccess']) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->expects($this->once()) + ->method('userExists') + ->willReturn(true); $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - + ->method('getLDAPAccess') + ->willReturn($access); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->clearCache('existing_user'); - $this->assertTrue(TRUE); + $this->addToAssertionCount(1); } - /** - * @expectedException \Exception - * @expectedExceptionMessage Group id not found in LDAP - */ - public function testClearGroupCacheGroupIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') + + public function testClearGroupCacheGroupIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) ->disableOriginalConstructor() ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists']) ->disableOriginalConstructor() ->getMock(); $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); @@ -452,79 +481,75 @@ class LDAPProviderTest extends \Test\TestCase { $ldapProvider->clearGroupCache('nonexisting_group'); } - public function testClearGroupCache() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() + public function testClearGroupCache(): void { + $userBackend = $this->createMock(User_LDAP::class); + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'clearCache']) + $connection->expects($this->once()) + ->method('clearCache') + ->willReturn(true); + $access = $this->createMock(Access::class); + $access->method('getConnection') + ->willReturn($connection); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists', 'getLDAPAccess']) ->disableOriginalConstructor() ->getMock(); - $groupBackend->expects($this->at(0)) + $groupBackend->expects($this->once()) ->method('groupExists') ->willReturn(true); - $groupBackend->expects($this->at(3)) - ->method('clearCache') - ->willReturn(true); $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); + ->method('getLDAPAccess') + ->willReturn($access); $server = $this->getServerMock($userBackend, $groupBackend); $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->clearGroupCache('existing_group'); - $this->assertTrue(TRUE); - } - - public function testDnExists() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['dn2UserName']) - ->disableOriginalConstructor() - ->getMock(); + $this->addToAssertionCount(1); + } + + public function testDnExists(): void { + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['dn2UserName']) + ->disableOriginalConstructor() + ->getMock(); $userBackend->expects($this->any()) - ->method('dn2UserName') - ->willReturn('existing_user'); - + ->method('dn2UserName') + ->willReturn('existing_user'); + $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $this->assertTrue($ldapProvider->dnExists('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); } - - public function testFlagRecord() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - + + public function testFlagRecord(): void { + $userBackend = $this->createMock(User_LDAP::class); $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->flagRecord('existing_user'); - $this->assertTrue(TRUE); - } - - public function testUnflagRecord() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - + $this->addToAssertionCount(1); + } + + public function testUnflagRecord(): void { + $userBackend = $this->createMock(User_LDAP::class); $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - + $ldapProvider = $this->getLDAPProvider($server); $ldapProvider->unflagRecord('existing_user'); - $this->assertTrue(TRUE); + $this->addToAssertionCount(1); } - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testGetLDAPDisplayNameFieldUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) + + public function testGetLDAPDisplayNameFieldUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists']) ->disableOriginalConstructor() ->getMock(); $userBackend->expects($this->any())->method('userExists')->willReturn(false); @@ -535,20 +560,26 @@ class LDAPProviderTest extends \Test\TestCase { $ldapProvider->getLDAPDisplayNameField('nonexisting_user'); } - public function testGetLDAPDisplayNameField() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + public function testGetLDAPDisplayNameField(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects($this->once()) + ->method('getConfiguration') + ->willReturn(['ldap_display_name' => 'displayName']); + $access = $this->createMock(Access::class); + $access->method('getConnection') + ->willReturn($connection); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getLDAPAccess']) ->disableOriginalConstructor() ->getMock(); - $userBackend->expects($this->at(0)) + $userBackend->expects($this->once()) ->method('userExists') ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('getConfiguration') - ->willReturn(array('ldap_display_name'=>'displayName')); $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); + ->method('getLDAPAccess') + ->willReturn($access); $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); @@ -556,13 +587,13 @@ class LDAPProviderTest extends \Test\TestCase { $this->assertEquals('displayName', $ldapProvider->getLDAPDisplayNameField('existing_user')); } - /** - * @expectedException \Exception - * @expectedExceptionMessage User id not found in LDAP - */ - public function testGetLDAPEmailFieldUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) + + public function testGetLDAPEmailFieldUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists']) ->disableOriginalConstructor() ->getMock(); $userBackend->expects($this->any())->method('userExists')->willReturn(false); @@ -573,20 +604,26 @@ class LDAPProviderTest extends \Test\TestCase { $ldapProvider->getLDAPEmailField('nonexisting_user'); } - public function testGetLDAPEmailField() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + public function testGetLDAPEmailField(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects($this->once()) + ->method('getConfiguration') + ->willReturn(['ldap_email_attr' => 'mail']); + $access = $this->createMock(Access::class); + $access->method('getConnection') + ->willReturn($connection); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->onlyMethods(['userExists', 'getLDAPAccess']) ->disableOriginalConstructor() ->getMock(); - $userBackend->expects($this->at(0)) + $userBackend->expects($this->once()) ->method('userExists') ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('getConfiguration') - ->willReturn(array('ldap_email_attr'=>'mail')); $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); + ->method('getLDAPAccess') + ->willReturn($access); $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); @@ -594,21 +631,20 @@ class LDAPProviderTest extends \Test\TestCase { $this->assertEquals('mail', $ldapProvider->getLDAPEmailField('existing_user')); } - /** - * @expectedException \Exception - * @expectedExceptionMessage Group id not found in LDAP - */ - public function testGetLDAPGroupMemberAssocUserIDNotFound() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) + public function testGetLDAPGroupMemberAssocUserIDNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Group id not found in LDAP'); + + $userBackend = $this->createMock(User_LDAP::class); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists']) ->disableOriginalConstructor() ->getMock(); - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); + $groupBackend->expects($this->any()) + ->method('groupExists') + ->willReturn(false); $server = $this->getServerMock($userBackend, $groupBackend); @@ -616,30 +652,232 @@ class LDAPProviderTest extends \Test\TestCase { $ldapProvider->getLDAPGroupMemberAssoc('nonexisting_group'); } - public function testgetLDAPGroupMemberAssoc() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); + public function testgetLDAPGroupMemberAssoc(): void { + $userBackend = $this->createMock(User_LDAP::class); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects($this->once()) + ->method('getConfiguration') + ->willReturn(['ldap_group_member_assoc_attribute' => 'assoc_type']); + $access = $this->createMock(Access::class); + $access->method('getConnection') + ->willReturn($connection); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->onlyMethods(['groupExists', 'getLDAPAccess']) ->disableOriginalConstructor() ->getMock(); - $groupBackend->expects($this->at(0)) + $groupBackend->expects($this->once()) ->method('groupExists') ->willReturn(true); $groupBackend->expects($this->any()) - ->method('getConfiguration') - ->willReturn(array('ldap_group_member_assoc_attribute'=>'assoc_type')); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); + ->method('getLDAPAccess') + ->willReturn($access); $server = $this->getServerMock($userBackend, $groupBackend); $ldapProvider = $this->getLDAPProvider($server); $this->assertEquals('assoc_type', $ldapProvider->getLDAPGroupMemberAssoc('existing_group')); - } + } + + public function testGetMultiValueUserAttributeUserNotFound(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('User id not found in LDAP'); + + $userBackend = $this->createMock(User_LDAP::class); + $userBackend->expects(self::once()) + ->method('userExists') + ->with('admin') + ->willReturn(false); + $groupBackend = $this->createMock(Group_LDAP::class); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + } + + public function testGetMultiValueUserAttributeCacheHit(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(['aliasA@test.local', 'aliasB@test.local']); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $userBackend = $this->createMock(User_LDAP::class); + $userBackend->expects(self::once()) + ->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->expects(self::once()) + ->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->createMock(Group_LDAP::class); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + } + + public function testGetMultiValueUserAttributeLdapError(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(false); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $values = $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + + self::assertCount(0, $values); + } + + public function testGetMultiValueUserAttribute(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(['aliasA@test.local', 'aliasB@test.local']); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $values = $ldapProvider->getMultiValueUserAttribute('admin', 'mailAlias'); + + self::assertCount(2, $values); + } + + public function testGetUserAttributeLdapError(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(false); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + $ldapProvider = $this->getLDAPProvider($server); + $value = $ldapProvider->getUserAttribute('admin', 'mailAlias'); + + self::assertNull($value); + } + + public function testGetUserAttribute(): void { + $connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $connection->expects(self::once()) + ->method('getFromCache') + ->with('admin-mailAlias') + ->willReturn(null); + $access = $this->createMock(Access::class); + $access->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $access->expects(self::once()) + ->method('username2dn') + ->with('admin') + ->willReturn('admin'); + $access->expects(self::once()) + ->method('readAttribute') + ->with('admin', 'mailAlias') + ->willReturn(['aliasA@test.local', 'aliasB@test.local']); + $userBackend = $this->getMockBuilder(User_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $userBackend->method('userExists') + ->with('admin') + ->willReturn(true); + $userBackend->method('getLDAPAccess') + ->willReturn($access); + $groupBackend = $this->getMockBuilder(Group_LDAP::class) + ->disableOriginalConstructor() + ->getMock(); + $server = $this->getServerMock($userBackend, $groupBackend); + + $ldapProvider = $this->getLDAPProvider($server); + $value = $ldapProvider->getUserAttribute('admin', 'mailAlias'); + + self::assertEquals('aliasA@test.local', $value); + } } diff --git a/apps/user_ldap/tests/LDAPTest.php b/apps/user_ldap/tests/LDAPTest.php index 8e181741b50..6da592ad6a1 100644 --- a/apps/user_ldap/tests/LDAPTest.php +++ b/apps/user_ldap/tests/LDAPTest.php @@ -1,50 +1,70 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Lukas Reschke <lukas@statuscode.ch> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; use OCA\User_LDAP\LDAP; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; -class LDAPTest extends TestCase { - /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */ - private $ldap; +class LDAPTest extends TestCase { + private LDAP&MockObject $ldap; - public function setUp() { + protected function setUp(): void { parent::setUp(); $this->ldap = $this->getMockBuilder(LDAP::class) - ->setMethods(['invokeLDAPMethod']) + ->onlyMethods(['invokeLDAPMethod']) ->getMock(); } - public function testModReplace() { + public static function errorProvider(): array { + return [ + [ + 'ldap_search(): Partial search results returned: Sizelimit exceeded at /srv/http/nextcloud/master/apps/user_ldap/lib/LDAP.php#292', + false + ], + [ + 'Some other error', true + ] + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('errorProvider')] + public function testSearchWithErrorHandler(string $errorMessage, bool $passThrough): void { + $wasErrorHandlerCalled = false; + $errorHandler = function ($number, $message, $file, $line) use (&$wasErrorHandlerCalled): void { + $wasErrorHandlerCalled = true; + }; + + set_error_handler($errorHandler); + + $this->ldap + ->expects($this->once()) + ->method('invokeLDAPMethod') + ->with('search', $this->anything(), $this->anything(), $this->anything(), $this->anything(), $this->anything()) + ->willReturnCallback(function () use ($errorMessage): void { + trigger_error($errorMessage); + }); + + $fakeResource = ldap_connect(); + $this->ldap->search($fakeResource, 'base', 'filter', []); + $this->assertSame($wasErrorHandlerCalled, $passThrough); + + restore_error_handler(); + } + + public function testModReplace(): void { $link = $this->createMock(LDAP::class); $userDN = 'CN=user'; $password = 'MyPassword'; $this->ldap ->expects($this->once()) ->method('invokeLDAPMethod') - ->with('mod_replace', $link, $userDN, array('userPassword' => $password)) + ->with('mod_replace', $link, $userDN, ['userPassword' => $password]) ->willReturn(true); $this->assertTrue($this->ldap->modReplace($link, $userDN, $password)); diff --git a/apps/user_ldap/tests/LDAPUserPluginDummy.php b/apps/user_ldap/tests/LDAPUserPluginDummy.php index eb7029a6ef7..8d4870406ae 100644 --- a/apps/user_ldap/tests/LDAPUserPluginDummy.php +++ b/apps/user_ldap/tests/LDAPUserPluginDummy.php @@ -1,33 +1,15 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br) - * - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; - use OCA\User_LDAP\ILDAPUserPlugin; class LDAPUserPluginDummy implements ILDAPUserPlugin { - public function respondToActions() { return null; } @@ -60,4 +42,11 @@ class LDAPUserPluginDummy implements ILDAPUserPlugin { return null; } + public function canDeleteUser() { + return true; + } + + public function deleteUser($uid) { + return null; + } } diff --git a/apps/user_ldap/tests/Mapping/AbstractMappingTest.php b/apps/user_ldap/tests/Mapping/AbstractMappingTestCase.php index d3d33a82da9..8efee4e2085 100644 --- a/apps/user_ldap/tests/Mapping/AbstractMappingTest.php +++ b/apps/user_ldap/tests/Mapping/AbstractMappingTestCase.php @@ -1,42 +1,24 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Aaron Wood <aaronjwood@gmail.com> - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Stefan Weil <sw@weilnetz.de> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Mapping; use OCA\User_LDAP\Mapping\AbstractMapping; use OCP\IDBConnection; +use OCP\Server; -abstract class AbstractMappingTest extends \Test\TestCase { - abstract public function getMapper(\OCP\IDBConnection $dbMock); +abstract class AbstractMappingTestCase extends \Test\TestCase { + abstract public function getMapper(IDBConnection $dbMock); /** * kiss test on isColNameValid */ - public function testIsColNameValid() { + public function testIsColNameValid(): void { $dbMock = $this->createMock(IDBConnection::class); $mapper = $this->getMapper($dbMock); @@ -48,71 +30,69 @@ abstract class AbstractMappingTest extends \Test\TestCase { * returns an array of test entries with dn, name and uuid as keys * @return array */ - protected function getTestData() { - $data = array( - array( + protected static function getTestData(): array { + return [ + [ 'dn' => 'uid=foobar,dc=example,dc=org', 'name' => 'Foobar', 'uuid' => '1111-AAAA-1234-CDEF', - ), - array( + ], + [ 'dn' => 'uid=barfoo,dc=example,dc=org', 'name' => 'Barfoo', 'uuid' => '2222-BBBB-1234-CDEF', - ), - array( + ], + [ 'dn' => 'uid=barabara,dc=example,dc=org', 'name' => 'BaraBara', 'uuid' => '3333-CCCC-1234-CDEF', - ) - ); - - return $data; + ] + ]; } /** * calls map() on the given mapper and asserts result for true - * @param \OCA\User_LDAP\Mapping\AbstractMapping $mapper + * @param AbstractMapping $mapper * @param array $data */ - protected function mapEntries($mapper, $data) { - foreach($data as $entry) { + protected function mapEntries(AbstractMapping $mapper, array $data): void { + foreach ($data as $entry) { $done = $mapper->map($entry['dn'], $entry['name'], $entry['uuid']); $this->assertTrue($done); } } /** - * initalizes environment for a test run and returns an array with + * initializes environment for a test run and returns an array with * test objects. Preparing environment means that all mappings are cleared * first and then filled with test entries. * @return array 0 = \OCA\User_LDAP\Mapping\AbstractMapping, 1 = array of - * users or groups + * users or groups */ - private function initTest() { - $dbc = \OC::$server->getDatabaseConnection(); + private function initTest(): array { + $dbc = Server::get(IDBConnection::class); $mapper = $this->getMapper($dbc); $data = $this->getTestData(); // make sure DB is pristine, then fill it with test entries $mapper->clear(); $this->mapEntries($mapper, $data); - return array($mapper, $data); + return [$mapper, $data]; } /** * tests map() method with input that should result in not-mapping. * Hint: successful mapping is tested inherently with mapEntries(). */ - public function testMap() { - list($mapper, $data) = $this->initTest(); + public function testMap(): void { + [$mapper, $data] = $this->initTest(); // test that mapping will not happen when it shall not $tooLongDN = 'uid=joann,ou=Secret Small Specialized Department,ou=Some Tremendously Important Department,ou=Another Very Important Department,ou=Pretty Meaningful Derpartment,ou=Quite Broad And General Department,ou=The Topmost Department,dc=hugelysuccessfulcompany,dc=com'; - $paramKeys = array('', 'dn', 'name', 'uuid', $tooLongDN); - foreach($paramKeys as $key) { + $paramKeys = ['', 'dn', 'name', 'uuid', $tooLongDN]; + foreach ($paramKeys as $key) { $failEntry = $data[0]; - if(!empty($key)) { + if (!empty($key)) { $failEntry[$key] = 'do-not-get-mapped'; } $isMapped = $mapper->map($failEntry['dn'], $failEntry['name'], $failEntry['uuid']); @@ -124,12 +104,16 @@ abstract class AbstractMappingTest extends \Test\TestCase { * tests unmap() for both successful and unsuccessful removing of * mapping entries */ - public function testUnmap() { - list($mapper, $data) = $this->initTest(); + public function testUnmap(): void { + [$mapper, $data] = $this->initTest(); - foreach($data as $entry) { + foreach ($data as $entry) { + $fdnBefore = $mapper->getDNByName($entry['name']); $result = $mapper->unmap($entry['name']); + $fdnAfter = $mapper->getDNByName($entry['name']); $this->assertTrue($result); + $this->assertSame($fdnBefore, $entry['dn']); + $this->assertFalse($fdnAfter); } $result = $mapper->unmap('notAnEntry'); @@ -140,24 +124,24 @@ abstract class AbstractMappingTest extends \Test\TestCase { * tests getDNByName(), getNameByDN() and getNameByUUID() for successful * and unsuccessful requests. */ - public function testGetMethods() { - list($mapper, $data) = $this->initTest(); + public function testGetMethods(): void { + [$mapper, $data] = $this->initTest(); - foreach($data as $entry) { + foreach ($data as $entry) { $fdn = $mapper->getDNByName($entry['name']); $this->assertSame($fdn, $entry['dn']); } $fdn = $mapper->getDNByName('nosuchname'); $this->assertFalse($fdn); - foreach($data as $entry) { + foreach ($data as $entry) { $name = $mapper->getNameByDN($entry['dn']); $this->assertSame($name, $entry['name']); } $name = $mapper->getNameByDN('nosuchdn'); $this->assertFalse($name); - foreach($data as $entry) { + foreach ($data as $entry) { $name = $mapper->getNameByUUID($entry['uuid']); $this->assertSame($name, $entry['name']); } @@ -168,24 +152,24 @@ abstract class AbstractMappingTest extends \Test\TestCase { /** * tests getNamesBySearch() for successful and unsuccessful requests. */ - public function testSearch() { - list($mapper,) = $this->initTest(); + public function testSearch(): void { + [$mapper,] = $this->initTest(); $names = $mapper->getNamesBySearch('oo', '%', '%'); - $this->assertTrue(is_array($names)); + $this->assertIsArray($names); $this->assertSame(2, count($names)); - $this->assertTrue(in_array('Foobar', $names)); - $this->assertTrue(in_array('Barfoo', $names)); + $this->assertContains('Foobar', $names); + $this->assertContains('Barfoo', $names); $names = $mapper->getNamesBySearch('nada'); - $this->assertTrue(is_array($names)); - $this->assertSame(0, count($names)); + $this->assertIsArray($names); + $this->assertCount(0, $names); } /** * tests setDNbyUUID() for successful and unsuccessful update. */ - public function testSetDNMethod() { - list($mapper, $data) = $this->initTest(); + public function testSetDNMethod(): void { + [$mapper, $data] = $this->initTest(); $newDN = 'uid=modified,dc=example,dc=org'; $done = $mapper->setDNbyUUID($newDN, $data[0]['uuid']); @@ -203,9 +187,9 @@ abstract class AbstractMappingTest extends \Test\TestCase { /** * tests setUUIDbyDN() for successful and unsuccessful update. */ - public function testSetUUIDMethod() { + public function testSetUUIDMethod(): void { /** @var AbstractMapping $mapper */ - list($mapper, $data) = $this->initTest(); + [$mapper, $data] = $this->initTest(); $newUUID = 'ABC737-DEF754'; @@ -223,12 +207,35 @@ abstract class AbstractMappingTest extends \Test\TestCase { /** * tests clear() for successful update. */ - public function testClear() { - list($mapper, $data) = $this->initTest(); + public function testClear(): void { + [$mapper, $data] = $this->initTest(); $done = $mapper->clear(); $this->assertTrue($done); - foreach($data as $entry) { + foreach ($data as $entry) { + $name = $mapper->getNameByUUID($entry['uuid']); + $this->assertFalse($name); + } + } + + /** + * tests clear() for successful update. + */ + public function testClearCb(): void { + [$mapper, $data] = $this->initTest(); + + $callbackCalls = 0; + $test = $this; + + $callback = function (string $id) use ($test, &$callbackCalls): void { + $test->assertTrue(trim($id) !== ''); + $callbackCalls++; + }; + + $done = $mapper->clearCb($callback, $callback); + $this->assertTrue($done); + $this->assertSame(count($data) * 2, $callbackCalls); + foreach ($data as $entry) { $name = $mapper->getNameByUUID($entry['uuid']); $this->assertFalse($name); } @@ -237,24 +244,43 @@ abstract class AbstractMappingTest extends \Test\TestCase { /** * tests getList() method */ - public function testList() { - list($mapper, $data) = $this->initTest(); + public function testList(): void { + [$mapper, $data] = $this->initTest(); // get all entries without specifying offset or limit $results = $mapper->getList(); - $this->assertSame(3, count($results)); + $this->assertCount(3, $results); // get all-1 entries by specifying offset, and an high limit // specifying only offset without limit will not work by underlying lib $results = $mapper->getList(1, 999); - $this->assertSame(count($data) - 1, count($results)); + $this->assertCount(count($data) - 1, $results); // get first 2 entries by limit, but not offset - $results = $mapper->getList(null, 2); - $this->assertSame(2, count($results)); + $results = $mapper->getList(0, 2); + $this->assertCount(2, $results); // get 2nd entry by specifying both offset and limit $results = $mapper->getList(1, 1); - $this->assertSame(1, count($results)); + $this->assertCount(1, $results); + } + + public function testGetListOfIdsByDn(): void { + /** @var AbstractMapping $mapper */ + [$mapper,] = $this->initTest(); + + $listOfDNs = []; + for ($i = 0; $i < 66640; $i++) { + // Postgres has a limit of 65535 values in a single IN list + $name = 'as_' . $i; + $dn = 'uid=' . $name . ',dc=example,dc=org'; + $listOfDNs[] = $dn; + if ($i % 20 === 0) { + $mapper->map($dn, $name, 'fake-uuid-' . $i); + } + } + + $result = $mapper->getListOfIdsByDn($listOfDNs); + $this->assertCount(66640 / 20, $result); } } diff --git a/apps/user_ldap/tests/Mapping/GroupMappingTest.php b/apps/user_ldap/tests/Mapping/GroupMappingTest.php index 4b31f07a7d1..5729058d10e 100644 --- a/apps/user_ldap/tests/Mapping/GroupMappingTest.php +++ b/apps/user_ldap/tests/Mapping/GroupMappingTest.php @@ -1,31 +1,15 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Mapping; use OCA\User_LDAP\Mapping\GroupMapping; +use OCP\IDBConnection; /** * Class GroupMappingTest @@ -34,8 +18,8 @@ use OCA\User_LDAP\Mapping\GroupMapping; * * @package OCA\User_LDAP\Tests\Mapping */ -class GroupMappingTest extends AbstractMappingTest { - public function getMapper(\OCP\IDBConnection $dbMock) { +class GroupMappingTest extends AbstractMappingTestCase { + public function getMapper(IDBConnection $dbMock) { return new GroupMapping($dbMock); } } diff --git a/apps/user_ldap/tests/Mapping/UserMappingTest.php b/apps/user_ldap/tests/Mapping/UserMappingTest.php index c1752c5f67b..4346fe1d23f 100644 --- a/apps/user_ldap/tests/Mapping/UserMappingTest.php +++ b/apps/user_ldap/tests/Mapping/UserMappingTest.php @@ -1,31 +1,16 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2019-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\Mapping; use OCA\User_LDAP\Mapping\UserMapping; +use OCP\IDBConnection; +use OCP\Support\Subscription\IAssertion; /** * Class UserMappingTest @@ -34,8 +19,8 @@ use OCA\User_LDAP\Mapping\UserMapping; * * @package OCA\User_LDAP\Tests\Mapping */ -class UserMappingTest extends AbstractMappingTest { - public function getMapper(\OCP\IDBConnection $dbMock) { - return new UserMapping($dbMock); +class UserMappingTest extends AbstractMappingTestCase { + public function getMapper(IDBConnection $dbMock) { + return new UserMapping($dbMock, $this->createMock(IAssertion::class)); } } diff --git a/apps/user_ldap/tests/Migration/AbstractUUIDFixTest.php b/apps/user_ldap/tests/Migration/AbstractUUIDFixTestCase.php index 8921648da83..7a85b885bc1 100644 --- a/apps/user_ldap/tests/Migration/AbstractUUIDFixTest.php +++ b/apps/user_ldap/tests/Migration/AbstractUUIDFixTestCase.php @@ -1,69 +1,41 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests\Migration; -use OCA\User_LDAP\LDAP; -use Test\TestCase; use OCA\User_LDAP\Access; use OCA\User_LDAP\Helper; -use OCA\User_LDAP\Migration\UUIDFixUser; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\User_Proxy; +use OCA\User_LDAP\LDAP; +use OCA\User_LDAP\Mapping\AbstractMapping; +use OCA\User_LDAP\Migration\UUIDFix; +use OCA\User_LDAP\Proxy; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; -abstract class AbstractUUIDFixTest extends TestCase { - /** @var Helper|\PHPUnit_Framework_MockObject_MockObject */ - protected $helper; - - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - protected $config; - - /** @var LDAP|\PHPUnit_Framework_MockObject_MockObject */ - protected $ldap; - - /** @var UserMapping|GroupMapping|\PHPUnit_Framework_MockObject_MockObject */ - protected $mapper; - - /** @var UUIDFixUser */ - protected $job; - - /** @var User_Proxy|\PHPUnit_Framework_MockObject_MockObject */ - protected $proxy; - - /** @var Access|\PHPUnit_Framework_MockObject_MockObject */ - protected $access; - - /** @var bool */ - protected $isUser = true; - - public function setUp() { +abstract class AbstractUUIDFixTestCase extends TestCase { + protected Helper&MockObject $helper; + protected IConfig&MockObject $config; + protected LDAP&MockObject $ldap; + protected AbstractMapping $mapper; + protected UUIDFix $job; + protected Proxy $proxy; + protected Access&MockObject $access; + protected ITimeFactory&MockObject $time; + protected bool $isUser = true; + + protected function setUp(): void { parent::setUp(); $this->ldap = $this->createMock(LDAP::class); $this->config = $this->createMock(IConfig::class); $this->access = $this->createMock(Access::class); + $this->time = $this->createMock(ITimeFactory::class); $this->helper = $this->createMock(Helper::class); $this->helper->expects($this->any()) @@ -72,19 +44,14 @@ abstract class AbstractUUIDFixTest extends TestCase { ->willReturn(['s01', 's03']); } - protected function mockProxy($className) { - $this->proxy = $this->createMock($className); + protected function instantiateJob($className) { + $this->job = new $className($this->time, $this->mapper, $this->proxy); $this->proxy->expects($this->any()) ->method('getLDAPAccess') ->willReturn($this->access); } - protected function instantiateJob($className) { - $this->job = new $className($this->mapper, $this->ldap, $this->config, $this->helper); - $this->job->overrideProxy($this->proxy); - } - - public function testRunSingleRecord() { + public function testRunSingleRecord(): void { $args = [ 'records' => [ 0 => [ @@ -108,7 +75,7 @@ abstract class AbstractUUIDFixTest extends TestCase { $this->job->run($args); } - public function testRunValidRecord() { + public function testRunValidRecord(): void { $correctUUID = '4355-AED3-9D73-03AD'; $args = [ 'records' => [ @@ -131,7 +98,7 @@ abstract class AbstractUUIDFixTest extends TestCase { $this->job->run($args); } - public function testRunRemovedRecord() { + public function testRunRemovedRecord(): void { $args = [ 'records' => [ 0 => [ @@ -153,7 +120,7 @@ abstract class AbstractUUIDFixTest extends TestCase { $this->job->run($args); } - public function testRunManyRecords() { + public function testRunManyRecords(): void { $args = [ 'records' => [ 0 => [ @@ -177,21 +144,24 @@ abstract class AbstractUUIDFixTest extends TestCase { $this->access->expects($this->exactly(3)) ->method('getUUID') - ->withConsecutive( - [$args['records'][0]['dn'], $this->isUser], - [$args['records'][1]['dn'], $this->isUser], - [$args['records'][2]['dn'], $this->isUser] - ) - ->willReturnOnConsecutiveCalls($correctUUIDs[0], $correctUUIDs[1], $correctUUIDs[2]); - + ->willReturnMap([ + [$args['records'][0]['dn'], $this->isUser, null, $correctUUIDs[0]], + [$args['records'][1]['dn'], $this->isUser, null, $correctUUIDs[1]], + [$args['records'][2]['dn'], $this->isUser, null, $correctUUIDs[2]], + ]); + + $calls = [ + [$correctUUIDs[0], $args['records'][0]['dn']], + [$correctUUIDs[2], $args['records'][2]['dn']], + ]; $this->mapper->expects($this->exactly(2)) ->method('setUUIDbyDN') - ->withConsecutive( - [$correctUUIDs[0], $args['records'][0]['dn']], - [$correctUUIDs[2], $args['records'][2]['dn']] - ); + ->willReturnCallback(function ($i, $j) use (&$calls) { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + return true; + }); $this->job->run($args); } - } diff --git a/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php b/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php index b91f4af433f..89d880f4acb 100644 --- a/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php +++ b/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php @@ -1,32 +1,15 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ +namespace OCA\User_LDAP\Tests\Migration; -namespace OCA\Group_LDAP\Tests\Migration; - -use OCA\User_LDAP\Migration\UUIDFixGroup; -use OCA\User_LDAP\Mapping\GroupMapping; use OCA\User_LDAP\Group_Proxy; -use OCA\User_LDAP\Tests\Migration\AbstractUUIDFixTest; +use OCA\User_LDAP\Mapping\GroupMapping; +use OCA\User_LDAP\Migration\UUIDFixGroup; /** * Class UUIDFixGroupTest @@ -34,17 +17,14 @@ use OCA\User_LDAP\Tests\Migration\AbstractUUIDFixTest; * @package OCA\Group_LDAP\Tests\Migration * @group DB */ -class UUIDFixGroupTest extends AbstractUUIDFixTest { - public function setUp() { +class UUIDFixGroupTest extends AbstractUUIDFixTestCase { + protected function setUp(): void { $this->isUser = false; parent::setUp(); - $this->isUser = false; - $this->mapper = $this->createMock(GroupMapping::class); + $this->proxy = $this->createMock(Group_Proxy::class); - $this->mockProxy(Group_Proxy::class); $this->instantiateJob(UUIDFixGroup::class); } - } diff --git a/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php b/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php index a5f7ea50175..6215ffcb6a1 100644 --- a/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php +++ b/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php @@ -1,53 +1,29 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests\Migration; -use OCA\User_LDAP\Migration\UUIDFixInsert; -use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\Mapping\GroupMapping; +use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\Migration\UUIDFixInsert; use OCP\BackgroundJob\IJobList; use OCP\IConfig; use OCP\Migration\IOutput; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class UUIDFixInsertTest extends TestCase { - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - protected $config; - - /** @var UserMapping|\PHPUnit_Framework_MockObject_MockObject */ - protected $userMapper; + protected IConfig&MockObject $config; + protected UserMapping&MockObject $userMapper; + protected GroupMapping&MockObject $groupMapper; + protected IJobList&MockObject $jobList; + protected UUIDFixInsert $job; - /** @var GroupMapping|\PHPUnit_Framework_MockObject_MockObject */ - protected $groupMapper; - - /** @var IJobList|\PHPUnit_Framework_MockObject_MockObject */ - protected $jobList; - - /** @var UUIDFixInsert */ - protected $job; - - public function setUp() { + protected function setUp(): void { parent::setUp(); $this->jobList = $this->createMock(IJobList::class); @@ -62,22 +38,21 @@ class UUIDFixInsertTest extends TestCase { ); } - public function testGetName() { + public function testGetName(): void { $this->assertSame('Insert UUIDFix background job for user and group in batches', $this->job->getName()); } - public function recordProvider() { + public static function recordProvider(): array { $record = [ 'dn' => 'cn=somerecord,dc=somewhere', 'name' => 'Something', 'uuid' => 'AB12-3456-CDEF7-8GH9' ]; - array_fill(0, 50, $record); $userBatches = [ 0 => array_fill(0, 50, $record), 1 => array_fill(0, 50, $record), - 2 => array_fill(0, 13, $record), + 2 => array_fill(0, 13, $record), ]; $groupBatches = [ @@ -89,13 +64,12 @@ class UUIDFixInsertTest extends TestCase { ]; } - public function recordProviderTooLongAndNone() { + public static function recordProviderTooLongAndNone(): array { $record = [ 'dn' => 'cn=somerecord,dc=somewhere', 'name' => 'Something', 'uuid' => 'AB12-3456-CDEF7-8GH9' ]; - array_fill(0, 50, $record); $userBatches = [ 0 => array_fill(0, 50, $record), @@ -112,10 +86,8 @@ class UUIDFixInsertTest extends TestCase { ]; } - /** - * @dataProvider recordProvider - */ - public function testRun($userBatches, $groupBatches) { + #[\PHPUnit\Framework\Attributes\DataProvider('recordProvider')] + public function testRun(array $userBatches, array $groupBatches): void { $this->config->expects($this->once()) ->method('getAppValue') ->with('user_ldap', 'installed_version', '1.2.1') @@ -123,8 +95,11 @@ class UUIDFixInsertTest extends TestCase { $this->userMapper->expects($this->exactly(3)) ->method('getList') - ->withConsecutive([0, 50], [50, 50], [100, 50]) - ->willReturnOnConsecutiveCalls($userBatches[0], $userBatches[1], $userBatches[2]); + ->willReturnMap([ + [0, 50, false, $userBatches[0]], + [50, 50, false, $userBatches[1]], + [100, 50, false, $userBatches[2]], + ]); $this->groupMapper->expects($this->exactly(1)) ->method('getList') @@ -139,10 +114,8 @@ class UUIDFixInsertTest extends TestCase { $this->job->run($out); } - /** - * @dataProvider recordProviderTooLongAndNone - */ - public function testRunWithManyAndNone($userBatches, $groupBatches) { + #[\PHPUnit\Framework\Attributes\DataProvider('recordProviderTooLongAndNone')] + public function testRunWithManyAndNone(array $userBatches, array $groupBatches): void { $this->config->expects($this->once()) ->method('getAppValue') ->with('user_ldap', 'installed_version', '1.2.1') @@ -150,33 +123,35 @@ class UUIDFixInsertTest extends TestCase { $this->userMapper->expects($this->exactly(5)) ->method('getList') - ->withConsecutive([0, 50], [0, 40], [0, 32], [32, 32], [64, 32]) - ->willReturnOnConsecutiveCalls($userBatches[0], $userBatches[1], $userBatches[2], $userBatches[3], $userBatches[4]); + ->willReturnMap([ + [0, 50, false, $userBatches[0]], + [0, 40, false, $userBatches[1]], + [0, 32, false, $userBatches[2]], + [32, 32, false, $userBatches[3]], + [64, 32, false, $userBatches[4]], + ]); $this->groupMapper->expects($this->once()) ->method('getList') ->with(0, 50) ->willReturn($groupBatches[0]); - $this->jobList->expects($this->at(0)) - ->method('add') - ->willThrowException(new \InvalidArgumentException('Background job arguments can\'t exceed 4000 etc')); - $this->jobList->expects($this->at(1)) + $this->jobList->expects($this->exactly(5)) ->method('add') - ->willThrowException(new \InvalidArgumentException('Background job arguments can\'t exceed 4000 etc')); - $this->jobList->expects($this->at(2)) - ->method('add'); - $this->jobList->expects($this->at(3)) - ->method('add'); - $this->jobList->expects($this->at(4)) - ->method('add'); + ->willReturnOnConsecutiveCalls( + $this->throwException(new \InvalidArgumentException('Background job arguments can\'t exceed 4000 etc')), + $this->throwException(new \InvalidArgumentException('Background job arguments can\'t exceed 4000 etc')), + null, + null, + null, + ); /** @var IOutput $out */ $out = $this->createMock(IOutput::class); $this->job->run($out); } - public function testDonNotRun() { + public function testDonNotRun(): void { $this->config->expects($this->once()) ->method('getAppValue') ->with('user_ldap', 'installed_version', '1.2.1') diff --git a/apps/user_ldap/tests/Migration/UUIDFixUserTest.php b/apps/user_ldap/tests/Migration/UUIDFixUserTest.php index 28eca1608d2..a582fd677fa 100644 --- a/apps/user_ldap/tests/Migration/UUIDFixUserTest.php +++ b/apps/user_ldap/tests/Migration/UUIDFixUserTest.php @@ -1,30 +1,14 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests\Migration; -use OCA\User_LDAP\Migration\UUIDFixUser; use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\Migration\UUIDFixUser; use OCA\User_LDAP\User_Proxy; /** @@ -33,14 +17,14 @@ use OCA\User_LDAP\User_Proxy; * @package OCA\User_LDAP\Tests\Migration * @group DB */ -class UUIDFixUserTest extends AbstractUUIDFixTest { - public function setUp() { +class UUIDFixUserTest extends AbstractUUIDFixTestCase { + protected function setUp(): void { $this->isUser = true; parent::setUp(); $this->mapper = $this->createMock(UserMapping::class); + $this->proxy = $this->createMock(User_Proxy::class); - $this->mockProxy(User_Proxy::class); $this->instantiateJob(UUIDFixUser::class); } } diff --git a/apps/user_ldap/tests/Service/BirthdateParserServiceTest.php b/apps/user_ldap/tests/Service/BirthdateParserServiceTest.php new file mode 100644 index 00000000000..061118f10c1 --- /dev/null +++ b/apps/user_ldap/tests/Service/BirthdateParserServiceTest.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\User_LDAP\Tests\Service; + +use DateTimeImmutable; +use OCA\User_LDAP\Service\BirthdateParserService; +use PHPUnit\Framework\TestCase; + +class BirthdateParserServiceTest extends TestCase { + private BirthdateParserService $service; + + protected function setUp(): void { + parent::setUp(); + + $this->service = new BirthdateParserService(); + } + + public static function parseBirthdateDataProvider(): array { + return [ + ['2024-01-01', new DateTimeImmutable('2024-01-01'), false], + ['20240101', new DateTimeImmutable('2024-01-01'), false], + ['199412161032Z', new DateTimeImmutable('1994-12-16'), false], // LDAP generalized time + ['199412160532-0500', new DateTimeImmutable('1994-12-16'), false], // LDAP generalized time + ['2023-07-31T00:60:59.000Z', null, true], + ['01.01.2024', null, true], + ['01/01/2024', null, true], + ['01 01 2024', null, true], + ['foobar', null, true], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('parseBirthdateDataProvider')] + public function testParseBirthdate( + string $value, + ?DateTimeImmutable $expected, + bool $shouldThrow, + ): void { + if ($shouldThrow) { + $this->expectException(\InvalidArgumentException::class); + } + + $actual = $this->service->parseBirthdate($value); + $this->assertEquals($expected, $actual); + } +} diff --git a/apps/user_ldap/tests/Service/UpdateGroupsServiceTest.php b/apps/user_ldap/tests/Service/UpdateGroupsServiceTest.php new file mode 100644 index 00000000000..601aee86602 --- /dev/null +++ b/apps/user_ldap/tests/Service/UpdateGroupsServiceTest.php @@ -0,0 +1,137 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\User_LDAP\Tests\Service; + +use OCA\User_LDAP\Db\GroupMembership; +use OCA\User_LDAP\Db\GroupMembershipMapper; +use OCA\User_LDAP\Group_Proxy; +use OCA\User_LDAP\Service\UpdateGroupsService; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Group\Events\UserAddedEvent; +use OCP\Group\Events\UserRemovedEvent; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IUser; +use OCP\IUserManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\TestCase; + +class UpdateGroupsServiceTest extends TestCase { + protected Group_Proxy&MockObject $groupBackend; + protected IEventDispatcher&MockObject $dispatcher; + protected IGroupManager&MockObject $groupManager; + protected IUserManager&MockObject $userManager; + protected LoggerInterface&MockObject $logger; + protected GroupMembershipMapper&MockObject $groupMembershipMapper; + protected UpdateGroupsService $updateGroupsService; + + public function setUp(): void { + $this->groupBackend = $this->createMock(Group_Proxy::class); + $this->dispatcher = $this->createMock(IEventDispatcher::class); + $this->groupManager = $this->createMock(IGroupManager::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->groupMembershipMapper = $this->createMock(GroupMembershipMapper::class); + + $this->updateGroupsService = new UpdateGroupsService( + $this->groupBackend, + $this->dispatcher, + $this->groupManager, + $this->userManager, + $this->logger, + $this->groupMembershipMapper, + ); + } + + public function testHandleKnownGroups(): void { + $knownGroups = [ + 'emptyGroup' => [], + 'stableGroup' => ['userA', 'userC', 'userE'], + 'groupWithAdditions' => ['userA', 'userC', 'userE'], + 'groupWithRemovals' => ['userA', 'userC', 'userDeleted', 'userE'], + 'groupWithAdditionsAndRemovals' => ['userA', 'userC', 'userE'], + 'vanishedGroup' => ['userB', 'userDeleted'], + ]; + $knownGroupsDB = []; + foreach ($knownGroups as $gid => $members) { + $knownGroupsDB[] = [ + 'owncloudname' => $gid, + 'owncloudusers' => $members + ]; + } + $actualGroups = [ + 'emptyGroup' => [], + 'stableGroup' => ['userA', 'userC', 'userE'], + 'groupWithAdditions' => ['userA', 'userC', 'userE', 'userF'], + 'groupWithRemovals' => ['userA', 'userE'], + 'groupWithAdditionsAndRemovals' => ['userC', 'userE', 'userF'], + 'newGroup' => ['userB', 'userF'], + ]; + $groups = array_intersect(array_keys($knownGroups), array_keys($actualGroups)); + + $this->groupMembershipMapper->expects($this->never()) + ->method('getKnownGroups'); + $this->groupMembershipMapper->expects($this->exactly(5)) + ->method('findGroupMemberships') + ->willReturnCallback( + fn ($group) => array_map( + fn ($userid) => GroupMembership::fromParams(['groupid' => $group,'userid' => $userid]), + $knownGroups[$group] + ) + ); + $this->groupMembershipMapper->expects($this->exactly(3)) + ->method('delete'); + $this->groupMembershipMapper->expects($this->exactly(2)) + ->method('insert'); + + $this->groupBackend->expects($this->any()) + ->method('usersInGroup') + ->willReturnCallback(function ($groupID) use ($actualGroups) { + return $actualGroups[$groupID] ?? []; + }); + + $this->groupManager->expects($this->any()) + ->method('get') + ->willReturnCallback(function (string $groupId): ?IGroup { + if ($groupId === 'vanishedGroup') { + return null; + } + return $this->createMock(IGroup::class); + }); + + $this->userManager->expects($this->exactly(5)) + ->method('get') + ->willReturnCallback(function (string $userId) { + if ($userId === 'userDeleted') { + // user already deleted + return null; + } + return $this->createMock(IUser::class); + }); + + $addedEvents = 0; + $removedEvents = 0; + $this->dispatcher->expects($this->exactly(4)) + ->method('dispatchTyped') + ->willReturnCallback(function ($event) use (&$addedEvents, &$removedEvents): void { + if ($event instanceof UserRemovedEvent) { + $removedEvents++; + } elseif ($event instanceof UserAddedEvent) { + $addedEvents++; + } + }); + + $this->updateGroupsService->handleKnownGroups($groups); + + $this->assertSame(2, $removedEvents); + $this->assertSame(2, $addedEvents); + // and no event for the user that is already deleted, the DB is nevertheless updated, hence 5 + } +} diff --git a/apps/user_ldap/tests/Settings/AdminTest.php b/apps/user_ldap/tests/Settings/AdminTest.php index 8161896e719..b17e96c1a68 100644 --- a/apps/user_ldap/tests/Settings/AdminTest.php +++ b/apps/user_ldap/tests/Settings/AdminTest.php @@ -1,36 +1,19 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests\Settings; use OCA\User_LDAP\Configuration; -use OCA\User_LDAP\Helper; use OCA\User_LDAP\Settings\Admin; use OCP\AppFramework\Http\TemplateResponse; use OCP\IL10N; -use OCP\Template; +use OCP\Server; +use OCP\Template\ITemplateManager; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; /** @@ -38,34 +21,31 @@ use Test\TestCase; * @package OCA\User_LDAP\Tests\Settings */ class AdminTest extends TestCase { - /** @var Admin */ - private $admin; - /** @var IL10N */ - private $l10n; + private IL10N&MockObject $l10n; + private ITemplateManager $templateManager; + private Admin $admin; - public function setUp() { + protected function setUp(): void { parent::setUp(); - $this->l10n = $this->getMockBuilder(IL10N::class)->getMock(); + $this->l10n = $this->createMock(IL10N::class); + $this->templateManager = Server::get(ITemplateManager::class); $this->admin = new Admin( - $this->l10n + $this->l10n, + $this->templateManager, ); } - /** - * @UseDB - */ - public function testGetForm() { - - $helper = new Helper(\OC::$server->getConfig()); - $prefixes = $helper->getServerConfigurationPrefixes(); - $hosts = $helper->getServerConfigurationHosts(); + public function testGetForm(): void { + $prefixes = ['s01']; + $hosts = ['s01' => '']; - $wControls = new Template('user_ldap', 'part.wizardcontrols'); + $wControls = $this->templateManager->getTemplate('user_ldap', 'part.wizardcontrols'); $wControls = $wControls->fetchPage(); - $sControls = new Template('user_ldap', 'part.settingcontrols'); + $sControls = $this->templateManager->getTemplate('user_ldap', 'part.settingcontrols'); $sControls = $sControls->fetchPage(); + $parameters = []; $parameters['serverConfigurationPrefixes'] = $prefixes; $parameters['serverConfigurationHosts'] = $hosts; $parameters['settingControls'] = $sControls; @@ -74,19 +54,19 @@ class AdminTest extends TestCase { // assign default values $config = new Configuration('', false); $defaults = $config->getDefaults(); - foreach($defaults as $key => $default) { - $parameters[$key.'_default'] = $default; + foreach ($defaults as $key => $default) { + $parameters[$key . '_default'] = $default; } $expected = new TemplateResponse('user_ldap', 'settings', $parameters); $this->assertEquals($expected, $this->admin->getForm()); } - public function testGetSection() { + public function testGetSection(): void { $this->assertSame('ldap', $this->admin->getSection()); } - public function testGetPriority() { + public function testGetPriority(): void { $this->assertSame(5, $this->admin->getPriority()); } } diff --git a/apps/user_ldap/tests/Settings/SectionTest.php b/apps/user_ldap/tests/Settings/SectionTest.php index 65dff000af3..3f9ae1e56d4 100644 --- a/apps/user_ldap/tests/Settings/SectionTest.php +++ b/apps/user_ldap/tests/Settings/SectionTest.php @@ -1,43 +1,24 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests\Settings; use OCA\User_LDAP\Settings\Section; use OCP\IL10N; use OCP\IURLGenerator; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class SectionTest extends TestCase { - /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ - private $url; - /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ - private $l; - /** @var Section */ - private $section; + private IURLGenerator&MockObject $url; + private IL10N&MockObject $l; + private Section $section; - public function setUp() { + protected function setUp(): void { parent::setUp(); $this->url = $this->createMock(IURLGenerator::class); $this->l = $this->createMock(IL10N::class); @@ -48,25 +29,25 @@ class SectionTest extends TestCase { ); } - public function testGetID() { + public function testGetID(): void { $this->assertSame('ldap', $this->section->getID()); } - public function testGetName() { + public function testGetName(): void { $this->l ->expects($this->once()) ->method('t') - ->with('LDAP / AD integration') - ->willReturn('LDAP / AD integration'); + ->with('LDAP/AD integration') + ->willReturn('LDAP/AD integration'); - $this->assertSame('LDAP / AD integration', $this->section->getName()); + $this->assertSame('LDAP/AD integration', $this->section->getName()); } - public function testGetPriority() { + public function testGetPriority(): void { $this->assertSame(25, $this->section->getPriority()); } - public function testGetIcon() { + public function testGetIcon(): void { $this->url->expects($this->once()) ->method('imagePath') ->with('user_ldap', 'app-dark.svg') diff --git a/apps/user_ldap/tests/User/DeletedUsersIndexTest.php b/apps/user_ldap/tests/User/DeletedUsersIndexTest.php new file mode 100644 index 00000000000..b245e52fe6e --- /dev/null +++ b/apps/user_ldap/tests/User/DeletedUsersIndexTest.php @@ -0,0 +1,101 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\User_LDAP\Tests\User; + +use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\User\DeletedUsersIndex; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Server; +use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * Class DeletedUsersIndexTest + * + * @group DB + * + * @package OCA\User_LDAP\Tests\User + */ +class DeletedUsersIndexTest extends \Test\TestCase { + protected DeletedUsersIndex $dui; + protected IConfig $config; + protected IDBConnection $db; + protected UserMapping&MockObject $mapping; + protected IManager&MockObject $shareManager; + + protected function setUp(): void { + parent::setUp(); + + // no mocks for those as tests go against DB + $this->config = Server::get(IConfig::class); + $this->db = Server::get(IDBConnection::class); + + // ensure a clean database + $this->config->deleteAppFromAllUsers('user_ldap'); + + $this->mapping = $this->createMock(UserMapping::class); + $this->shareManager = $this->createMock(IManager::class); + + $this->dui = new DeletedUsersIndex($this->config, $this->mapping, $this->shareManager); + } + + protected function tearDown(): void { + $this->config->deleteAppFromAllUsers('user_ldap'); + parent::tearDown(); + } + + public function testMarkAndFetchUser(): void { + $uids = [ + 'cef3775c-71d2-48eb-8984-39a4051b0b95', + '8c4bbb40-33ed-42d0-9b14-85b0ab76c1cc', + ]; + + // ensure test works on a pristine state + $this->assertFalse($this->dui->hasUsers()); + + $this->dui->markUser($uids[0]); + + $this->assertTrue($this->dui->hasUsers()); + + $this->dui->markUser($uids[1]); + + $deletedUsers = $this->dui->getUsers(); + $this->assertSame(2, count($deletedUsers)); + + // ensure the different uids were used + foreach ($deletedUsers as $deletedUser) { + $this->assertTrue(in_array($deletedUser->getOCName(), $uids)); + $i = array_search($deletedUser->getOCName(), $uids); + $this->assertNotFalse($i); + unset($uids[$i]); + } + $this->assertEmpty($uids); + } + + public function testUnmarkUser(): void { + $uids = [ + '22a162c7-a9ee-487c-9f33-0563795583fb', + '1fb4e0da-4a75-47f3-8fa7-becc7e35c9c5', + ]; + + // we know this works, because of "testMarkAndFetchUser" + $this->dui->markUser($uids[0]); + // this returns a working instance of OfflineUser + $testUser = $this->dui->getUsers()[0]; + $testUser->unmark(); + + // the DUI caches the users, to clear mark someone else + $this->dui->markUser($uids[1]); + + $deletedUsers = $this->dui->getUsers(); + foreach ($deletedUsers as $deletedUser) { + $this->assertNotSame($testUser->getOCName(), $deletedUser->getOCName()); + } + } +} diff --git a/apps/user_ldap/tests/User/ManagerTest.php b/apps/user_ldap/tests/User/ManagerTest.php index da30b210b17..bf9d1f5746f 100644 --- a/apps/user_ldap/tests/User/ManagerTest.php +++ b/apps/user_ldap/tests/User/ManagerTest.php @@ -1,44 +1,27 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Philippe Jung <phil.jung@free.fr> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Roger Szabo <roger.szabo@web.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\User; -use OCA\User_LDAP\FilesystemHelper; +use OCA\User_LDAP\Access; +use OCA\User_LDAP\Connection; use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\IUserTools; use OCA\User_LDAP\User\Manager; +use OCA\User_LDAP\User\User; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; use OCP\Image; use OCP\IUserManager; use OCP\Notification\IManager as INotificationManager; +use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; /** * Class Test_User_Manager @@ -48,226 +31,175 @@ use OCP\Notification\IManager as INotificationManager; * @package OCA\User_LDAP\Tests\User */ class ManagerTest extends \Test\TestCase { - - private function getTestInstances() { - $access = $this->createMock(IUserTools::class); - $config = $this->createMock(IConfig::class); - $filesys = $this->createMock(FilesystemHelper::class); - $log = $this->createMock(LogWrapper::class); - $avaMgr = $this->createMock(IAvatarManager::class); - $image = $this->createMock(Image::class); - $dbc = $this->createMock(IDBConnection::class); - $userMgr = $this->createMock(IUserManager::class); - $notiMgr = $this->createMock(INotificationManager::class); - - $connection = new \OCA\User_LDAP\Connection( - $lw = $this->createMock(ILDAPWrapper::class), - '', - null - ); - - $access->expects($this->any()) + protected Access&MockObject $access; + protected IConfig&MockObject $config; + protected LoggerInterface&MockObject $logger; + protected IAvatarManager&MockObject $avatarManager; + protected Image&MockObject $image; + protected IDBConnection&MockObject $dbc; + protected IUserManager&MockObject $ncUserManager; + protected INotificationManager&MockObject $notificationManager; + protected ILDAPWrapper&MockObject $ldapWrapper; + protected Connection $connection; + protected IManager&MockObject $shareManager; + protected Manager $manager; + + protected function setUp(): void { + parent::setUp(); + + $this->access = $this->createMock(Access::class); + $this->config = $this->createMock(IConfig::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->avatarManager = $this->createMock(IAvatarManager::class); + $this->image = $this->createMock(Image::class); + $this->ncUserManager = $this->createMock(IUserManager::class); + $this->notificationManager = $this->createMock(INotificationManager::class); + $this->ldapWrapper = $this->createMock(ILDAPWrapper::class); + $this->shareManager = $this->createMock(IManager::class); + + $this->connection = new Connection($this->ldapWrapper, '', null); + + $this->access->expects($this->any()) ->method('getConnection') - ->will($this->returnValue($connection)); + ->willReturn($this->connection); + + /** @noinspection PhpUnhandledExceptionInspection */ + $this->manager = new Manager( + $this->config, + $this->logger, + $this->avatarManager, + $this->image, + $this->ncUserManager, + $this->notificationManager, + $this->shareManager + ); - return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr); + $this->manager->setLdapAccess($this->access); } - public function testGetByDNExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + public static function dnProvider(): array { + return [ + ['cn=foo,dc=foobar,dc=bar'], + ['uid=foo,o=foobar,c=bar'], + ['ab=cde,f=ghei,mno=pq'], + ]; + } - $inputDN = 'cn=foo,dc=foobar,dc=bar'; + #[\PHPUnit\Framework\Attributes\DataProvider('dnProvider')] + public function testGetByDNExisting(string $inputDN): void { $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('stringResemblesDN') ->with($this->equalTo($inputDN)) - ->will($this->returnValue(true)); - - $access->expects($this->once()) + ->willReturn(true); + $this->access->expects($this->once()) ->method('dn2username') ->with($this->equalTo($inputDN)) - ->will($this->returnValue($uid)); - - $access->expects($this->never()) + ->willReturn($uid); + $this->access->expects($this->never()) ->method('username2dn'); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->manager->get($inputDN); // Now we fetch the user again. If this leads to a failing test, // runtime caching the manager is broken. - $user = $manager->get($inputDN); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($inputDN); - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); + $this->assertInstanceOf(User::class, $user); } - public function testGetByEDirectoryDN() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $inputDN = 'uid=foo,o=foobar,c=bar'; - $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - - $access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue(true)); - - $access->expects($this->once()) - ->method('dn2username') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue($uid)); - - $access->expects($this->never()) - ->method('username2dn'); - - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); - - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); - } - - public function testGetByExoticDN() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $inputDN = 'ab=cde,f=ghei,mno=pq'; - $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - - $access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue(true)); - - $access->expects($this->once()) - ->method('dn2username') - ->with($this->equalTo($inputDN)) - ->will($this->returnValue($uid)); - - $access->expects($this->never()) - ->method('username2dn'); - - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); - - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); - } - - public function testGetByDNNotExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testGetByDNNotExisting(): void { $inputDN = 'cn=gone,dc=foobar,dc=bar'; - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('stringResemblesDN') ->with($this->equalTo($inputDN)) - ->will($this->returnValue(true)); - - $access->expects($this->once()) + ->willReturn(true); + $this->access->expects($this->once()) ->method('dn2username') ->with($this->equalTo($inputDN)) - ->will($this->returnValue(false)); - - $access->expects($this->once()) + ->willReturn(false); + $this->access->expects($this->once()) ->method('username2dn') ->with($this->equalTo($inputDN)) - ->will($this->returnValue(false)); + ->willReturn(false); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($inputDN); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($inputDN); $this->assertNull($user); } - public function testGetByUidExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testGetByUidExisting(): void { $dn = 'cn=foo,dc=foobar,dc=bar'; $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2username'); - - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('username2dn') ->with($this->equalTo($uid)) - ->will($this->returnValue($dn)); - - $access->expects($this->once()) + ->willReturn($dn); + $this->access->expects($this->once()) ->method('stringResemblesDN') ->with($this->equalTo($uid)) - ->will($this->returnValue(false)); + ->willReturn(false); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($uid); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->manager->get($uid); // Now we fetch the user again. If this leads to a failing test, // runtime caching the manager is broken. - $user = $manager->get($uid); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($uid); - $this->assertInstanceOf('\OCA\User_LDAP\User\User', $user); + $this->assertInstanceOf(User::class, $user); } - public function testGetByUidNotExisting() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testGetByUidNotExisting(): void { $uid = 'gone'; - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2username'); - - $access->expects($this->exactly(1)) + $this->access->expects($this->exactly(1)) ->method('username2dn') ->with($this->equalTo($uid)) - ->will($this->returnValue(false)); + ->willReturn(false); - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - $user = $manager->get($uid); + /** @noinspection PhpUnhandledExceptionInspection */ + $user = $this->manager->get($uid); $this->assertNull($user); } - public function testGetAttributesAll() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - - $connection = $access->getConnection(); - $connection->setConfiguration(array('ldapEmailAttribute' => 'mail')); - - $attributes = $manager->getAttributes(); - - $this->assertTrue(in_array('dn', $attributes)); - $this->assertTrue(in_array($access->getConnection()->ldapEmailAttribute, $attributes)); - $this->assertTrue(in_array('jpegphoto', $attributes)); - $this->assertTrue(in_array('thumbnailphoto', $attributes)); + public static function attributeRequestProvider(): array { + return [ + [false], + [true], + ]; } - public function testGetAttributesMinimal() { - list($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $manager = new Manager($config, $filesys, $log, $avaMgr, $image, $dbc, $userMgr, $notiMgr); - $manager->setLdapAccess($access); - - $attributes = $manager->getAttributes(true); - - $this->assertTrue(in_array('dn', $attributes)); - $this->assertTrue(!in_array('jpegphoto', $attributes)); - $this->assertTrue(!in_array('thumbnailphoto', $attributes)); + #[\PHPUnit\Framework\Attributes\DataProvider('attributeRequestProvider')] + public function testGetAttributes($minimal): void { + $this->connection->setConfiguration([ + 'ldapEmailAttribute' => 'MAIL', + 'ldapUserAvatarRule' => 'default', + 'ldapQuotaAttribute' => '', + 'ldapUserDisplayName2' => 'Mail', + ]); + + $attributes = $this->manager->getAttributes($minimal); + + $this->assertContains('dn', $attributes); + $this->assertContains(strtolower($this->access->getConnection()->ldapEmailAttribute), $attributes); + $this->assertNotContains($this->access->getConnection()->ldapEmailAttribute, $attributes); #cases check + $this->assertNotContains('', $attributes); + $this->assertSame(!$minimal, in_array('jpegphoto', $attributes)); + $this->assertSame(!$minimal, in_array('thumbnailphoto', $attributes)); + $valueCounts = array_count_values($attributes); + $this->assertSame(1, $valueCounts['mail']); } - } diff --git a/apps/user_ldap/tests/User/OfflineUserTest.php b/apps/user_ldap/tests/User/OfflineUserTest.php new file mode 100644 index 00000000000..223e63421ad --- /dev/null +++ b/apps/user_ldap/tests/User/OfflineUserTest.php @@ -0,0 +1,65 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\User_LDAP\Tests\User; + +use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\User\OfflineUser; +use OCP\IConfig; +use OCP\Share\IManager; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class OfflineUserTest extends TestCase { + protected UserMapping&MockObject $mapping; + protected string $uid; + protected IConfig&MockObject $config; + protected IManager&MockObject $shareManager; + protected OfflineUser $offlineUser; + + public function setUp(): void { + $this->uid = 'deborah'; + $this->config = $this->createMock(IConfig::class); + $this->mapping = $this->createMock(UserMapping::class); + $this->shareManager = $this->createMock(IManager::class); + + $this->offlineUser = new OfflineUser( + $this->uid, + $this->config, + $this->mapping, + $this->shareManager + ); + } + + public static function shareOwnerProvider(): array { + return [ + [[], false], + [[IShare::TYPE_USER], true], + [[IShare::TYPE_GROUP, IShare::TYPE_LINK], true], + [[IShare::TYPE_EMAIL, IShare::TYPE_REMOTE, IShare::TYPE_CIRCLE], true], + [[IShare::TYPE_GUEST, IShare::TYPE_REMOTE_GROUP, IShare::TYPE_ROOM], true], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('shareOwnerProvider')] + public function testHasActiveShares(array $existingShareTypes, bool $expected): void { + $shareMock = $this->createMock(IShare::class); + + $this->shareManager->expects($this->atLeastOnce()) + ->method('getSharesBy') + ->willReturnCallback(function (string $uid, int $shareType) use ($existingShareTypes, $shareMock) { + if (in_array($shareType, $existingShareTypes)) { + return [$shareMock]; + } + return []; + }); + + $this->assertSame($expected, $this->offlineUser->getHasActiveShares()); + } +} diff --git a/apps/user_ldap/tests/User/UserTest.php b/apps/user_ldap/tests/User/UserTest.php index 27bd7762e39..00edd8b3f9b 100644 --- a/apps/user_ldap/tests/User/UserTest.php +++ b/apps/user_ldap/tests/User/UserTest.php @@ -1,50 +1,28 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Juan Pablo Villafáñez <jvillafanez@solidgear.es> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Roger Szabo <roger.szabo@web.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Victor Dubiniuk <dubiniuk@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests\User; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; -use OCA\User_LDAP\FilesystemHelper; use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\IUserTools; use OCA\User_LDAP\User\User; use OCP\IAvatar; use OCP\IAvatarManager; use OCP\IConfig; -use OCP\IDBConnection; use OCP\Image; use OCP\IUser; use OCP\IUserManager; use OCP\Notification\IManager as INotificationManager; use OCP\Notification\INotification; +use OCP\Util; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; /** * Class UserTest @@ -54,410 +32,309 @@ use OCP\Notification\INotification; * @package OCA\User_LDAP\Tests\User */ class UserTest extends \Test\TestCase { - /** @var Access|\PHPUnit_Framework_MockObject_MockObject */ - protected $access; - /** @var Connection|\PHPUnit_Framework_MockObject_MockObject */ - protected $connection; + protected Access&MockObject $access; + protected Connection&MockObject $connection; + protected IConfig&MockObject $config; + protected INotificationManager&MockObject $notificationManager; + protected IUserManager&MockObject $userManager; + protected Image&MockObject $image; + protected IAvatarManager&MockObject $avatarManager; + protected LoggerInterface&MockObject $logger; + protected string $uid = 'alice'; + protected string $dn = 'uid=alice,dc=foo,dc=bar'; + protected User $user; + + protected function setUp(): void { + parent::setUp(); - public function setUp() { - /** @var Access|\PHPUnit_Framework_MockObject_MockObject access */ - $this->access = $this->createMock(Access::class); - $this->connection = $this->createMock(Connection::class); + $this->connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) + ->getMock(); + $this->access = $this->createMock(Access::class); $this->access->connection = $this->connection; $this->access->expects($this->any()) ->method('getConnection') ->willReturn($this->connection); - parent::setUp(); + $this->config = $this->createMock(IConfig::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->avatarManager = $this->createMock(IAvatarManager::class); + $this->image = $this->createMock(Image::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->notificationManager = $this->createMock(INotificationManager::class); + + $this->user = new User( + $this->uid, + $this->dn, + $this->access, + $this->config, + $this->image, + $this->logger, + $this->avatarManager, + $this->userManager, + $this->notificationManager + ); } - private function getTestInstances() { - $access = $this->createMock(IUserTools::class); - $config = $this->createMock(IConfig::class); - $filesys = $this->createMock(FilesystemHelper::class); - $log = $this->createMock(LogWrapper::class); - $avaMgr = $this->createMock(IAvatarManager::class); - $image = $this->createMock(Image::class); - $dbc = $this->createMock(IDBConnection::class); - $userMgr = $this->createMock(IUserManager::class); - $notiMgr = $this->createMock(INotificationManager::class); - - return array($access, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr); + public function testGetDNandUsername(): void { + $this->assertSame($this->dn, $this->user->getDN()); + $this->assertSame($this->uid, $this->user->getUsername()); } - public function testGetDNandUsername() { - list($access, $config, $filesys, $image, $log, $avaMgr, $db, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $this->assertSame($dn, $user->getDN()); - $this->assertSame($uid, $user->getUsername()); - } - - public function testUpdateEmailProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testUpdateEmailProvided(): void { $this->connection->expects($this->once()) ->method('__get') ->with($this->equalTo('ldapEmailAttribute')) - ->will($this->returnValue('email')); + ->willReturn('email'); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('email')) - ->will($this->returnValue(array('alice@foo.bar'))); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + ->willReturn(['alice@foo.bar']); - $uuser = $this->getMockBuilder(IUser::class) - ->disableOriginalConstructor() - ->getMock(); - $uuser->expects($this->once()) - ->method('setEMailAddress') + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) + ->method('setSystemEMailAddress') ->with('alice@foo.bar'); - /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject $userMgr */ - $userMgr->expects($this->any()) + + $this->userManager->expects($this->any()) ->method('get') - ->willReturn($uuser); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + ->willReturn($coreUser); - $user->updateEmail(); + $this->user->updateEmail(); } - public function testUpdateEmailNotProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testUpdateEmailNotProvided(): void { $this->connection->expects($this->once()) ->method('__get') ->with($this->equalTo('ldapEmailAttribute')) - ->will($this->returnValue('email')); + ->willReturn('email'); + $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('email')) - ->will($this->returnValue(false)); + ->willReturn(false); - $config->expects($this->never()) + $this->config->expects($this->never()) ->method('setUserValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateEmail(); + $this->user->updateEmail(); } - public function testUpdateEmailNotConfigured() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testUpdateEmailNotConfigured(): void { $this->connection->expects($this->once()) ->method('__get') ->with($this->equalTo('ldapEmailAttribute')) - ->will($this->returnValue('')); + ->willReturn(''); $this->access->expects($this->never()) ->method('readAttribute'); - $config->expects($this->never()) + $this->config->expects($this->never()) ->method('setUserValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateEmail(); + $this->user->updateEmail(); } - public function testUpdateQuotaAllProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) + public function testUpdateQuotaAllProvided(): void { + $this->connection->expects($this->exactly(2)) ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->exactly(1)) - ->method('__get'); + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', ''] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(array('42 GB'))); + ->willReturn(['42 GB']); - $user = $this->createMock(IUser::class); - $user->expects($this->once()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) ->method('setQuota') ->with('42 GB'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + ->with($this->uid) + ->willReturn($coreUser); - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaToDefaultAllProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) + public function testUpdateQuotaToDefaultAllProvided(): void { + $this->connection->expects($this->exactly(2)) ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->exactly(1)) - ->method('__get'); + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', ''] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(array('default'))); + ->willReturn(['default']); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->once()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) ->method('setQuota') ->with('default'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->once()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + ->with($this->uid) + ->willReturn($coreUser); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaToNoneAllProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) + public function testUpdateQuotaToNoneAllProvided(): void { + $this->connection->expects($this->exactly(2)) ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->exactly(1)) - ->method('__get'); + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', ''] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(array('none'))); + ->willReturn(['none']); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->once()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) ->method('setQuota') ->with('none'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->once()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); + ->with($this->uid) + ->willReturn($coreUser); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaDefaultProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('25 GB')); + public function testUpdateQuotaDefaultProvided(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', '25 GB'], + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(false)); + ->willReturn(false); - $user = $this->createMock(IUser::class); - $user->expects($this->once()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) ->method('setQuota') ->with('25 GB'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->once()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); + ->with($this->uid) + ->willReturn($coreUser); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaIndividualProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) + public function testUpdateQuotaIndividualProvided(): void { + $this->connection->expects($this->exactly(2)) ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->exactly(1)) - ->method('__get'); + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', ''] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(array('27 GB'))); + ->willReturn(['27 GB']); - $user = $this->createMock(IUser::class); - $user->expects($this->once()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) ->method('setQuota') ->with('27 GB'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->once()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + ->with($this->uid) + ->willReturn($coreUser); - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaNoneProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('')); + public function testUpdateQuotaNoneProvided(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', ''] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(false)); + ->willReturn(false); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->never()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->never()) ->method('setQuota'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->never()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); + ->with($this->uid); - $config->expects($this->never()) + $this->config->expects($this->never()) ->method('setUserValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaNoneConfigured() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('')); + public function testUpdateQuotaNoneConfigured(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', ''], + ['ldapQuotaDefault', ''] + ]); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->never()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->never()) ->method('setQuota'); - $userMgr->expects($this->once()) - ->method('get') - ->with('alice') - ->will($this->returnValue($user)); + $this->userManager->expects($this->never()) + ->method('get'); $this->access->expects($this->never()) ->method('readAttribute'); - $config->expects($this->never()) + $this->config->expects($this->never()) ->method('setUserValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } - public function testUpdateQuotaFromValue() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testUpdateQuotaFromValue(): void { $readQuota = '19 GB'; - $this->connection->expects($this->never()) + $this->connection->expects($this->exactly(2)) ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')); + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', ''] + ]); $this->access->expects($this->never()) ->method('readAttribute'); @@ -467,787 +344,836 @@ class UserTest extends \Test\TestCase { ->method('setQuota') ->with($readQuota); - $userMgr->expects($this->once()) + $this->userManager->expects($this->once()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + ->with($this->uid) + ->willReturn($user); - $user->updateQuota($readQuota); + $this->user->updateQuota($readQuota); } /** * Unparseable quota will fallback to use the LDAP default */ - public function testUpdateWrongQuotaAllProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('23 GB')); + public function testUpdateWrongQuotaAllProvided(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', '23 GB'] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(array('42 GBwos'))); + ->willReturn(['42 GBwos']); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->once()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->once()) ->method('setQuota') ->with('23 GB'); - $userMgr->expects($this->once()) + $this->userManager->expects($this->once()) ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + ->with($this->uid) + ->willReturn($coreUser); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } /** * No user quota and wrong default will set 'default' as quota */ - public function testUpdateWrongDefaultQuotaProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('23 GBwowowo')); + public function testUpdateWrongDefaultQuotaProvided(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', '23 GBwowowo'] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(false)); + ->willReturn(false); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->never()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->never()) ->method('setQuota'); - $userMgr->expects($this->once()) - ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->userManager->expects($this->never()) + ->method('get'); - $user->updateQuota(); + $this->user->updateQuota(); } /** * Wrong user quota and wrong default will set 'default' as quota */ - public function testUpdateWrongQuotaAndDefaultAllProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('myquota')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('23 GBwowowo')); + public function testUpdateWrongQuotaAndDefaultAllProvided(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', 'myquota'], + ['ldapQuotaDefault', '23 GBwowowo'] + ]); $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), + ->with($this->equalTo($this->dn), $this->equalTo('myquota')) - ->will($this->returnValue(array('23 flush'))); + ->willReturn(['23 flush']); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->never()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->never()) ->method('setQuota'); - $userMgr->expects($this->once()) - ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + $this->userManager->expects($this->never()) + ->method('get'); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->updateQuota(); + $this->user->updateQuota(); } /** * No quota attribute set and wrong default will set 'default' as quota */ - public function testUpdateWrongDefaultQuotaNotProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->will($this->returnValue('')); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->will($this->returnValue('23 GBwowowo')); + public function testUpdateWrongDefaultQuotaNotProvided(): void { $this->connection->expects($this->exactly(2)) - ->method('__get'); + ->method('__get') + ->willReturnMap([ + ['ldapQuotaAttribute', ''], + ['ldapQuotaDefault', '23 GBwowowo'] + ]); $this->access->expects($this->never()) ->method('readAttribute'); - $user = $this->createMock('\OCP\IUser'); - $user->expects($this->never()) + $coreUser = $this->createMock(IUser::class); + $coreUser->expects($this->never()) ->method('setQuota'); - $userMgr->expects($this->once()) - ->method('get') - ->with('alice') - ->will($this->returnValue($user)); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->userManager->expects($this->never()) + ->method('get'); - $user->updateQuota(); + $this->user->updateQuota(); } - //the testUpdateAvatar series also implicitely tests getAvatarImage - public function testUpdateAvatarJpegPhotoProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, , $userMgr, $notiMgr) = - $this->getTestInstances(); - + //the testUpdateAvatar series also implicitly tests getAvatarImage + public function XtestUpdateAvatarJpegPhotoProvided() { $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), - $this->equalTo('jpegPhoto')) - ->will($this->returnValue(array('this is a photo'))); - - $image->expects($this->once()) + ->with($this->equalTo($this->dn), + $this->equalTo('jpegphoto')) + ->willReturn(['this is a photo']); + + $this->image->expects($this->once()) + ->method('loadFromBase64') + ->willReturn('imageResource'); + $this->image->expects($this->once()) ->method('valid') - ->will($this->returnValue(true)); - $image->expects($this->once()) + ->willReturn(true); + $this->image->expects($this->once()) ->method('width') - ->will($this->returnValue(128)); - $image->expects($this->once()) + ->willReturn(128); + $this->image->expects($this->once()) ->method('height') - ->will($this->returnValue(128)); - $image->expects($this->once()) + ->willReturn(128); + $this->image->expects($this->once()) ->method('centerCrop') - ->will($this->returnValue(true)); + ->willReturn(true); + $this->image->expects($this->once()) + ->method('data') + ->willReturn('this is a photo'); - $filesys->expects($this->once()) - ->method('isLoaded') - ->will($this->returnValue(true)); + $this->config->expects($this->once()) + ->method('getUserValue') + ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') + ->willReturn(''); + $this->config->expects($this->once()) + ->method('setUserValue') + ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo')); $avatar = $this->createMock(IAvatar::class); $avatar->expects($this->once()) ->method('set') - ->with($this->isInstanceOf($image)); + ->with($this->image); - $avaMgr->expects($this->once()) + $this->avatarManager->expects($this->once()) ->method('getAvatar') - ->with($this->equalTo('alice')) - ->will($this->returnValue($avatar)); + ->with($this->equalTo($this->uid)) + ->willReturn($avatar); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); - $user->updateAvatar(); + $this->user->updateAvatar(); } - public function testUpdateAvatarThumbnailPhotoProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + public function testUpdateAvatarKnownJpegPhotoProvided(): void { + $this->access->expects($this->once()) + ->method('readAttribute') + ->with($this->equalTo($this->dn), + $this->equalTo('jpegphoto')) + ->willReturn(['this is a photo']); + + $this->image->expects($this->once()) + ->method('loadFromBase64') + ->willReturn('imageResource'); + $this->image->expects($this->never()) + ->method('valid'); + $this->image->expects($this->never()) + ->method('width'); + $this->image->expects($this->never()) + ->method('height'); + $this->image->expects($this->never()) + ->method('centerCrop'); + $this->image->expects($this->once()) + ->method('data') + ->willReturn('this is a photo'); + + $this->config->expects($this->once()) + ->method('getUserValue') + ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') + ->willReturn(md5('this is a photo')); + $this->config->expects($this->never()) + ->method('setUserValue'); + + $avatar = $this->createMock(IAvatar::class); + $avatar->expects($this->never()) + ->method('set'); + $avatar->expects($this->any()) + ->method('exists') + ->willReturn(true); + $avatar->expects($this->any()) + ->method('isCustomAvatar') + ->willReturn(true); + + $this->avatarManager->expects($this->any()) + ->method('getAvatar') + ->with($this->uid) + ->willReturn($avatar); + + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); + $this->assertTrue($this->user->updateAvatar()); + } + + public function XtestUpdateAvatarThumbnailPhotoProvided() { $this->access->expects($this->any()) ->method('readAttribute') - ->willReturnCallback(function($dn, $attr) { - if($dn === 'uid=alice,dc=foo,dc=bar' - && $attr === 'jpegPhoto') - { + ->willReturnCallback(function ($dn, $attr) { + if ($dn === $this->dn + && $attr === 'jpegphoto') { return false; - } elseif($dn === 'uid=alice,dc=foo,dc=bar' - && $attr === 'thumbnailPhoto') - { + } elseif ($dn === $this->dn + && $attr === 'thumbnailphoto') { return ['this is a photo']; } return null; }); - $image->expects($this->once()) + $this->image->expects($this->once()) + ->method('loadFromBase64') + ->willReturn('imageResource'); + $this->image->expects($this->once()) ->method('valid') - ->will($this->returnValue(true)); - $image->expects($this->once()) + ->willReturn(true); + $this->image->expects($this->once()) ->method('width') - ->will($this->returnValue(128)); - $image->expects($this->once()) + ->willReturn(128); + $this->image->expects($this->once()) ->method('height') - ->will($this->returnValue(128)); - $image->expects($this->once()) + ->willReturn(128); + $this->image->expects($this->once()) ->method('centerCrop') - ->will($this->returnValue(true)); + ->willReturn(true); + $this->image->expects($this->once()) + ->method('data') + ->willReturn('this is a photo'); - $filesys->expects($this->once()) - ->method('isLoaded') - ->will($this->returnValue(true)); + $this->config->expects($this->once()) + ->method('getUserValue') + ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') + ->willReturn(''); + $this->config->expects($this->once()) + ->method('setUserValue') + ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo')); $avatar = $this->createMock(IAvatar::class); $avatar->expects($this->once()) ->method('set') - ->with($this->isInstanceOf($image)); + ->with($this->image); - $avaMgr->expects($this->once()) + $this->avatarManager->expects($this->once()) ->method('getAvatar') - ->with($this->equalTo('alice')) - ->will($this->returnValue($avatar)); + ->with($this->equalTo($this->uid)) + ->willReturn($avatar); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); - $user->updateAvatar(); + $this->user->updateAvatar(); } - public function testUpdateAvatarNotProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testUpdateAvatarCorruptPhotoProvided(): void { $this->access->expects($this->any()) ->method('readAttribute') - ->willReturnCallback(function($dn, $attr) { - if($dn === 'uid=alice,dc=foo,dc=bar' - && $attr === 'jpegPhoto') - { - return false; - } elseif($dn === 'uid=alice,dc=foo,dc=bar' - && $attr === 'thumbnailPhoto') - { + ->willReturnCallback(function ($dn, $attr) { + if ($dn === $this->dn + && $attr === 'jpegphoto') { return false; + } elseif ($dn === $this->dn + && $attr === 'thumbnailphoto') { + return ['this is a photo']; } return null; }); - $image->expects($this->never()) + $this->image->expects($this->once()) + ->method('loadFromBase64') + ->willReturn(false); + $this->image->expects($this->never()) ->method('valid'); - $image->expects($this->never()) + $this->image->expects($this->never()) ->method('width'); - $image->expects($this->never()) + $this->image->expects($this->never()) ->method('height'); - $image->expects($this->never()) + $this->image->expects($this->never()) ->method('centerCrop'); + $this->image->expects($this->never()) + ->method('data'); - $filesys->expects($this->never()) - ->method('isLoaded'); + $this->config->expects($this->never()) + ->method('getUserValue'); + $this->config->expects($this->never()) + ->method('setUserValue'); - $avaMgr->expects($this->never()) - ->method('getAvatar'); + $avatar = $this->createMock(IAvatar::class); + $avatar->expects($this->never()) + ->method('set'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + $this->avatarManager->expects($this->never()) + ->method('getAvatar'); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); - $user->updateAvatar(); + $this->user->updateAvatar(); } - public function testUpdateBeforeFirstLogin() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + public function XtestUpdateAvatarUnsupportedThumbnailPhotoProvided() { + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturnCallback(function ($dn, $attr) { + if ($dn === $this->dn + && $attr === 'jpegphoto') { + return false; + } elseif ($dn === $this->dn + && $attr === 'thumbnailphoto') { + return ['this is a photo']; + } + return null; + }); - $config->expects($this->at(0)) - ->method('getUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN), - $this->equalTo(0)) - ->will($this->returnValue(0)); - $config->expects($this->at(1)) + $this->image->expects($this->once()) + ->method('loadFromBase64') + ->willReturn('imageResource'); + $this->image->expects($this->once()) + ->method('valid') + ->willReturn(true); + $this->image->expects($this->once()) + ->method('width') + ->willReturn(128); + $this->image->expects($this->once()) + ->method('height') + ->willReturn(128); + $this->image->expects($this->once()) + ->method('centerCrop') + ->willReturn(true); + $this->image->expects($this->once()) + ->method('data') + ->willReturn('this is a photo'); + + $this->config->expects($this->once()) ->method('getUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_LASTREFRESH), - $this->equalTo(0)) - ->will($this->returnValue(0)); - $config->expects($this->exactly(2)) - ->method('getUserValue'); - $config->expects($this->never()) + ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') + ->willReturn(''); + $this->config->expects($this->never()) ->method('setUserValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + $avatar = $this->createMock(IAvatar::class); + $avatar->expects($this->once()) + ->method('set') + ->with($this->image) + ->willThrowException(new \Exception()); + + $this->avatarManager->expects($this->once()) + ->method('getAvatar') + ->with($this->equalTo($this->uid)) + ->willReturn($avatar); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); - $user->update(); + $this->assertFalse($this->user->updateAvatar()); } - public function testUpdateAfterFirstLogin() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + public function testUpdateAvatarNotProvided(): void { + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturnCallback(function ($dn, $attr) { + if ($dn === $this->dn + && $attr === 'jpegPhoto') { + return false; + } elseif ($dn === $this->dn + && $attr === 'thumbnailPhoto') { + return false; + } + return null; + }); - $config->expects($this->at(0)) - ->method('getUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN), - $this->equalTo(0)) - ->will($this->returnValue(1)); - $config->expects($this->at(1)) - ->method('getUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_LASTREFRESH), - $this->equalTo(0)) - ->will($this->returnValue(0)); - $config->expects($this->exactly(2)) + $this->image->expects($this->never()) + ->method('valid'); + $this->image->expects($this->never()) + ->method('width'); + $this->image->expects($this->never()) + ->method('height'); + $this->image->expects($this->never()) + ->method('centerCrop'); + $this->image->expects($this->never()) + ->method('data'); + + $this->config->expects($this->never()) ->method('getUserValue'); - $config->expects($this->once()) - ->method('setUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_LASTREFRESH), - $this->anything()) - ->will($this->returnValue(true)); + $this->config->expects($this->never()) + ->method('setUserValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + $this->avatarManager->expects($this->never()) + ->method('getAvatar'); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); - $user->update(); + $this->user->updateAvatar(); } - public function testUpdateNoRefresh() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $config->expects($this->at(0)) - ->method('getUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN), - $this->equalTo(0)) - ->will($this->returnValue(1)); - $config->expects($this->at(1)) - ->method('getUserValue') - ->with($this->equalTo('alice'), $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_LASTREFRESH), - $this->equalTo(0)) - ->will($this->returnValue(time() - 10)); - - $config->expects($this->once()) - ->method('getAppValue') - ->with($this->equalTo('user_ldap'), - $this->equalTo('updateAttributesInterval'), - $this->anything()) - ->will($this->returnValue(1800)); - $config->expects($this->exactly(2)) - ->method('getUserValue'); - $config->expects($this->never()) - ->method('setUserValue'); + public static function extStorageHomeDataProvider(): array { + return [ + [ 'myFolder', null ], + [ '', null, false ], + [ 'myFolder', 'myFolder' ], + ]; + } - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; + #[\PHPUnit\Framework\Attributes\DataProvider('extStorageHomeDataProvider')] + public function testUpdateExtStorageHome(string $expected, ?string $valueFromLDAP = null, bool $isSet = true): void { + if ($valueFromLDAP === null) { + $this->connection->expects($this->once()) + ->method('__get') + ->willReturnMap([ + ['ldapExtStorageHomeAttribute', 'homeDirectory'], + ]); + + $return = []; + if ($isSet) { + $return[] = $expected; + } + $this->access->expects($this->once()) + ->method('readAttribute') + ->with($this->dn, 'homeDirectory') + ->willReturn($return); + } - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + if ($expected !== '') { + $this->config->expects($this->once()) + ->method('setUserValue') + ->with($this->uid, 'user_ldap', 'extStorageHome', $expected); + } else { + $this->config->expects($this->once()) + ->method('deleteUserValue') + ->with($this->uid, 'user_ldap', 'extStorageHome'); + } - $user->update(); + $actual = $this->user->updateExtStorageHome($valueFromLDAP); + $this->assertSame($expected, $actual); } - public function testMarkLogin() { - list(, $config, $filesys, $image, $log, $avaMgr, $db, $userMgr, $notiMgr) = - $this->getTestInstances(); - - $config->expects($this->once()) + public function testMarkLogin(): void { + $this->config->expects($this->once()) ->method('setUserValue') - ->with($this->equalTo('alice'), + ->with($this->equalTo($this->uid), $this->equalTo('user_ldap'), $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN), $this->equalTo(1)) - ->will($this->returnValue(true)); + ->willReturn(true); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->markLogin(); + $this->user->markLogin(); } - public function testGetAvatarImageProvided() { - list(, $config, $filesys, $image, $log, $avaMgr, $db, $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testGetAvatarImageProvided(): void { $this->access->expects($this->once()) ->method('readAttribute') - ->with($this->equalTo('uid=alice,dc=foo,dc=bar'), - $this->equalTo('jpegPhoto')) - ->will($this->returnValue(array('this is a photo'))); - - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); + ->with($this->equalTo($this->dn), + $this->equalTo('jpegphoto')) + ->willReturn(['this is a photo']); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); - $photo = $user->getAvatarImage(); + $photo = $this->user->getAvatarImage(); $this->assertSame('this is a photo', $photo); //make sure readAttribute is not called again but the already fetched //photo is returned - $photo = $user->getAvatarImage(); + $this->user->getAvatarImage(); } - public function testProcessAttributes() { - list(, $config, $filesys, $image, $log, $avaMgr, , $userMgr, $notiMgr) = - $this->getTestInstances(); + public function testGetAvatarImageDisabled(): void { + $this->access->expects($this->never()) + ->method('readAttribute') + ->with($this->equalTo($this->dn), $this->anything()); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn([]); + + $this->assertFalse($this->user->getAvatarImage()); + } - $uid = 'alice'; - $dn = 'uid=alice'; + public static function imageDataProvider(): array { + return [ + [ false, false ], + [ 'corruptData', false ], + [ 'validData', true ], + ]; + } - $requiredMethods = array( - 'markRefreshTime', + public function testProcessAttributes(): void { + $requiredMethods = [ 'updateQuota', 'updateEmail', 'composeAndStoreDisplayName', 'storeLDAPUserName', 'getHomePath', - 'updateAvatar' - ); + 'updateAvatar', + 'updateExtStorageHome', + ]; - $userMock = $this->getMockBuilder('OCA\User_LDAP\User\User') - ->setConstructorArgs(array($uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr)) - ->setMethods($requiredMethods) + /** @var User&MockObject $userMock */ + $userMock = $this->getMockBuilder(User::class) + ->setConstructorArgs([ + $this->uid, + $this->dn, + $this->access, + $this->config, + $this->image, + $this->logger, + $this->avatarManager, + $this->userManager, + $this->notificationManager + ]) + ->onlyMethods($requiredMethods) ->getMock(); - $this->connection->setConfiguration(array( + $this->connection->setConfiguration([ 'homeFolderNamingRule' => 'homeDirectory' - )); + ]); $this->connection->expects($this->any()) ->method('__get') - //->will($this->returnArgument(0)); - ->will($this->returnCallback(function($name) { - if($name === 'homeFolderNamingRule') { + ->willReturnCallback(function ($name) { + if ($name === 'homeFolderNamingRule') { return 'attr:homeDirectory'; } return $name; - })); - - $record = array( - strtolower($this->connection->ldapQuotaAttribute) => array('4096'), - strtolower($this->connection->ldapEmailAttribute) => array('alice@wonderland.org'), - strtolower($this->connection->ldapUserDisplayName) => array('Aaaaalice'), - 'uid' => array($uid), - 'homedirectory' => array('Alice\'s Folder'), - 'memberof' => array('cn=groupOne', 'cn=groupTwo'), - 'jpegphoto' => array('here be an image') - ); + }); + $this->connection->expects($this->any()) + ->method('resolveRule') + ->with('avatar') + ->willReturn(['jpegphoto', 'thumbnailphoto']); + + $record = [ + strtolower($this->connection->ldapQuotaAttribute) => ['4096'], + strtolower($this->connection->ldapEmailAttribute) => ['alice@wonderland.org'], + strtolower($this->connection->ldapUserDisplayName) => ['Aaaaalice'], + strtolower($this->connection->ldapExtStorageHomeAttribute) => ['homeDirectory'], + 'uid' => [$this->uid], + 'homedirectory' => ['Alice\'s Folder'], + 'memberof' => ['cn=groupOne', 'cn=groupTwo'], + 'jpegphoto' => ['here be an image'] + ]; - foreach($requiredMethods as $method) { + foreach ($requiredMethods as $method) { $userMock->expects($this->once()) ->method($method); } - \OC_Hook::clear();//disconnect irrelevant hooks + \OC_Hook::clear();//disconnect irrelevant hooks $userMock->processAttributes($record); - \OC_Hook::emit('OC_User', 'post_login', array('uid' => $uid)); + /** @noinspection PhpUnhandledExceptionInspection */ + \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]); } - public function emptyHomeFolderAttributeValueProvider() { - return array( - 'empty' => array(''), - 'prefixOnly' => array('attr:'), - ); + public static function emptyHomeFolderAttributeValueProvider(): array { + return [ + 'empty' => [''], + 'prefixOnly' => ['attr:'], + ]; } - /** - * @dataProvider emptyHomeFolderAttributeValueProvider - */ - public function testGetHomePathNotConfigured($attributeValue) { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); - + #[\PHPUnit\Framework\Attributes\DataProvider('emptyHomeFolderAttributeValueProvider')] + public function testGetHomePathNotConfigured(string $attributeValue): void { $this->connection->expects($this->any()) ->method('__get') ->with($this->equalTo('homeFolderNamingRule')) - ->will($this->returnValue($attributeValue)); + ->willReturn($attributeValue); $this->access->expects($this->never()) ->method('readAttribute'); - $config->expects($this->never()) + $this->config->expects($this->never()) ->method('getAppValue'); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $path = $user->getHomePath(); - $this->assertSame($path, false); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertFalse($this->user->getHomePath()); } - public function testGetHomePathConfiguredNotAvailableAllowed() { - list(, $config, $filesys, $image, $log, $avaMgr, , $userMgr, $notiMgr) = - $this->getTestInstances(); - + public function testGetHomePathConfiguredNotAvailableAllowed(): void { $this->connection->expects($this->any()) ->method('__get') ->with($this->equalTo('homeFolderNamingRule')) - ->will($this->returnValue('attr:foobar')); + ->willReturn('attr:foobar'); $this->access->expects($this->once()) ->method('readAttribute') - ->will($this->returnValue(false)); + ->willReturn(false); + + $this->access->expects($this->once()) + ->method('username2dn') + ->willReturn($this->dn); // asks for "enforce_home_folder_naming_rule" - $config->expects($this->once()) + $this->config->expects($this->once()) ->method('getAppValue') - ->will($this->returnValue(false)); + ->willReturn(false); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $path = $user->getHomePath(); - - $this->assertSame($path, false); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertFalse($this->user->getHomePath()); } - /** - * @expectedException \Exception - */ - public function testGetHomePathConfiguredNotAvailableNotAllowed() { - list(, $config, $filesys, $image, $log, $avaMgr, , $userMgr, $notiMgr) = - $this->getTestInstances(); + + public function testGetHomePathConfiguredNotAvailableNotAllowed(): void { + $this->expectException(\Exception::class); $this->connection->expects($this->any()) ->method('__get') ->with($this->equalTo('homeFolderNamingRule')) - ->will($this->returnValue('attr:foobar')); + ->willReturn('attr:foobar'); $this->access->expects($this->once()) ->method('readAttribute') - ->will($this->returnValue(false)); + ->willReturn(false); + + $this->access->expects($this->once()) + ->method('username2dn') + ->willReturn($this->dn); // asks for "enforce_home_folder_naming_rule" - $config->expects($this->once()) + $this->config->expects($this->once()) ->method('getAppValue') - ->will($this->returnValue(true)); + ->willReturn(true); - $uid = 'alice'; - $dn = 'uid=alice,dc=foo,dc=bar'; - - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $user->getHomePath(); + $this->user->getHomePath(); } - public function displayNameProvider() { + public static function displayNameProvider(): array { return [ - ['Roland Deschain', '', 'Roland Deschain'], - ['Roland Deschain', null, 'Roland Deschain'], - ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)'], + ['Roland Deschain', '', 'Roland Deschain', false], + ['Roland Deschain', '', 'Roland Deschain', true], + ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', false], + ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', true], ]; } - /** - * @dataProvider displayNameProvider - */ - public function testComposeAndStoreDisplayName($part1, $part2, $expected) { - list(, $config, $filesys, $image, $log, $avaMgr, , $userMgr, $notiMgr) = - $this->getTestInstances(); - - $config->expects($this->once()) + #[\PHPUnit\Framework\Attributes\DataProvider('displayNameProvider')] + public function testComposeAndStoreDisplayName(string $part1, string $part2, string $expected, bool $expectTriggerChange): void { + $this->config->expects($this->once()) ->method('setUserValue'); + $oldName = $expectTriggerChange ? 'xxGunslingerxx' : null; + $this->config->expects($this->once()) + ->method('getUserValue') + ->with($this->user->getUsername(), 'user_ldap', 'displayName', null) + ->willReturn($oldName); + + $ncUserObj = $this->createMock(\OC\User\User::class); + if ($expectTriggerChange) { + $ncUserObj->expects($this->once()) + ->method('triggerChange') + ->with('displayName', $expected); + } else { + $ncUserObj->expects($this->never()) + ->method('triggerChange'); + } + $this->userManager->expects($this->once()) + ->method('get') + ->willReturn($ncUserObj); - $user = new User( - 'user', 'cn=user', $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - $displayName = $user->composeAndStoreDisplayName($part1, $part2); + $displayName = $this->user->composeAndStoreDisplayName($part1, $part2); $this->assertSame($expected, $displayName); } - public function testHandlePasswordExpiryWarningDefaultPolicy() { - list(, $config, $filesys, $image, $log, $avaMgr, $dbc, $userMgr, $notiMgr) = - $this->getTestInstances(); + public function testComposeAndStoreDisplayNameNoOverwrite(): void { + $displayName = 'Randall Flagg'; + $this->config->expects($this->never()) + ->method('setUserValue'); + $this->config->expects($this->once()) + ->method('getUserValue') + ->willReturn($displayName); + + $this->userManager->expects($this->never()) + ->method('get'); // Implicit: no triggerChange can be called - $uid = 'alice'; - $dn = 'uid=alice'; + $composedDisplayName = $this->user->composeAndStoreDisplayName($displayName); + $this->assertSame($composedDisplayName, $displayName); + } + public function testHandlePasswordExpiryWarningDefaultPolicy(): void { $this->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapDefaultPPolicyDN') { + ->willReturnCallback(function ($name) { + if ($name === 'ldapDefaultPPolicyDN') { return 'cn=default,ou=policies,dc=foo,dc=bar'; } - if($name === 'turnOnPasswordChange') { + if ($name === 'turnOnPasswordChange') { return '1'; } return $name; - })); + }); $this->access->expects($this->any()) ->method('search') - ->will($this->returnCallback(function($filter, $base) { - if($base === 'uid=alice') { - return array( - array( - 'pwdchangedtime' => array((new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'), + ->willReturnCallback(function ($filter, $base) { + if ($base === $this->dn) { + return [ + [ + 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis') . 'Z'], 'pwdgraceusetime' => [], - ), - ); + ], + ]; } - if($base === 'cn=default,ou=policies,dc=foo,dc=bar') { - return array( - array( - 'pwdmaxage' => array('2592000'), - 'pwdexpirewarning' => array('2591999'), - ), - ); + if ($base === 'cn=default,ou=policies,dc=foo,dc=bar') { + return [ + [ + 'pwdmaxage' => ['2592000'], + 'pwdexpirewarning' => ['2591999'], + ], + ]; } - return array(); - })); + return []; + }); $notification = $this->getMockBuilder(INotification::class) ->disableOriginalConstructor() ->getMock(); $notification->expects($this->any()) ->method('setApp') - ->will($this->returnValue($notification)); + ->willReturn($notification); $notification->expects($this->any()) ->method('setUser') - ->will($this->returnValue($notification)); + ->willReturn($notification); $notification->expects($this->any()) ->method('setObject') - ->will($this->returnValue($notification)); + ->willReturn($notification); $notification->expects($this->any()) ->method('setDateTime') - ->will($this->returnValue($notification)); - $notiMgr->expects($this->exactly(2)) + ->willReturn($notification); + + $this->notificationManager->expects($this->exactly(2)) ->method('createNotification') - ->will($this->returnValue($notification)); - $notiMgr->expects($this->exactly(1)) + ->willReturn($notification); + $this->notificationManager->expects($this->exactly(1)) ->method('notify'); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - \OC_Hook::clear();//disconnect irrelevant hooks - \OCP\Util::connectHook('OC_User', 'post_login', $user, 'handlePasswordExpiry'); - \OC_Hook::emit('OC_User', 'post_login', array('uid' => $uid)); + Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry'); + /** @noinspection PhpUnhandledExceptionInspection */ + \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]); } - public function testHandlePasswordExpiryWarningCustomPolicy() { - list(, $config, $filesys, $image, $log, $avaMgr, , $userMgr, $notiMgr) = - $this->getTestInstances(); - - $uid = 'alice'; - $dn = 'uid=alice'; - + public function testHandlePasswordExpiryWarningCustomPolicy(): void { $this->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapDefaultPPolicyDN') { + ->willReturnCallback(function ($name) { + if ($name === 'ldapDefaultPPolicyDN') { return 'cn=default,ou=policies,dc=foo,dc=bar'; } - if($name === 'turnOnPasswordChange') { + if ($name === 'turnOnPasswordChange') { return '1'; } return $name; - })); + }); $this->access->expects($this->any()) ->method('search') - ->will($this->returnCallback(function($filter, $base) { - if($base === 'uid=alice') { - return array( - array( - 'pwdpolicysubentry' => array('cn=custom,ou=policies,dc=foo,dc=bar'), - 'pwdchangedtime' => array((new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'), + ->willReturnCallback(function ($filter, $base) { + if ($base === $this->dn) { + return [ + [ + 'pwdpolicysubentry' => ['cn=custom,ou=policies,dc=foo,dc=bar'], + 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis') . 'Z'], 'pwdgraceusetime' => [], - ) - ); + ] + ]; } - if($base === 'cn=custom,ou=policies,dc=foo,dc=bar') { - return array( - array( - 'pwdmaxage' => array('2592000'), - 'pwdexpirewarning' => array('2591999'), - ) - ); + if ($base === 'cn=custom,ou=policies,dc=foo,dc=bar') { + return [ + [ + 'pwdmaxage' => ['2592000'], + 'pwdexpirewarning' => ['2591999'], + ] + ]; } - return array(); - })); + return []; + }); $notification = $this->getMockBuilder(INotification::class) ->disableOriginalConstructor() ->getMock(); $notification->expects($this->any()) ->method('setApp') - ->will($this->returnValue($notification)); + ->willReturn($notification); $notification->expects($this->any()) ->method('setUser') - ->will($this->returnValue($notification)); + ->willReturn($notification); $notification->expects($this->any()) ->method('setObject') - ->will($this->returnValue($notification)); + ->willReturn($notification); $notification->expects($this->any()) ->method('setDateTime') - ->will($this->returnValue($notification)); - $notiMgr->expects($this->exactly(2)) + ->willReturn($notification); + + $this->notificationManager->expects($this->exactly(2)) ->method('createNotification') - ->will($this->returnValue($notification)); - $notiMgr->expects($this->exactly(1)) + ->willReturn($notification); + $this->notificationManager->expects($this->exactly(1)) ->method('notify'); - $user = new User( - $uid, $dn, $this->access, $config, $filesys, $image, $log, $avaMgr, $userMgr, $notiMgr); - - \OC_Hook::clear();//disconnect irrelevant hooks - \OCP\Util::connectHook('OC_User', 'post_login', $user, 'handlePasswordExpiry'); - \OC_Hook::emit('OC_User', 'post_login', array('uid' => $uid)); + \OC_Hook::clear();//disconnect irrelevant hooks + Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry'); + /** @noinspection PhpUnhandledExceptionInspection */ + \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]); } } diff --git a/apps/user_ldap/tests/UserLDAPPluginTest.php b/apps/user_ldap/tests/UserLDAPPluginTest.php index 1d7d2ee7c75..8a065374e61 100644 --- a/apps/user_ldap/tests/UserLDAPPluginTest.php +++ b/apps/user_ldap/tests/UserLDAPPluginTest.php @@ -1,54 +1,33 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 EITA Cooperative (eita.org.br) - * - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; - use OC\User\Backend; use OCA\User_LDAP\UserPluginManager; class UserLDAPPluginTest extends \Test\TestCase { - - /** - * @return UserPluginManager - */ - private function getUserPluginManager() { + private function getUserPluginManager(): UserPluginManager { return new UserPluginManager(); } - public function testImplementsActions() { + public function testImplementsActions(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions']) ->getMock(); $plugin->expects($this->any()) ->method('respondToActions') ->willReturn(Backend::CREATE_USER); - $plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions']) + $plugin2 = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions']) ->getMock(); $plugin2->expects($this->any()) @@ -63,11 +42,11 @@ class UserLDAPPluginTest extends \Test\TestCase { $this->assertTrue($pluginManager->implementsActions(Backend::PROVIDE_AVATAR)); } - public function testCreateUser() { + public function testCreateUser(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'createUser']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'createUser']) ->getMock(); $plugin->expects($this->any()) @@ -85,20 +64,20 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->createUser('user', 'password'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements createUser in this LDAP Backend. - */ - public function testCreateUserNotRegistered() { + + public function testCreateUserNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements createUser in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); - $pluginManager->createUser('foo','bar'); + $pluginManager->createUser('foo', 'bar'); } - public function testSetPassword() { + public function testSetPassword(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'setPassword']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'setPassword']) ->getMock(); $plugin->expects($this->any()) @@ -116,20 +95,20 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->setPassword('user', 'password'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements setPassword in this LDAP Backend. - */ - public function testSetPasswordNotRegistered() { + + public function testSetPasswordNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements setPassword in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); - $pluginManager->setPassword('foo','bar'); + $pluginManager->setPassword('foo', 'bar'); } - public function testGetHome() { + public function testGetHome(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'getHome']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'getHome']) ->getMock(); $plugin->expects($this->any()) @@ -146,20 +125,20 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->getHome('uid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements getHome in this LDAP Backend. - */ - public function testGetHomeNotRegistered() { + + public function testGetHomeNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements getHome in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); $pluginManager->getHome('foo'); - } + } - public function testGetDisplayName() { + public function testGetDisplayName(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'getDisplayName']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'getDisplayName']) ->getMock(); $plugin->expects($this->any()) @@ -176,20 +155,20 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->getDisplayName('uid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements getDisplayName in this LDAP Backend. - */ - public function testGetDisplayNameNotRegistered() { + + public function testGetDisplayNameNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements getDisplayName in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); $pluginManager->getDisplayName('foo'); } - public function testSetDisplayName() { + public function testSetDisplayName(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'setDisplayName']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'setDisplayName']) ->getMock(); $plugin->expects($this->any()) @@ -204,23 +183,23 @@ class UserLDAPPluginTest extends \Test\TestCase { ); $pluginManager->register($plugin); - $pluginManager->setDisplayName('user', 'password'); + $pluginManager->setDisplayName('user', 'password'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements setDisplayName in this LDAP Backend. - */ - public function testSetDisplayNameNotRegistered() { + + public function testSetDisplayNameNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements setDisplayName in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); $pluginManager->setDisplayName('foo', 'bar'); - } + } - public function testCanChangeAvatar() { + public function testCanChangeAvatar(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'canChangeAvatar']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'canChangeAvatar']) ->getMock(); $plugin->expects($this->any()) @@ -237,20 +216,20 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->canChangeAvatar('uid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements canChangeAvatar in this LDAP Backend. - */ - public function testCanChangeAvatarNotRegistered() { + + public function testCanChangeAvatarNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements canChangeAvatar in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); $pluginManager->canChangeAvatar('foo'); } - public function testCountUsers() { + public function testCountUsers(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'countUsers']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'countUsers']) ->getMock(); $plugin->expects($this->any()) @@ -264,20 +243,20 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->countUsers(); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements countUsers in this LDAP Backend. - */ - public function testCountUsersNotRegistered() { + + public function testCountUsersNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements countUsers in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); $pluginManager->countUsers(); - } + } - public function testDeleteUser() { + public function testDeleteUser(): void { $pluginManager = $this->getUserPluginManager(); - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'canDeleteUser','deleteUser']) + $plugin = $this->getMockBuilder(LDAPUserPluginDummy::class) + ->onlyMethods(['respondToActions', 'canDeleteUser','deleteUser']) ->getMock(); $plugin->expects($this->any()) @@ -300,11 +279,11 @@ class UserLDAPPluginTest extends \Test\TestCase { $pluginManager->deleteUser('uid'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage No plugin implements deleteUser in this LDAP Backend. - */ - public function testDeleteUserNotRegistered() { + + public function testDeleteUserNotRegistered(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('No plugin implements deleteUser in this LDAP Backend.'); + $pluginManager = $this->getUserPluginManager(); $pluginManager->deleteUser('foo'); } diff --git a/apps/user_ldap/tests/User_LDAPTest.php b/apps/user_ldap/tests/User_LDAPTest.php index 9911aa37e37..f8900c3cca4 100644 --- a/apps/user_ldap/tests/User_LDAPTest.php +++ b/apps/user_ldap/tests/User_LDAPTest.php @@ -1,59 +1,36 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Roger Szabo <roger.szabo@web.de> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests; use OC\User\Backend; -use OC\User\Session; use OCA\User_LDAP\Access; use OCA\User_LDAP\Connection; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\Helper; use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\LogWrapper; +use OCA\User_LDAP\Mapping\AbstractMapping; use OCA\User_LDAP\Mapping\UserMapping; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; -use OC\HintException; use OCA\User_LDAP\User\User; -use OCA\User_LDAP\User_LDAP as UserLDAP; use OCA\User_LDAP\User_LDAP; -use OCP\IAvatarManager; +use OCA\User_LDAP\User_LDAP as UserLDAP; +use OCA\User_LDAP\UserPluginManager; +use OCP\HintException; use OCP\IConfig; -use OCP\IDBConnection; -use OCP\Image; +use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; -use Test\TestCase; use OCP\Notification\IManager as INotificationManager; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\TestCase; /** * Class Test_User_Ldap_Direct @@ -63,219 +40,200 @@ use OCP\Notification\IManager as INotificationManager; * @package OCA\User_LDAP\Tests */ class User_LDAPTest extends TestCase { - protected $backend; - protected $access; - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - protected $configMock; - /** @var OfflineUser|\PHPUnit_Framework_MockObject_MockObject */ - protected $offlineUser; - - protected function setUp() { + protected Access&MockObject $access; + protected OfflineUser&MockObject $offlineUser; + protected INotificationManager&MockObject $notificationManager; + protected UserPluginManager&MockObject $pluginManager; + protected Connection&MockObject $connection; + protected Manager&MockObject $userManager; + protected LoggerInterface&MockObject $logger; + protected DeletedUsersIndex&MockObject $deletedUsersIndex; + protected User_LDAP $backend; + + protected function setUp(): void { parent::setUp(); - \OC_User::clearBackends(); - \OC::$server->getGroupManager()->clearBackends(); - } + Server::get(IUserManager::class)->clearBackends(); + Server::get(IGroupManager::class)->clearBackends(); - /** - * @return \PHPUnit_Framework_MockObject_MockObject|Access - */ - private function getAccessMock() { - $this->configMock = $this->createMock(IConfig::class); - - $this->offlineUser = $this->createMock(OfflineUser::class); - - /** @var Manager|\PHPUnit_Framework_MockObject_MockObject $um */ - $um = $this->getMockBuilder(Manager::class) - ->setMethods(['getDeletedUser']) - ->setConstructorArgs([ - $this->configMock, - $this->createMock(FilesystemHelper::class), - $this->createMock(LogWrapper::class), - $this->createMock(IAvatarManager::class), - $this->createMock(Image::class), - $this->createMock(IDBConnection::class), - $this->createMock(IUserManager::class), - $this->createMock(INotificationManager::class) - ]) + $this->connection = $this->getMockBuilder(Connection::class) + ->setConstructorArgs([$this->createMock(ILDAPWrapper::class)]) ->getMock(); + $this->userManager = $this->createMock(Manager::class); - /** @var Connection|\PHPUnit_Framework_MockObject_MockObject $connection */ - $connection = $this->createMock(Connection::class); + $this->access = $this->createMock(Access::class); + $this->access->connection = $this->connection; + $this->access->userManager = $this->userManager; - /** @var Manager|\PHPUnit_Framework_MockObject_MockObject $userManager */ - $userManager = $this->createMock(Manager::class); + $this->notificationManager = $this->createMock(INotificationManager::class); + $this->pluginManager = $this->createMock(UserPluginManager::class); - /** @var Access|\PHPUnit_Framework_MockObject_MockObject $access */ - $access = $this->createMock(Access::class); - $access->connection = $connection; - $access->userManager = $userManager; + $this->logger = $this->createMock(LoggerInterface::class); - return $access; - } + $this->deletedUsersIndex = $this->createMock(DeletedUsersIndex::class); - private function getDefaultPluginManagerMock() { - return $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager')->getMock(); + $this->backend = new User_LDAP( + $this->access, + $this->notificationManager, + $this->pluginManager, + $this->logger, + $this->deletedUsersIndex, + ); } - private function prepareMockForUserExists(&$access) { - $access->expects($this->any()) - ->method('username2dn') - ->will($this->returnCallback(function($uid) { - switch ($uid) { - case 'gunslinger': - return 'dnOfRoland,dc=test'; - break; - case 'formerUser': - return 'dnOfFormerUser,dc=test'; - break; - case 'newyorker': - return 'dnOfNewYorker,dc=test'; - break; - case 'ladyofshadows': - return 'dnOfLadyOfShadows,dc=test'; - break; - default: - return false; - } - })); + private function prepareMockForUserExists(): void { + $this->access->expects($this->any()) + ->method('username2dn') + ->willReturnCallback(function ($uid) { + switch ($uid) { + case 'gunslinger': + return 'dnOfRoland,dc=test'; + break; + case 'formerUser': + return 'dnOfFormerUser,dc=test'; + break; + case 'newyorker': + return 'dnOfNewYorker,dc=test'; + break; + case 'ladyofshadows': + return 'dnOfLadyOfShadows,dc=test'; + break; + default: + return false; + } + }); - $access->method('fetchUsersByLoginName') + $this->access->method('fetchUsersByLoginName') ->willReturn([]); } /** * Prepares the Access mock for checkPassword tests - * @param Access|\PHPUnit_Framework_MockObject_MockObject $access mock - * @param bool $noDisplayName - * @return void */ - private function prepareAccessForCheckPassword(&$access, $noDisplayName = false) { - $access->connection->expects($this->any()) - ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapLoginFilter') { - return '%uid'; - } - return null; - })); - - $access->expects($this->any()) - ->method('fetchListOfUsers') - ->will($this->returnCallback(function($filter) { - if($filter === 'roland') { - return array(array('dn' => ['dnOfRoland,dc=test'])); - } - return array(); - })); + private function prepareAccessForCheckPassword(bool $noDisplayName = false): void { + $this->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + if ($name === 'ldapLoginFilter') { + return '%uid'; + } + return null; + }); - $access->expects($this->any()) + $this->access->expects($this->any()) + ->method('fetchListOfUsers') + ->willReturnCallback(function ($filter) { + if ($filter === 'roland') { + return [['dn' => ['dnOfRoland,dc=test']]]; + } + return []; + }); + $this->access->expects($this->any()) ->method('fetchUsersByLoginName') - ->will($this->returnCallback(function($uid) { - if($uid === 'roland') { - return array(array('dn' => ['dnOfRoland,dc=test'])); + ->willReturnCallback(function ($uid) { + if ($uid === 'roland') { + return [['dn' => ['dnOfRoland,dc=test']]]; } - return array(); - })); + return []; + }); $retVal = 'gunslinger'; - if($noDisplayName === true) { + if ($noDisplayName === true) { $retVal = false; } - $access->expects($this->any()) - ->method('dn2username') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->will($this->returnValue($retVal)); - - $access->expects($this->any()) - ->method('stringResemblesDN') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->will($this->returnValue(true)); - - $access->expects($this->any()) - ->method('areCredentialsValid') - ->will($this->returnCallback(function($dn, $pwd) { - if($pwd === 'dt19') { - return true; - } - return false; - })); + $this->access->expects($this->any()) + ->method('dn2username') + ->with($this->equalTo('dnOfRoland,dc=test')) + ->willReturn($retVal); + $this->access->expects($this->any()) + ->method('username2dn') + ->with($this->equalTo('gunslinger')) + ->willReturn('dnOfRoland,dc=test'); + $this->access->expects($this->any()) + ->method('stringResemblesDN') + ->with($this->equalTo('dnOfRoland,dc=test')) + ->willReturn(true); + $this->access->expects($this->any()) + ->method('areCredentialsValid') + ->willReturnCallback(function ($dn, $pwd) { + if ($pwd === 'dt19') { + return true; + } + return false; + }); + + $this->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); } - public function testCheckPasswordUidReturn() { + public function testCheckPasswordUidReturn(): void { $user = $this->createMock(User::class); $user->expects($this->any()) ->method('getUsername') ->willReturn('gunslinger'); - $access = $this->getAccessMock(); - $this->prepareAccessForCheckPassword($access); - $access->userManager->expects($this->any()) + $this->prepareAccessForCheckPassword(); + $this->userManager->expects($this->any()) ->method('get') ->willReturn($user); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); - \OC_User::useBackend($backend); + Server::get(IUserManager::class)->registerBackend($backend); $result = $backend->checkPassword('roland', 'dt19'); $this->assertEquals('gunslinger', $result); } - public function testCheckPasswordWrongPassword() { - $access = $this->getAccessMock(); - - $this->prepareAccessForCheckPassword($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testCheckPasswordWrongPassword(): void { + $this->prepareAccessForCheckPassword(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); $result = $backend->checkPassword('roland', 'wrong'); $this->assertFalse($result); } - public function testCheckPasswordWrongUser() { - $access = $this->getAccessMock(); - - $this->prepareAccessForCheckPassword($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testCheckPasswordWrongUser(): void { + $this->prepareAccessForCheckPassword(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); $result = $backend->checkPassword('mallory', 'evil'); $this->assertFalse($result); } - public function testCheckPasswordNoDisplayName() { - $access = $this->getAccessMock(); - $this->prepareAccessForCheckPassword($access, true); + public function testCheckPasswordNoDisplayName(): void { + $this->prepareAccessForCheckPassword(true); - $this->prepareAccessForCheckPassword($access); - $access->userManager->expects($this->atLeastOnce()) + $this->prepareAccessForCheckPassword(); + $this->userManager->expects($this->atLeastOnce()) ->method('get') ->willReturn(null); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); $result = $backend->checkPassword('roland', 'dt19'); $this->assertFalse($result); } - public function testCheckPasswordPublicAPI() { + public function testCheckPasswordPublicAPI(): void { $user = $this->createMock(User::class); $user->expects($this->any()) ->method('getUsername') ->willReturn('gunslinger'); - $access = $this->getAccessMock(); - $this->prepareAccessForCheckPassword($access); - $access->userManager->expects($this->any()) + $this->prepareAccessForCheckPassword(); + $this->userManager->expects($this->any()) ->method('get') ->willReturn($user); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $user = \OC::$server->getUserManager()->checkPassword('roland', 'dt19'); + $user = Server::get(IUserManager::class)->checkPassword('roland', 'dt19'); $result = false; if ($user !== false) { $result = $user->getUID(); @@ -283,13 +241,12 @@ class User_LDAPTest extends TestCase { $this->assertEquals('gunslinger', $result); } - public function testCheckPasswordPublicAPIWrongPassword() { - $access = $this->getAccessMock(); - $this->prepareAccessForCheckPassword($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testCheckPasswordPublicAPIWrongPassword(): void { + $this->prepareAccessForCheckPassword(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $user = \OC::$server->getUserManager()->checkPassword('roland', 'wrong'); + $user = Server::get(IUserManager::class)->checkPassword('roland', 'wrong'); $result = false; if ($user !== false) { $result = $user->getUID(); @@ -297,13 +254,12 @@ class User_LDAPTest extends TestCase { $this->assertFalse($result); } - public function testCheckPasswordPublicAPIWrongUser() { - $access = $this->getAccessMock(); - $this->prepareAccessForCheckPassword($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testCheckPasswordPublicAPIWrongUser(): void { + $this->prepareAccessForCheckPassword(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $user = \OC::$server->getUserManager()->checkPassword('mallory', 'evil'); + $user = Server::get(IUserManager::class)->checkPassword('mallory', 'evil'); $result = false; if ($user !== false) { $result = $user->getUID(); @@ -311,425 +267,356 @@ class User_LDAPTest extends TestCase { $this->assertFalse($result); } - public function testDeleteUserCancel() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testDeleteUserCancel(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->deleteUser('notme'); $this->assertFalse($result); } - public function testDeleteUserSuccess() { + public function testDeleteUserSuccess(): void { $uid = 'jeremy'; $home = '/var/vhome/jdings/'; - $access = $this->getAccessMock(); $mapping = $this->createMock(UserMapping::class); $mapping->expects($this->once()) ->method('unmap') - ->will($this->returnValue(true)); - $access->expects($this->once()) + ->willReturn(true); + $this->access->expects($this->once()) ->method('getUserMapper') - ->will($this->returnValue($mapping)); - $access->connection->expects($this->any()) + ->willReturn($mapping); + $this->connection->expects($this->any()) ->method('getConnectionResource') - ->willReturn('this is an ldap link'); + ->willReturn(ldap_connect('ldap://example.com')); - $this->configMock->expects($this->any()) - ->method('getUserValue') - ->with($uid, 'user_ldap', 'isDeleted') - ->willReturn('1'); + $this->deletedUsersIndex->expects($this->once()) + ->method('isUserMarked') + ->with($uid) + ->willReturn(true); - $this->offlineUser->expects($this->once()) + $offlineUser = $this->createMock(OfflineUser::class); + $offlineUser->expects($this->once()) ->method('getHomePath') ->willReturn($home); - $this->offlineUser->expects($this->once()) - ->method('getOCName') - ->willReturn($uid); - $access->userManager->expects($this->atLeastOnce()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') - ->willReturn($this->offlineUser); + ->willReturn($offlineUser); + $this->userManager->expects($this->once()) + ->method('exists') + ->with($uid) + ->willReturn(true); - $backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); - $user = $this->createMock(IUser::class); - $user->expects($this->once()) - ->method('getUID') - ->willReturn($uid); - - $backend->preDeleteUser($user); $result = $backend->deleteUser($uid); $this->assertTrue($result); + /** @noinspection PhpUnhandledExceptionInspection */ $this->assertSame($backend->getHome($uid), $home); } - public function testDeleteUserWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['canDeleteUser','deleteUser']) - ->getMock(); - - $pluginManager->expects($this->once()) + public function testDeleteUserWithPlugin(): void { + $this->pluginManager->expects($this->once()) ->method('canDeleteUser') ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('deleteUser') ->with('uid') - ->willReturn('result'); + ->willReturn(true); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); + $this->deletedUsersIndex->expects($this->once()) + ->method('isUserMarked') + ->with('uid') + ->willReturn(true); + + $mapper = $this->createMock(UserMapping::class); + $mapper->expects($this->once()) + ->method('unmap') + ->with('uid'); + + $this->access->expects($this->atLeastOnce()) + ->method('getUserMapper') + ->willReturn($mapper); + + $this->userManager->expects($this->once()) + ->method('invalidate') + ->with('uid'); - $this->assertEquals($ldap->deleteUser('uid'),'result'); + $this->assertTrue($this->backend->deleteUser('uid')); } /** * Prepares the Access mock for getUsers tests - * @param Access $access mock - * @return void */ - private function prepareAccessForGetUsers(&$access) { - $access->expects($this->once()) - ->method('escapeFilterPart') - ->will($this->returnCallback(function($search) { - return $search; - })); - - $access->expects($this->any()) - ->method('getFilterPartForUserSearch') - ->will($this->returnCallback(function($search) { - return $search; - })); - - $access->expects($this->any()) - ->method('combineFilterWithAnd') - ->will($this->returnCallback(function($param) { - return $param[2]; - })); - - $access->expects($this->any()) - ->method('fetchListOfUsers') - ->will($this->returnCallback(function($search, $a, $l, $o) { - $users = array('gunslinger', 'newyorker', 'ladyofshadows'); - if(empty($search)) { - $result = $users; - } else { - $result = array(); - foreach($users as $user) { - if(stripos($user, $search) !== false) { - $result[] = $user; - } + private function prepareAccessForGetUsers() { + $this->access->expects($this->once()) + ->method('escapeFilterPart') + ->willReturnCallback(function ($search) { + return $search; + }); + $this->access->expects($this->any()) + ->method('getFilterPartForUserSearch') + ->willReturnCallback(function ($search) { + return $search; + }); + $this->access->expects($this->any()) + ->method('combineFilterWithAnd') + ->willReturnCallback(function ($param) { + return $param[2]; + }); + $this->access->expects($this->any()) + ->method('fetchListOfUsers') + ->willReturnCallback(function ($search, $a, $l, $o) { + $users = ['gunslinger', 'newyorker', 'ladyofshadows']; + if (empty($search)) { + $result = $users; + } else { + $result = []; + foreach ($users as $user) { + if (stripos($user, $search) !== false) { + $result[] = $user; } } - if(!is_null($l) || !is_null($o)) { - $result = array_slice($result, $o, $l); - } - return $result; - })); - - $access->expects($this->any()) - ->method('nextcloudUserNames') - ->will($this->returnArgument(0)); - - $access->method('fetchUsersByLoginName') + } + if (!is_null($l) || !is_null($o)) { + $result = array_slice($result, $o, $l); + } + return $result; + }); + $this->access->expects($this->any()) + ->method('nextcloudUserNames') + ->willReturnArgument(0); + $this->access->method('fetchUsersByLoginName') ->willReturn([]); + + $this->access->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); } - public function testGetUsersNoParam() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testGetUsersNoParam(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->getUsers(); - $this->assertEquals(3, count($result)); + $this->assertCount(3, $result); } - public function testGetUsersLimitOffset() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testGetUsersLimitOffset(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->getUsers('', 1, 2); - $this->assertEquals(1, count($result)); + $this->assertCount(1, $result); } - public function testGetUsersLimitOffset2() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testGetUsersLimitOffset2(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->getUsers('', 2, 1); - $this->assertEquals(2, count($result)); + $this->assertCount(2, $result); } - public function testGetUsersSearchWithResult() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testGetUsersSearchWithResult(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->getUsers('yo'); - $this->assertEquals(2, count($result)); + $this->assertCount(2, $result); } - public function testGetUsersSearchEmptyResult() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testGetUsersSearchEmptyResult(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->getUsers('nix'); - $this->assertEquals(0, count($result)); + $this->assertCount(0, $result); } - public function testGetUsersViaAPINoParam() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); - - $result = \OCP\User::getUsers(); - $this->assertEquals(3, count($result)); + private function getUsers($search = '', $limit = null, $offset = null) { + $users = Server::get(IUserManager::class)->search($search, $limit, $offset); + $uids = array_map(function (IUser $user) { + return $user->getUID(); + }, $users); + return $uids; } - public function testGetUsersViaAPILimitOffset() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testGetUsersViaAPINoParam(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $result = \OCP\User::getUsers('', 1, 2); - $this->assertEquals(1, count($result)); + $result = $this->getUsers(); + $this->assertCount(3, $result); } - public function testGetUsersViaAPILimitOffset2() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testGetUsersViaAPILimitOffset(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $result = \OCP\User::getUsers('', 2, 1); - $this->assertEquals(2, count($result)); + $result = $this->getUsers('', 1, 2); + $this->assertCount(1, $result); } - public function testGetUsersViaAPISearchWithResult() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testGetUsersViaAPILimitOffset2(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $result = \OCP\User::getUsers('yo'); - $this->assertEquals(2, count($result)); + $result = $this->getUsers('', 2, 1); + $this->assertCount(2, $result); } - public function testGetUsersViaAPISearchEmptyResult() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetUsers($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + public function testGetUsersViaAPISearchWithResult(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $result = \OCP\User::getUsers('nix'); - $this->assertEquals(0, count($result)); + $result = $this->getUsers('yo'); + $this->assertCount(2, $result); } - public function testUserExists() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + public function testGetUsersViaAPISearchEmptyResult(): void { + $this->prepareAccessForGetUsers(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getDN') - ->willReturn('dnOfRoland,dc=test'); + $result = $this->getUsers('nix'); + $this->assertCount(0, $result); + } - $access->expects($this->any()) - ->method('readAttribute') - ->will($this->returnCallback(function($dn) { - if($dn === 'dnOfRoland,dc=test') { - return array(); - } - return false; - })); - $access->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - $access->expects($this->any()) + public function testUserExists(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); + + $this->userManager->expects($this->never()) + ->method('get'); + $this->userManager->expects($this->once()) + ->method('exists') + ->with('gunslinger') + ->willReturn(true); + $this->access->expects($this->any()) ->method('getUserMapper') ->willReturn($this->createMock(UserMapping::class)); //test for existing user + /** @noinspection PhpUnhandledExceptionInspection */ $result = $backend->userExists('gunslinger'); $this->assertTrue($result); } - /** - * @expectedException \Exception - */ - public function testUserExistsForDeleted() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + public function testUserExistsForDeleted(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $access->expects($this->any()) - ->method('readAttribute') - ->will($this->returnCallback(function($dn) { - if($dn === 'dnOfRoland,dc=test') { - return array(); - } - return false; - })); + $mapper = $this->createMock(UserMapping::class); + $mapper->expects($this->any()) + ->method('getUUIDByDN') + ->with('dnOfFormerUser,dc=test') + ->willReturn('45673458748'); - $access->userManager = $this->createMock(Manager::class); - $access->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($this->createMock(User::class)); + $this->access->expects($this->any()) + ->method('getUserMapper') + ->willReturn($mapper); - //test for deleted user - $backend->userExists('formerUser'); + $this->userManager->expects($this->never()) + ->method('get'); + $this->userManager->expects($this->once()) + ->method('exists') + ->with('formerUser') + ->willReturn(true); + + //test for deleted user – always returns true as long as we have the user in DB + $this->assertTrue($backend->userExists('formerUser')); } - public function testUserExistsForNeverExisting() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + public function testUserExistsForNeverExisting(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn) { - if($dn === 'dnOfRoland,dc=test') { - return array(); + ->willReturnCallback(function ($dn) { + if ($dn === 'dnOfRoland,dc=test') { + return []; } return false; - })); + }); //test for never-existing user + /** @noinspection PhpUnhandledExceptionInspection */ $result = $backend->userExists('mallory'); $this->assertFalse($result); } - public function testUserExistsPublicAPI() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); - \OC_User::useBackend($backend); + public function testUserExistsPublicAPI(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); + Server::get(IUserManager::class)->registerBackend($backend); $user = $this->createMock(User::class); $user->expects($this->any()) ->method('getDN') ->willReturn('dnOfRoland,dc=test'); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn) { - if($dn === 'dnOfRoland,dc=test') { - return array(); + ->willReturnCallback(function ($dn) { + if ($dn === 'dnOfRoland,dc=test') { + return []; } return false; - })); - $access->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - $access->expects($this->any()) + }); + $this->userManager->expects($this->never()) + ->method('get'); + $this->userManager->expects($this->once()) + ->method('exists') + ->with('gunslinger') + ->willReturn(true); + $this->access->expects($this->any()) ->method('getUserMapper') ->willReturn($this->createMock(UserMapping::class)); //test for existing user - $result = \OC::$server->getUserManager()->userExists('gunslinger'); + $result = Server::get(IUserManager::class)->userExists('gunslinger'); $this->assertTrue($result); } - /** - * @expectedException \Exception - */ - public function testUserExistsPublicAPIForDeleted() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); - \OC_User::useBackend($backend); - - $access->expects($this->any()) - ->method('readAttribute') - ->will($this->returnCallback(function($dn) { - if($dn === 'dnOfRoland,dc=test') { - return array(); - } - return false; - })); - $access->userManager = $this->createMock(Manager::class); - $access->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($this->createMock(User::class)); - - //test for deleted user - \OC::$server->getUserManager()->userExists('formerUser'); - } - - public function testUserExistsPublicAPIForNeverExisting() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); - \OC_User::useBackend($backend); - - $access->expects($this->any()) - ->method('readAttribute') - ->will($this->returnCallback(function($dn) { - if($dn === 'dnOfRoland,dc=test') { - return array(); - } - return false; - })); - - //test for never-existing user - $result = \OC::$server->getUserManager()->userExists('mallory'); - $this->assertFalse($result); - } - - public function testDeleteUserExisting() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + public function testDeleteUserExisting(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); //we do not support deleting existing users at all $result = $backend->deleteUser('gunslinger'); $this->assertFalse($result); } - public function testGetHomeAbsolutePath() { - $access = $this->getAccessMock(); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $backend = new UserLDAP($access, $config, $noti, $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + public function testGetHomeAbsolutePath(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $access->connection->expects($this->any()) + $this->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'homeFolderNamingRule') { + ->willReturnCallback(function ($name) { + if ($name === 'homeFolderNamingRule') { return 'attr:testAttribute'; } return null; - })); + }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { + ->willReturnCallback(function ($dn, $attr) { switch ($dn) { case 'dnOfRoland,dc=test': - if($attr === 'testAttribute') { - return array('/tmp/rolandshome/'); + if ($attr === 'testAttribute') { + return ['/tmp/rolandshome/']; } - return array(); + return []; break; default: return false; } - })); + }); $user = $this->createMock(User::class); $user->expects($this->any()) @@ -742,48 +629,51 @@ class User_LDAPTest extends TestCase { ->method('getHomePath') ->willReturn('/tmp/rolandshome/'); - $access->userManager->expects($this->atLeastOnce()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') + ->with('gunslinger') ->willReturn($user); + $this->userManager->expects($this->once()) + ->method('exists') + ->with('gunslinger') + ->willReturn(true); //absolute path + /** @noinspection PhpUnhandledExceptionInspection */ $result = $backend->getHome('gunslinger'); $this->assertEquals('/tmp/rolandshome/', $result); } - public function testGetHomeRelative() { - $access = $this->getAccessMock(); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $backend = new UserLDAP($access, $config, $noti, $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + public function testGetHomeRelative(): void { + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $dataDir = \OC::$server->getConfig()->getSystemValue( - 'datadirectory', \OC::$SERVERROOT.'/data'); + $dataDir = Server::get(IConfig::class)->getSystemValue( + 'datadirectory', \OC::$SERVERROOT . '/data'); - $access->connection->expects($this->any()) + $this->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'homeFolderNamingRule') { + ->willReturnCallback(function ($name) { + if ($name === 'homeFolderNamingRule') { return 'attr:testAttribute'; } return null; - })); + }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { + ->willReturnCallback(function ($dn, $attr) { switch ($dn) { case 'dnOfLadyOfShadows,dc=test': - if($attr === 'testAttribute') { - return array('susannah/'); + if ($attr === 'testAttribute') { + return ['susannah/']; } - return array(); + return []; break; default: return false; } - })); + }); $user = $this->createMock(User::class); $user->expects($this->any()) @@ -794,41 +684,44 @@ class User_LDAPTest extends TestCase { ->willReturn('dnOfLadyOfShadows,dc=test'); $user->expects($this->any()) ->method('getHomePath') - ->willReturn($dataDir.'/susannah/'); + ->willReturn($dataDir . '/susannah/'); - $access->userManager->expects($this->atLeastOnce()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') ->willReturn($user); + $this->userManager->expects($this->once()) + ->method('exists') + ->with('ladyofshadows') + ->willReturn(true); + /** @noinspection PhpUnhandledExceptionInspection */ $result = $backend->getHome('ladyofshadows'); - $this->assertEquals($dataDir.'/susannah/', $result); + $this->assertEquals($dataDir . '/susannah/', $result); } - /** - * @expectedException \Exception - */ - public function testGetHomeNoPath() { - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); - $access->connection->expects($this->any()) + public function testGetHomeNoPath(): void { + $this->expectException(\Exception::class); + + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); + + $this->connection->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'homeFolderNamingRule') { + ->willReturnCallback(function ($name) { + if ($name === 'homeFolderNamingRule') { return 'attr:testAttribute'; } return null; - })); - - $access->expects($this->any()) + }); + $this->access->expects($this->any()) ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { + ->willReturnCallback(function ($dn, $attr) { switch ($dn) { default: return false; } - })); + }); $user = $this->createMock(User::class); $user->expects($this->any()) @@ -838,136 +731,124 @@ class User_LDAPTest extends TestCase { ->method('getHomePath') ->willThrowException(new \Exception()); - $access->userManager->expects($this->atLeastOnce()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') + ->with('newyorker') ->willReturn($user); + $this->userManager->expects($this->once()) + ->method('exists') + ->with('newyorker') + ->willReturn(true); //no path at all – triggers OC default behaviour $result = $backend->getHome('newyorker'); $this->assertFalse($result); } - /** - * @expectedException \OC\User\NoUserException - */ - public function testGetHomeDeletedUser() { + public function testGetHomeDeletedUser(): void { $uid = 'newyorker'; - $access = $this->getAccessMock(); - $backend = new UserLDAP($access, $this->configMock, $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $access->connection->expects($this->any()) - ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'homeFolderNamingRule') { - return 'attr:testAttribute'; - } - return null; - })); + $this->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + if ($name === 'homeFolderNamingRule') { + return 'attr:testAttribute'; + } + return null; + }); - $access->expects($this->any()) - ->method('readAttribute') - ->will($this->returnValue([])); + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturn([]); $userMapper = $this->createMock(UserMapping::class); - $access->expects($this->any()) - ->method('getUserMapper') - ->will($this->returnValue($userMapper)); - - $this->configMock->expects($this->any()) - ->method('getUserValue') - ->will($this->returnValue(true)); + $this->access->expects($this->any()) + ->method('getUserMapper') + ->willReturn($userMapper); - $this->offlineUser->expects($this->never()) - ->method('getHomePath'); + $offlineUser = $this->createMock(OfflineUser::class); + $offlineUser->expects($this->atLeastOnce()) + ->method('getHomePath') + ->willReturn(''); - $access->userManager->expects($this->atLeastOnce()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') - ->willReturn($this->offlineUser); + ->with($uid) + ->willReturn($offlineUser); + $this->userManager->expects($this->once()) + ->method('exists') + ->with($uid) + ->willReturn(true); - $backend->getHome($uid); + $result = $backend->getHome($uid); + $this->assertFalse($result); } - public function testGetHomeWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','getHome']) - ->getMock(); - - $pluginManager->expects($this->once()) + public function testGetHomeWithPlugin(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::GET_HOME) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('getHome') ->with('uid') ->willReturn('result'); - $access = $this->getAccessMock(); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $access->connection->expects($this->any()) + $this->connection->expects($this->any()) ->method('getFromCache') - ->will($this->returnCallback(function($uid) { + ->willReturnCallback(function ($uid) { return true; - })); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); + }); - $this->assertEquals($ldap->getHome('uid'),'result'); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertEquals($this->backend->getHome('uid'), 'result'); } - private function prepareAccessForGetDisplayName(&$access) { - $access->connection->expects($this->any()) - ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapUserDisplayName') { - return 'displayname'; - } - return null; - })); - - $access->expects($this->any()) - ->method('readAttribute') - ->will($this->returnCallback(function($dn, $attr) { - switch ($dn) { - case 'dnOfRoland,dc=test': - if($attr === 'displayname') { - return array('Roland Deschain'); - } - return array(); - break; - - default: - return false; - } - })); - - $access->method('fetchUsersByLoginName') + private function prepareAccessForGetDisplayName() { + $this->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) { + if ($name === 'ldapUserDisplayName') { + return 'displayname'; + } elseif ($name === 'ldapUserDisplayName2') { + return 'displayname2'; + } + return null; + }); + + $this->access->expects($this->any()) + ->method('readAttribute') + ->willReturnCallback(function ($dn, $attr) { + switch ($dn) { + case 'dnOfRoland,dc=test': + if ($attr === 'displayname') { + return ['Roland Deschain']; + } + return []; + break; + + default: + return false; + } + }); + $this->access->method('fetchUsersByLoginName') ->willReturn([]); } - public function testGetDisplayName() { - $access = $this->getAccessMock(); - $this->prepareAccessForGetDisplayName($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + public function testGetDisplayName(): void { + $this->prepareAccessForGetDisplayName(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $access->connection->expects($this->any()) + $this->connection->expects($this->any()) ->method('getConnectionResource') - ->will($this->returnCallback(function() { + ->willReturnCallback(function () { return true; - })); + }); $user1 = $this->createMock(User::class); $user1->expects($this->once()) @@ -987,23 +868,38 @@ class User_LDAPTest extends TestCase { $mapper = $this->createMock(UserMapping::class); $mapper->expects($this->any()) ->method('getUUIDByDN') - ->willReturnCallback(function($dn) { return $dn; }); + ->willReturnCallback(function ($dn) { + return $dn; + }); - $access->userManager->expects($this->any()) + $this->userManager->expects($this->any()) ->method('get') - ->willReturnCallback(function($uid) use ($user1, $user2) { - if($uid === 'gunslinger') { + ->willReturnCallback(function ($uid) use ($user1, $user2) { + if ($uid === 'gunslinger') { return $user1; - } else if($uid === 'newyorker') { + } elseif ($uid === 'newyorker') { return $user2; } + return null; }); - $access->expects($this->any()) + $this->userManager->expects($this->any()) + ->method('exists') + ->willReturnCallback(function ($uid) use ($user1, $user2) { + if ($uid === 'gunslinger') { + return true; + } elseif ($uid === 'newyorker') { + return true; + } + return false; + }); + $this->access->expects($this->any()) ->method('getUserMapper') ->willReturn($mapper); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('getUserDnByUuid') - ->willReturnCallback(function($uuid) { return $uuid . '1'; }); + ->willReturnCallback(function ($uuid) { + return $uuid . '1'; + }); //with displayName $result = $backend->getDisplayName('gunslinger'); @@ -1014,11 +910,10 @@ class User_LDAPTest extends TestCase { $this->assertEquals(null, $result); } - public function testGetDisplayNamePublicAPI() { - $access = $this->getAccessMock(); - $access->expects($this->any()) + public function testGetDisplayNamePublicAPI(): void { + $this->access->expects($this->any()) ->method('username2dn') - ->will($this->returnCallback(function($uid) { + ->willReturnCallback(function ($uid) { switch ($uid) { case 'gunslinger': return 'dnOfRoland,dc=test'; @@ -1035,18 +930,18 @@ class User_LDAPTest extends TestCase { default: return false; } - })); - $this->prepareAccessForGetDisplayName($access); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $this->prepareMockForUserExists($access); + }); + $this->prepareAccessForGetDisplayName(); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->prepareMockForUserExists(); - $access->connection->expects($this->any()) + $this->connection->expects($this->any()) ->method('getConnectionResource') - ->will($this->returnCallback(function() { + ->willReturnCallback(function () { return true; - })); + }); - \OC_User::useBackend($backend); + Server::get(IUserManager::class)->registerBackend($backend); $user1 = $this->createMock(User::class); $user1->expects($this->once()) @@ -1066,160 +961,139 @@ class User_LDAPTest extends TestCase { $mapper = $this->createMock(UserMapping::class); $mapper->expects($this->any()) ->method('getUUIDByDN') - ->willReturnCallback(function($dn) { return $dn; }); + ->willReturnCallback(function ($dn) { + return $dn; + }); - $access->userManager->expects($this->any()) + $this->userManager->expects($this->any()) ->method('get') - ->willReturnCallback(function($uid) use ($user1, $user2) { - if($uid === 'gunslinger') { + ->willReturnCallback(function ($uid) use ($user1, $user2) { + if ($uid === 'gunslinger') { return $user1; - } else if($uid === 'newyorker') { + } elseif ($uid === 'newyorker') { return $user2; } + return null; + }); + $this->userManager->expects($this->any()) + ->method('exists') + ->willReturnCallback(function ($uid) use ($user1, $user2) { + if ($uid === 'gunslinger') { + return true; + } elseif ($uid === 'newyorker') { + return true; + } + return false; }); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('getUserMapper') ->willReturn($mapper); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('getUserDnByUuid') - ->willReturnCallback(function($uuid) { return $uuid . '1'; }); + ->willReturnCallback(function ($uuid) { + return $uuid . '1'; + }); //with displayName - $result = \OCP\User::getDisplayName('gunslinger'); + $result = Server::get(IUserManager::class)->get('gunslinger')?->getDisplayName(); $this->assertEquals('Roland Deschain', $result); //empty displayname retrieved - $result = \OCP\User::getDisplayName('newyorker'); + $result = Server::get(IUserManager::class)->get('newyorker') === null ? 'newyorker' : Server::get(IUserManager::class)->get('newyorker')->getDisplayName(); $this->assertEquals('newyorker', $result); } - public function testGetDisplayNameWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','getDisplayName']) - ->getMock(); - - $pluginManager->expects($this->once()) + public function testGetDisplayNameWithPlugin(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::GET_DISPLAYNAME) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('getDisplayName') ->with('uid') ->willReturn('result'); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); - - $this->assertEquals($ldap->getDisplayName('uid'),'result'); + $this->assertEquals($this->backend->getDisplayName('uid'), 'result'); } //no test for getDisplayNames, because it just invokes getUsers and //getDisplayName - public function testCountUsers() { - $access = $this->getAccessMock(); - - $access->expects($this->once()) - ->method('countUsers') - ->will($this->returnValue(5)); + public function testCountUsers(): void { + $this->access->expects($this->once()) + ->method('countUsers') + ->willReturn(5); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->countUsers(); $this->assertEquals(5, $result); } - public function testCountUsersFailing() { - $access = $this->getAccessMock(); - - $access->expects($this->once()) - ->method('countUsers') - ->will($this->returnValue(false)); + public function testCountUsersFailing(): void { + $this->access->expects($this->once()) + ->method('countUsers') + ->willReturn(false); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $result = $backend->countUsers(); $this->assertFalse($result); } - public function testCountUsersWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','countUsers']) - ->getMock(); - - $pluginManager->expects($this->once()) + public function testCountUsersWithPlugin(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::COUNT_USERS) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('countUsers') ->willReturn(42); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); - - $this->assertEquals($ldap->countUsers(),42); - } + $this->assertEquals($this->backend->countUsers(), 42); + } - public function testLoginName2UserNameSuccess() { + public function testLoginName2UserNameSuccess(): void { $loginName = 'Alice'; - $username = 'alice'; - $dn = 'uid=alice,dc=what,dc=ever'; + $username = 'alice'; + $dn = 'uid=alice,dc=what,dc=ever'; - $access = $this->getAccessMock(); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('fetchUsersByLoginName') ->with($this->equalTo($loginName)) ->willReturn([['dn' => [$dn]]]); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('stringResemblesDN') ->with($this->equalTo($dn)) ->willReturn(true); - $access->expects($this->any()) + $this->access->expects($this->any()) ->method('dn2username') ->with($this->equalTo($dn)) ->willReturn($username); - $access->connection->expects($this->exactly(2)) + $this->connection->expects($this->exactly(2)) ->method('getFromCache') - ->with($this->equalTo('loginName2UserName-'.$loginName)) + ->with($this->equalTo('loginName2UserName-' . $loginName)) ->willReturnOnConsecutiveCalls(null, $username); - $access->connection->expects($this->once()) + $this->connection->expects($this->once()) ->method('writeToCache') - ->with($this->equalTo('loginName2UserName-'.$loginName), $this->equalTo($username)); + ->with($this->equalTo('loginName2UserName-' . $loginName), $this->equalTo($username)); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $user = $this->createMock(User::class); $user->expects($this->any()) ->method('getUsername') ->willReturn('alice'); - $access->userManager->expects($this->atLeastOnce()) + $this->userManager->expects($this->atLeastOnce()) ->method('get') ->with($dn) ->willReturn($user); + $this->userManager->expects($this->never()) + ->method('exists'); + $this->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); $name = $backend->loginName2UserName($loginName); $this->assertSame($username, $name); @@ -1228,28 +1102,31 @@ class User_LDAPTest extends TestCase { $backend->loginName2UserName($loginName); } - public function testLoginName2UserNameNoUsersOnLDAP() { + public function testLoginName2UserNameNoUsersOnLDAP(): void { $loginName = 'Loki'; - $access = $this->getAccessMock(); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('fetchUsersByLoginName') ->with($this->equalTo($loginName)) ->willReturn([]); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('stringResemblesDN'); - $access->expects($this->never()) + $this->access->expects($this->never()) ->method('dn2username'); - $access->connection->expects($this->exactly(2)) + $this->connection->expects($this->exactly(2)) ->method('getFromCache') - ->with($this->equalTo('loginName2UserName-'.$loginName)) + ->with($this->equalTo('loginName2UserName-' . $loginName)) ->willReturnOnConsecutiveCalls(null, false); - $access->connection->expects($this->once()) + $this->connection->expects($this->once()) ->method('writeToCache') - ->with($this->equalTo('loginName2UserName-'.$loginName), false); + ->with($this->equalTo('loginName2UserName-' . $loginName), false); + + $this->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $name = $backend->loginName2UserName($loginName); $this->assertSame(false, $name); @@ -1257,379 +1134,334 @@ class User_LDAPTest extends TestCase { $backend->loginName2UserName($loginName); } - public function testLoginName2UserNameOfflineUser() { + public function testLoginName2UserNameOfflineUser(): void { $loginName = 'Alice'; - $dn = 'uid=alice,dc=what,dc=ever'; + $dn = 'uid=alice,dc=what,dc=ever'; $offlineUser = $this->getMockBuilder(OfflineUser::class) ->disableOriginalConstructor() ->getMock(); - $access = $this->getAccessMock(); - $access->expects($this->once()) + $this->access->expects($this->once()) ->method('fetchUsersByLoginName') ->with($this->equalTo($loginName)) ->willReturn([['dn' => [$dn]]]); - $access->connection->expects($this->exactly(2)) + $this->connection->expects($this->exactly(2)) ->method('getFromCache') - ->with($this->equalTo('loginName2UserName-'.$loginName)) + ->with($this->equalTo('loginName2UserName-' . $loginName)) ->willReturnOnConsecutiveCalls(null, false); - $access->connection->expects($this->once()) + $this->connection->expects($this->once()) ->method('writeToCache') - ->with($this->equalTo('loginName2UserName-'.$loginName), $this->equalTo(false)); + ->with($this->equalTo('loginName2UserName-' . $loginName), $this->equalTo(false)); - $access->userManager->expects($this->any()) + $this->userManager->expects($this->any()) ->method('get') ->with($dn) ->willReturn($offlineUser); + $this->userManager->expects($this->any()) + ->method('getAttributes') + ->willReturn(['dn', 'uid', 'mail', 'displayname']); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); $name = $backend->loginName2UserName($loginName); $this->assertSame(false, $name); // and once again to verify that caching works $backend->loginName2UserName($loginName); } - + /** * Prepares the Access mock for setPassword tests - * @param \OCA\User_LDAP\Access|\PHPUnit_Framework_MockObject_MockObject $access mock - * @return void */ - private function prepareAccessForSetPassword(&$access, $enablePasswordChange = true) { - $access->connection->expects($this->any()) - ->method('__get') - ->will($this->returnCallback(function($name) use (&$enablePasswordChange) { - if($name === 'ldapLoginFilter') { - return '%uid'; - } - if($name === 'turnOnPasswordChange') { - return $enablePasswordChange?1:0; - } - return null; - })); - - $access->connection->expects($this->any()) - ->method('getFromCache') - ->will($this->returnCallback(function($uid) { - if($uid === 'userExists'.'roland') { - return true; - } - return null; - })); - - $access->expects($this->any()) - ->method('fetchListOfUsers') - ->will($this->returnCallback(function($filter) { - if($filter === 'roland') { - return array(array('dn' => ['dnOfRoland,dc=test'])); - } - return array(); - })); + private function prepareAccessForSetPassword($enablePasswordChange = true) { + $this->connection->expects($this->any()) + ->method('__get') + ->willReturnCallback(function ($name) use (&$enablePasswordChange) { + if ($name === 'ldapLoginFilter') { + return '%uid'; + } + if ($name === 'turnOnPasswordChange') { + return $enablePasswordChange?1:0; + } + return null; + }); + $this->connection->expects($this->any()) + ->method('getFromCache') + ->willReturnCallback(function ($uid) { + if ($uid === 'userExists' . 'roland') { + return true; + } + return null; + }); - $access->expects($this->any()) + $this->access->expects($this->any()) + ->method('fetchListOfUsers') + ->willReturnCallback(function ($filter) { + if ($filter === 'roland') { + return [['dn' => ['dnOfRoland,dc=test']]]; + } + return []; + }); + $this->access->expects($this->any()) ->method('fetchUsersByLoginName') - ->will($this->returnCallback(function($uid) { - if($uid === 'roland') { - return array(array('dn' => ['dnOfRoland,dc=test'])); + ->willReturnCallback(function ($uid) { + if ($uid === 'roland') { + return [['dn' => ['dnOfRoland,dc=test']]]; } - return array(); - })); - - $access->expects($this->any()) - ->method('dn2username') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->will($this->returnValue('roland')); - - $access->expects($this->any()) - ->method('stringResemblesDN') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->will($this->returnValue(true)); - - $access->expects($this->any()) - ->method('setPassword') - ->will($this->returnCallback(function($uid, $password) { - if(strlen($password) <= 5) { - throw new HintException('Password fails quality checking policy', '', 19); - } - return true; - })); + return []; + }); + $this->access->expects($this->any()) + ->method('dn2username') + ->with($this->equalTo('dnOfRoland,dc=test')) + ->willReturn('roland'); + $this->access->expects($this->any()) + ->method('stringResemblesDN') + ->with($this->equalTo('dnOfRoland,dc=test')) + ->willReturn(true); + $this->access->expects($this->any()) + ->method('setPassword') + ->willReturnCallback(function ($uid, $password) { + if (strlen($password) <= 5) { + throw new HintException('Password fails quality checking policy', '', 19); + } + return true; + }); } - /** - * @expectedException \OC\HintException - * @expectedExceptionMessage Password fails quality checking policy - */ - public function testSetPasswordInvalid() { - $access = $this->getAccessMock(); - $this->prepareAccessForSetPassword($access); - $access->userManager->expects($this->atLeastOnce()) + public function testSetPasswordInvalid(): void { + $this->expectException(HintException::class); + $this->expectExceptionMessage('Password fails quality checking policy'); + + $this->prepareAccessForSetPassword($this->access); + $this->userManager->expects($this->atLeastOnce()) ->method('get') ->willReturn($this->createMock(User::class)); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); $this->assertTrue(\OC_User::setPassword('roland', 'dt')); } - - public function testSetPasswordValid() { - $access = $this->getAccessMock(); - $this->prepareAccessForSetPassword($access); + public function testSetPasswordValid(): void { + $this->prepareAccessForSetPassword($this->access); - $access->userManager->expects($this->any()) + $this->userManager->expects($this->any()) ->method('get') ->willReturn($this->createMock(User::class)); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - $access->userManager->expects($this->any()) + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + $this->userManager->expects($this->any()) ->method('get') ->willReturn($this->createMock(User::class)); - \OC_User::useBackend($backend); + Server::get(IUserManager::class)->registerBackend($backend); $this->assertTrue(\OC_User::setPassword('roland', 'dt12234$')); } - public function testSetPasswordValidDisabled() { - $access = $this->getAccessMock(); - $access->userManager->expects($this->any()) + public function testSetPasswordValidDisabled(): void { + $this->userManager->expects($this->any()) ->method('get') ->willReturn($this->createMock(User::class)); - $this->prepareAccessForSetPassword($access, false); - $backend = new UserLDAP($access, $this->createMock(IConfig::class), $this->createMock(INotificationManager::class), $this->createMock(Session::class), $this->getDefaultPluginManagerMock()); - \OC_User::useBackend($backend); + $this->prepareAccessForSetPassword(false); + $backend = new UserLDAP($this->access, $this->notificationManager, $this->pluginManager, $this->logger, $this->deletedUsersIndex); + Server::get(IUserManager::class)->registerBackend($backend); $this->assertFalse(\OC_User::setPassword('roland', 'dt12234$')); } - /** - * @expectedException \Exception - * @expectedExceptionMessage LDAP setPassword: Could not get user object for uid NotExistingUser. Maybe the LDAP entry has no set display name attribute? - */ - public function testSetPasswordWithInvalidUser() { - $access = $this->createMock(Access::class); - $access->userManager = $this->createMock(IUserManager::class); - $access->userManager + + public function testSetPasswordWithInvalidUser(): void { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('LDAP setPassword: Could not get user object for uid NotExistingUser. Maybe the LDAP entry has no set display name attribute?'); + + $this->userManager ->expects($this->once()) ->method('get') ->with('NotExistingUser') ->willReturn(null); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $userSession = $this->createMock(Session::class); - $ldap = new User_LDAP( - $access, - $config, - $noti, - $userSession, - $this->getDefaultPluginManagerMock() - ); - $ldap->setPassword('NotExistingUser', 'Password'); + + $this->backend->setPassword('NotExistingUser', 'Password'); } - public function testSetPasswordWithUsernameFalse() { + public function testSetPasswordWithUsernameFalse(): void { $user = $this->createMock(User::class); $user ->expects($this->once()) ->method('getUsername') ->willReturn(false); - $access = $this->createMock(Access::class); - $access->userManager = $this->createMock(IUserManager::class); - $access->userManager + $this->userManager ->expects($this->once()) ->method('get') ->with('NotExistingUser') ->willReturn($user); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $userSession = $this->createMock(Session::class); - $ldap = new User_LDAP( - $access, - $config, - $noti, - $userSession, - $this->getDefaultPluginManagerMock() - ); - $this->assertFalse($ldap->setPassword('NotExistingUser', 'Password')); - } - public function testSetPasswordWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','setPassword']) - ->getMock(); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertFalse($this->backend->setPassword('NotExistingUser', 'Password')); + } - $pluginManager->expects($this->once()) + public function testSetPasswordWithPlugin(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::SET_PASSWORD) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('setPassword') - ->with('uid','password') + ->with('uid', 'password') ->willReturn('result'); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertEquals($this->backend->setPassword('uid', 'password'), 'result'); + } + + public static function avatarDataProvider(): array { + return [ + [ 'validImageData', false ], + [ 'corruptImageData', true ], + [ false, true] + ]; + } - $this->assertEquals($ldap->setPassword('uid', 'password'),'result'); - } + #[\PHPUnit\Framework\Attributes\DataProvider('avatarDataProvider')] + public function testCanChangeAvatar(string|bool $imageData, bool $expected): void { + $isValidImage = str_starts_with((string)$imageData, 'valid'); - public function testCanChangeAvatarWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','canChangeAvatar']) - ->getMock(); + $user = $this->createMock(User::class); + $user->expects($this->once()) + ->method('getAvatarImage') + ->willReturn($imageData); + $user->expects($this->atMost(1)) + ->method('updateAvatar') + ->willReturn($isValidImage); + + $this->userManager->expects($this->atLeastOnce()) + ->method('get') + ->willReturn($user); - $pluginManager->expects($this->once()) + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertSame($expected, $this->backend->canChangeAvatar('uid')); + } + + public function testCanChangeAvatarWithPlugin(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::PROVIDE_AVATAR) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('canChangeAvatar') ->with('uid') ->willReturn('result'); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); + $this->assertEquals($this->backend->canChangeAvatar('uid'), 'result'); + } - $this->assertEquals($ldap->canChangeAvatar('uid'),'result'); + public function testSetDisplayNameWithPlugin(): void { + $newDisplayName = 'J. Baker'; + $this->pluginManager->expects($this->once()) + ->method('implementsActions') + ->with(Backend::SET_DISPLAYNAME) + ->willReturn(true); + $this->pluginManager->expects($this->once()) + ->method('setDisplayName') + ->with('uid', $newDisplayName) + ->willReturn($newDisplayName); + $this->access->expects($this->once()) + ->method('cacheUserDisplayName'); + + $this->assertEquals($newDisplayName, $this->backend->setDisplayName('uid', $newDisplayName)); } - public function testSetDisplayNameWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','setDisplayName']) - ->getMock(); - $pluginManager->expects($this->once()) + public function testSetDisplayNameErrorWithPlugin(): void { + $this->expectException(HintException::class); + + $newDisplayName = 'J. Baker'; + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::SET_DISPLAYNAME) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('setDisplayName') - ->with('uid','displayName') - ->willReturn('result'); + ->with('uid', $newDisplayName) + ->willThrowException(new HintException('something happned')); + $this->access->expects($this->never()) + ->method('cacheUserDisplayName'); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); - - $this->assertEquals($ldap->setDisplayName('uid', 'displayName'),'result'); + $this->backend->setDisplayName('uid', $newDisplayName); } - public function testSetDisplayNameFailing() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','setDisplayName']) - ->getMock(); - - $pluginManager->expects($this->once()) + public function testSetDisplayNameFailing(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::SET_DISPLAYNAME) ->willReturn(false); + $this->access->expects($this->never()) + ->method('cacheUserDisplayName'); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); - - $this->assertFalse($ldap->setDisplayName('uid', 'displayName')); + $this->assertFalse($this->backend->setDisplayName('uid', 'displayName')); } - public function testCreateUserWithPlugin() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions','createUser']) - ->getMock(); + public function testCreateUserWithPlugin(): void { + $uid = 'alien6372'; + $uuid = '123-2345-36756-123-2345234-4431'; + $pwd = 'passwørd'; - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::CREATE_USER) ->willReturn(true); - - $pluginManager->expects($this->once()) + $this->pluginManager->expects($this->once()) ->method('createUser') - ->with('uid','password') + ->with($uid, $pwd) ->willReturn('result'); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); + $this->access->expects($this->atLeastOnce()) + ->method('getUUID') + ->willReturn($uuid); + $this->access->expects($this->once()) + ->method('mapAndAnnounceIfApplicable') + ->with($this->isInstanceOf(AbstractMapping::class), $this->anything(), $uid, $uuid, true); + $this->access->expects($this->any()) + ->method('getUserMapper') + ->willReturn($this->createMock(UserMapping::class)); - $this->assertEquals($ldap->createUser('uid', 'password'),'result'); + $this->assertEquals($this->backend->createUser($uid, $pwd), true); } - public function testCreateUserFailing() { - $pluginManager = $this->getMockBuilder('\OCA\User_LDAP\UserPluginManager') - ->setMethods(['implementsActions', 'createUser']) - ->getMock(); - - $pluginManager->expects($this->once()) + public function testCreateUserFailing(): void { + $this->pluginManager->expects($this->once()) ->method('implementsActions') ->with(Backend::CREATE_USER) ->willReturn(false); - $access = $this->createMock(Access::class); - $config = $this->createMock(IConfig::class); - $noti = $this->createMock(INotificationManager::class); - $session = $this->createMock(Session::class); - - $ldap = new User_LDAP( - $access, - $config, - $noti, - $session, - $pluginManager - ); + $this->assertFalse($this->backend->createUser('uid', 'password')); + } + + public static function actionProvider(): array { + return [ + [ 'ldapUserAvatarRule', 'default', Backend::PROVIDE_AVATAR, true], + [ 'ldapUserAvatarRule', 'data:selfiePhoto', Backend::PROVIDE_AVATAR, true], + [ 'ldapUserAvatarRule', 'none', Backend::PROVIDE_AVATAR, false], + [ 'turnOnPasswordChange', 0, Backend::SET_PASSWORD, false], + [ 'turnOnPasswordChange', 1, Backend::SET_PASSWORD, true], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('actionProvider')] + public function testImplementsAction(string $configurable, string|int $value, int $actionCode, bool $expected): void { + $this->pluginManager->expects($this->once()) + ->method('getImplementedActions') + ->willReturn(0); + + $this->connection->expects($this->any()) + ->method('__get') + ->willReturnMap([ + [$configurable, $value], + ]); - $this->assertFalse($ldap->createUser('uid', 'password')); + $this->assertSame($expected, $this->backend->implementsActions($actionCode)); } } diff --git a/apps/user_ldap/tests/User_ProxyTest.php b/apps/user_ldap/tests/User_ProxyTest.php index 126391401e5..38f94af33a7 100644 --- a/apps/user_ldap/tests/User_ProxyTest.php +++ b/apps/user_ldap/tests/User_ProxyTest.php @@ -1,76 +1,58 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Roger Szabo <roger.szabo@web.de> - * @author Vinicius Cubas Brand <vinicius@eita.org.br> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace OCA\User_LDAP\Tests; -use OCA\User_LDAP\ILDAPUserPlugin; +use OCA\User_LDAP\AccessFactory; +use OCA\User_LDAP\Helper; use OCA\User_LDAP\ILDAPWrapper; +use OCA\User_LDAP\User\DeletedUsersIndex; use OCA\User_LDAP\User_Proxy; use OCA\User_LDAP\UserPluginManager; -use OCP\IConfig; -use OCP\IUserSession; use OCP\Notification\IManager as INotificationManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; -class User_ProxyTest extends TestCase { - /** @var ILDAPWrapper|\PHPUnit_Framework_MockObject_MockObject */ - private $ldapWrapper; - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - private $config; - /** @var INotificationManager|\PHPUnit_Framework_MockObject_MockObject */ - private $notificationManager; - /** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */ - private $userSession; - /** @var User_Proxy|\PHPUnit_Framework_MockObject_MockObject */ - private $proxy; - /** @var UserPluginManager|\PHPUnit_Framework_MockObject_MockObject */ - private $userPluginManager; +class User_ProxyTest extends TestCase { + protected Helper&MockObject $helper; + private ILDAPWrapper&MockObject $ldapWrapper; + private AccessFactory&MockObject $accessFactory; + private INotificationManager&MockObject $notificationManager; + private User_Proxy&MockObject $proxy; + private UserPluginManager&MockObject $userPluginManager; + protected LoggerInterface&MockObject $logger; + protected DeletedUsersIndex&MockObject $deletedUsersIndex; - public function setUp() { + protected function setUp(): void { parent::setUp(); + $this->helper = $this->createMock(Helper::class); $this->ldapWrapper = $this->createMock(ILDAPWrapper::class); - $this->config = $this->createMock(IConfig::class); + $this->accessFactory = $this->createMock(AccessFactory::class); $this->notificationManager = $this->createMock(INotificationManager::class); - $this->userSession = $this->createMock(IUserSession::class); $this->userPluginManager = $this->createMock(UserPluginManager::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->deletedUsersIndex = $this->createMock(DeletedUsersIndex::class); $this->proxy = $this->getMockBuilder(User_Proxy::class) ->setConstructorArgs([ - [], + $this->helper, $this->ldapWrapper, - $this->config, + $this->accessFactory, $this->notificationManager, - $this->userSession, - $this->userPluginManager + $this->userPluginManager, + $this->logger, + $this->deletedUsersIndex, ]) - ->setMethods(['handleRequest']) + ->onlyMethods(['handleRequest']) ->getMock(); } - public function testSetPassword() { + public function testSetPassword(): void { $this->proxy ->expects($this->once()) ->method('handleRequest') @@ -80,16 +62,17 @@ class User_ProxyTest extends TestCase { $this->assertTrue($this->proxy->setPassword('MyUid', 'MyPassword')); } - public function testSetDisplayName() { + public function testSetDisplayName(): void { $this->proxy ->expects($this->once()) ->method('handleRequest') ->with('MyUid', 'setDisplayName', ['MyUid', 'MyPassword']) ->willReturn(true); - $this->assertTrue($this->proxy->setDisplayName('MyUid', 'MyPassword')); } + $this->assertTrue($this->proxy->setDisplayName('MyUid', 'MyPassword')); + } - public function testCreateUser() { + public function testCreateUser(): void { $this->proxy ->expects($this->once()) ->method('handleRequest') diff --git a/apps/user_ldap/tests/WizardTest.php b/apps/user_ldap/tests/WizardTest.php index f11f7bec206..3ae9a409e88 100644 --- a/apps/user_ldap/tests/WizardTest.php +++ b/apps/user_ldap/tests/WizardTest.php @@ -1,37 +1,18 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Victor Dubiniuk <dubiniuk@owncloud.com> - * @author Viktor Szépe <viktor@szepe.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\User_LDAP\Tests; use OCA\User_LDAP\Access; use OCA\User_LDAP\Configuration; use OCA\User_LDAP\ILDAPWrapper; -use \OCA\User_LDAP\Wizard; +use OCA\User_LDAP\Wizard; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; /** @@ -42,371 +23,366 @@ use Test\TestCase; * @package OCA\User_LDAP\Tests */ class WizardTest extends TestCase { - protected function setUp() { + protected function setUp(): void { parent::setUp(); //we need to make sure the consts are defined, otherwise tests will fail //on systems without php5_ldap - $ldapConsts = array('LDAP_OPT_PROTOCOL_VERSION', - 'LDAP_OPT_REFERRALS', 'LDAP_OPT_NETWORK_TIMEOUT'); - foreach($ldapConsts as $const) { - if(!defined($const)) { + $ldapConsts = ['LDAP_OPT_PROTOCOL_VERSION', + 'LDAP_OPT_REFERRALS', 'LDAP_OPT_NETWORK_TIMEOUT']; + foreach ($ldapConsts as $const) { + if (!defined($const)) { define($const, 42); } } } - private function getWizardAndMocks() { + private function getWizardAndMocks(): array { static $confMethods; - static $connMethods; - static $accMethods; - if(is_null($confMethods)) { + if (is_null($confMethods)) { $confMethods = get_class_methods('\OCA\User_LDAP\Configuration'); - $connMethods = get_class_methods('\OCA\User_LDAP\Connection'); - $accMethods = get_class_methods('\OCA\User_LDAP\Access'); } - /** @var ILDAPWrapper|\PHPUnit_Framework_MockObject_MockObject $lw */ - $lw = $this->createMock(ILDAPWrapper::class); + /** @var ILDAPWrapper&MockObject $lw */ + $lw = $this->createMock(ILDAPWrapper::class); - /** @var Configuration|\PHPUnit_Framework_MockObject_MockObject $conf */ + /** @var Configuration&MockObject $conf */ $conf = $this->getMockBuilder(Configuration::class) - ->setMethods($confMethods) - ->setConstructorArgs([$lw, null, null]) + ->onlyMethods($confMethods) + ->setConstructorArgs(['', true]) ->getMock(); - /** @var Access|\PHPUnit_Framework_MockObject_MockObject $access */ + /** @var Access&MockObject $access */ $access = $this->createMock(Access::class); - return array(new Wizard($conf, $lw, $access), $conf, $lw, $access); + return [new Wizard($conf, $lw, $access), $conf, $lw, $access]; } - private function prepareLdapWrapperForConnections(\PHPUnit_Framework_MockObject_MockObject &$ldap) { + private function prepareLdapWrapperForConnections(MockObject $ldap) { $ldap->expects($this->once()) ->method('connect') - //dummy value, usually invalid - ->will($this->returnValue(true)); + //dummy value + ->willReturn(ldap_connect('ldap://example.com')); $ldap->expects($this->exactly(3)) ->method('setOption') - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->once()) ->method('bind') - ->will($this->returnValue(true)); - + ->willReturn(true); } - public function testCumulativeSearchOnAttributeLimited() { - list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); + public function testCumulativeSearchOnAttributeLimited(): void { + [$wizard, $configuration, $ldap] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapBase') { - return array('base'); - } - return null; - })); + ->willReturnCallback(function ($name) { + if ($name === 'ldapBase') { + return ['base']; + } + return null; + }); $this->prepareLdapWrapperForConnections($ldap); $ldap->expects($this->any()) ->method('isResource') - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->exactly(2)) ->method('search') //dummy value, usually invalid - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->exactly(2)) ->method('countEntries') //an is_resource check will follow, so we need to return a dummy resource - ->will($this->returnValue(23)); + ->willReturn(23); //5 DNs per filter means 2x firstEntry and 8x nextEntry $ldap->expects($this->exactly(2)) ->method('firstEntry') //dummy value, usually invalid - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->exactly(8)) ->method('nextEntry') //dummy value, usually invalid - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->exactly(10)) ->method('getAttributes') //dummy value, usually invalid - ->will($this->returnValue(array('cn' => array('foo'), 'count' => 1))); + ->willReturn(['cn' => ['foo'], 'count' => 1]); global $uidnumber; $uidnumber = 1; $ldap->expects($this->exactly(10)) ->method('getDN') //dummy value, usually invalid - ->will($this->returnCallback(function($a, $b) { + ->willReturnCallback(function ($a, $b) { global $uidnumber; return $uidnumber++; - })); + }); // The following expectations are the real test - $filters = array('f1', 'f2', '*'); + $filters = ['f1', 'f2', '*']; $wizard->cumulativeSearchOnAttribute($filters, 'cn', 5); unset($uidnumber); } - public function testCumulativeSearchOnAttributeUnlimited() { - list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); + public function testCumulativeSearchOnAttributeUnlimited(): void { + [$wizard, $configuration, $ldap] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapBase') { - return array('base'); - } - return null; - })); + ->willReturnCallback(function ($name) { + if ($name === 'ldapBase') { + return ['base']; + } + return null; + }); $this->prepareLdapWrapperForConnections($ldap); $ldap->expects($this->any()) ->method('isResource') - ->will($this->returnCallback(function($r) { - if($r === true) { + ->willReturnCallback(function ($r) { + if ($r instanceof \LDAP\Connection) { return true; } - if($r % 24 === 0) { + if ($r % 24 === 0) { global $uidnumber; $uidnumber++; return false; } return true; - })); + }); $ldap->expects($this->exactly(2)) ->method('search') //dummy value, usually invalid - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->exactly(2)) ->method('countEntries') //an is_resource check will follow, so we need to return a dummy resource - ->will($this->returnValue(23)); + ->willReturn(23); //5 DNs per filter means 2x firstEntry and 8x nextEntry $ldap->expects($this->exactly(2)) ->method('firstEntry') //dummy value, usually invalid - ->will($this->returnCallback(function($r) { + ->willReturnCallback(function ($r) { global $uidnumber; return $uidnumber; - })); + }); $ldap->expects($this->exactly(46)) ->method('nextEntry') //dummy value, usually invalid - ->will($this->returnCallback(function($r) { + ->willReturnCallback(function ($r) { global $uidnumber; return $uidnumber; - })); + }); $ldap->expects($this->exactly(46)) ->method('getAttributes') //dummy value, usually invalid - ->will($this->returnValue(array('cn' => array('foo'), 'count' => 1))); + ->willReturn(['cn' => ['foo'], 'count' => 1]); global $uidnumber; $uidnumber = 1; $ldap->expects($this->exactly(46)) ->method('getDN') //dummy value, usually invalid - ->will($this->returnCallback(function($a, $b) { + ->willReturnCallback(function ($a, $b) { global $uidnumber; return $uidnumber++; - })); + }); // The following expectations are the real test - $filters = array('f1', 'f2', '*'); + $filters = ['f1', 'f2', '*']; $wizard->cumulativeSearchOnAttribute($filters, 'cn', 0); unset($uidnumber); } - public function testDetectEmailAttributeAlreadySet() { - list($wizard, $configuration, $ldap, $access) + public function testDetectEmailAttributeAlreadySet(): void { + [$wizard, $configuration, $ldap, $access] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function ($name) { - if($name === 'ldapEmailAttribute') { + ->willReturnCallback(function ($name) { + if ($name === 'ldapEmailAttribute') { return 'myEmailAttribute'; } else { //for requirement checks return 'let me pass'; } - })); + }); $access->expects($this->once()) ->method('countUsers') - ->will($this->returnValue(42)); + ->willReturn(42); $wizard->detectEmailAttribute(); } - public function testDetectEmailAttributeOverrideSet() { - list($wizard, $configuration, $ldap, $access) + public function testDetectEmailAttributeOverrideSet(): void { + [$wizard, $configuration, $ldap, $access] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function ($name) { - if($name === 'ldapEmailAttribute') { + ->willReturnCallback(function ($name) { + if ($name === 'ldapEmailAttribute') { return 'myEmailAttribute'; } else { //for requirement checks return 'let me pass'; } - })); + }); $access->expects($this->exactly(3)) ->method('combineFilterWithAnd') - ->will($this->returnCallback(function ($filterParts) { + ->willReturnCallback(function ($filterParts) { return str_replace('=*', '', array_pop($filterParts)); - })); + }); $access->expects($this->exactly(3)) ->method('countUsers') - ->will($this->returnCallback(function ($filter) { - if($filter === 'myEmailAttribute') { + ->willReturnCallback(function ($filter) { + if ($filter === 'myEmailAttribute') { return 0; - } else if($filter === 'mail') { + } elseif ($filter === 'mail') { return 3; - } else if($filter === 'mailPrimaryAddress') { + } elseif ($filter === 'mailPrimaryAddress') { return 17; } throw new \Exception('Untested filter: ' . $filter); - })); + }); $result = $wizard->detectEmailAttribute()->getResultArray(); $this->assertSame('mailPrimaryAddress', $result['changes']['ldap_email_attr']); } - public function testDetectEmailAttributeFind() { - list($wizard, $configuration, $ldap, $access) + public function testDetectEmailAttributeFind(): void { + [$wizard, $configuration, $ldap, $access] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function ($name) { - if($name === 'ldapEmailAttribute') { + ->willReturnCallback(function ($name) { + if ($name === 'ldapEmailAttribute') { return ''; } else { //for requirement checks return 'let me pass'; } - })); + }); $access->expects($this->exactly(2)) ->method('combineFilterWithAnd') - ->will($this->returnCallback(function ($filterParts) { + ->willReturnCallback(function ($filterParts) { return str_replace('=*', '', array_pop($filterParts)); - })); + }); $access->expects($this->exactly(2)) ->method('countUsers') - ->will($this->returnCallback(function ($filter) { - if($filter === 'myEmailAttribute') { + ->willReturnCallback(function ($filter) { + if ($filter === 'myEmailAttribute') { return 0; - } else if($filter === 'mail') { + } elseif ($filter === 'mail') { return 3; - } else if($filter === 'mailPrimaryAddress') { + } elseif ($filter === 'mailPrimaryAddress') { return 17; } throw new \Exception('Untested filter: ' . $filter); - })); + }); $result = $wizard->detectEmailAttribute()->getResultArray(); $this->assertSame('mailPrimaryAddress', $result['changes']['ldap_email_attr']); } - public function testDetectEmailAttributeFindNothing() { - list($wizard, $configuration, $ldap, $access) + public function testDetectEmailAttributeFindNothing(): void { + [$wizard, $configuration, $ldap, $access] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function ($name) { - if($name === 'ldapEmailAttribute') { + ->willReturnCallback(function ($name) { + if ($name === 'ldapEmailAttribute') { return 'myEmailAttribute'; } else { //for requirement checks return 'let me pass'; } - })); + }); $access->expects($this->exactly(3)) ->method('combineFilterWithAnd') - ->will($this->returnCallback(function ($filterParts) { + ->willReturnCallback(function ($filterParts) { return str_replace('=*', '', array_pop($filterParts)); - })); + }); $access->expects($this->exactly(3)) ->method('countUsers') - ->will($this->returnCallback(function ($filter) { - if($filter === 'myEmailAttribute') { + ->willReturnCallback(function ($filter) { + if ($filter === 'myEmailAttribute') { return 0; - } else if($filter === 'mail') { + } elseif ($filter === 'mail') { return 0; - } else if($filter === 'mailPrimaryAddress') { + } elseif ($filter === 'mailPrimaryAddress') { return 0; } throw new \Exception('Untested filter: ' . $filter); - })); + }); $result = $wizard->detectEmailAttribute(); - $this->assertSame(false, $result->hasChanges()); + $this->assertFalse($result->hasChanges()); } - public function testCumulativeSearchOnAttributeSkipReadDN() { + public function testCumulativeSearchOnAttributeSkipReadDN(): void { // tests that there is no infinite loop, when skipping already processed // DNs (they can be returned multiple times for multiple filters ) - list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); + [$wizard, $configuration, $ldap] = $this->getWizardAndMocks(); $configuration->expects($this->any()) ->method('__get') - ->will($this->returnCallback(function($name) { - if($name === 'ldapBase') { - return array('base'); - } - return null; - })); + ->willReturnCallback(function ($name) { + if ($name === 'ldapBase') { + return ['base']; + } + return null; + }); $this->prepareLdapWrapperForConnections($ldap); $ldap->expects($this->any()) ->method('isResource') - ->will($this->returnCallback(function($res) { + ->willReturnCallback(function ($res) { return (bool)$res; - })); + }); $ldap->expects($this->any()) ->method('search') //dummy value, usually invalid - ->will($this->returnValue(true)); + ->willReturn(true); $ldap->expects($this->any()) ->method('countEntries') //an is_resource check will follow, so we need to return a dummy resource - ->will($this->returnValue(7)); + ->willReturn(7); //5 DNs per filter means 2x firstEntry and 8x nextEntry $ldap->expects($this->any()) ->method('firstEntry') //dummy value, usually invalid - ->will($this->returnValue(1)); + ->willReturn(1); global $mark; $mark = false; @@ -414,38 +390,37 @@ class WizardTest extends TestCase { $ldap->expects($this->any()) ->method('nextEntry') //dummy value, usually invalid - ->will($this->returnCallback(function($a, $prev){ + ->willReturnCallback(function ($a, $prev) { $current = $prev + 1; - if($current === 7) { + if ($current === 7) { return false; } global $mark; - if($prev === 4 && !$mark) { + if ($prev === 4 && !$mark) { $mark = true; return 4; } return $current; - })); + }); $ldap->expects($this->any()) ->method('getAttributes') //dummy value, usually invalid - ->will($this->returnCallback(function($a, $entry) { - return array('cn' => array($entry), 'count' => 1); - })); + ->willReturnCallback(function ($a, $entry) { + return ['cn' => [$entry], 'count' => 1]; + }); $ldap->expects($this->any()) ->method('getDN') //dummy value, usually invalid - ->will($this->returnCallback(function($a, $b) { + ->willReturnCallback(function ($a, $b) { return $b; - })); + }); // The following expectations are the real test - $filters = array('f1', 'f2', '*'); + $filters = ['f1', 'f2', '*']; $resultArray = $wizard->cumulativeSearchOnAttribute($filters, 'cn', 0); - $this->assertSame(6, count($resultArray)); + $this->assertCount(6, $resultArray); unset($mark); } - } |