diff options
Diffstat (limited to 'apps/user_ldap/tests/ConnectionTest.php')
-rw-r--r-- | apps/user_ldap/tests/ConnectionTest.php | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/apps/user_ldap/tests/ConnectionTest.php b/apps/user_ldap/tests/ConnectionTest.php new file mode 100644 index 00000000000..7116e15898f --- /dev/null +++ b/apps/user_ldap/tests/ConnectionTest.php @@ -0,0 +1,267 @@ +<?php + +declare(strict_types=1); +/** + * 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 + * + * @group DB + * + * @package OCA\User_LDAP\Tests + */ +class ConnectionTest extends \Test\TestCase { + protected ILDAPWrapper&MockObject $ldap; + protected Connection $connection; + + protected function setUp(): void { + parent::setUp(); + + $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(Connection::class) + ->onlyMethods(['getFromCache', 'writeToCache']) + ->setConstructorArgs([$this->ldap, '', null]) + ->getMock(); + + $this->ldap->expects($this->any()) + ->method('areLDAPFunctionsAvailable') + ->willReturn(true); + } + + 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); + + $connection = new Connection($lw, '', null); + $agent = [ + 'ldapAgentName' => 'agent', + 'ldapAgentPassword' => '123456', + ]; + $connection->setConfiguration($agent); + + $testConnection = clone $connection; + $user = [ + 'ldapAgentName' => 'user', + 'ldapAgentPassword' => 'password', + ]; + $testConnection->setConfiguration($user); + + $agentName = $connection->ldapAgentName; + $agentPawd = $connection->ldapAgentPassword; + + $this->assertSame($agentName, $agent['ldapAgentName']); + $this->assertSame($agentPawd, $agent['ldapAgentPassword']); + } + + public function testUseBackupServer(): 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->exactly(3)) + ->method('connect') + ->willReturn(ldap_connect('ldap://example.com')); + + $this->ldap->expects($this->any()) + ->method('errno') + ->willReturn(0); + + // Not called often enough? Then, the fallback to the backup server is broken. + $this->connection->expects($this->exactly(2)) + ->method('getFromCache') + ->with('overrideMainServer')->willReturnOnConsecutiveCalls(false, false, true, true); + + $this->connection->expects($this->once()) + ->method('writeToCache') + ->with('overrideMainServer', true); + + $isThrown = false; + $this->ldap->expects($this->exactly(3)) + ->method('bind') + ->willReturnCallback(function () use (&$isThrown) { + if (!$isThrown) { + $isThrown = true; + throw new ServerNotAvailableException(); + } + return true; + }); + + $this->connection->init(); + $this->connection->resetConnectionResource(); + // with the second init() we test whether caching works + $this->connection->init(); + } + + 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. + + $host = 'ldap://nixda.ldap'; + $config = [ + 'ldapConfigurationActive' => true, + 'ldapHost' => $host, + 'ldapPort' => 389, + 'ldapBackupHost' => '', + 'ldapAgentName' => 'user', + 'ldapAgentPassword' => 'password' + ]; + + $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->any()) + ->method('connect') + ->willReturn(ldap_connect('ldap://example.com')); + + $this->ldap->expects($this->once()) + ->method('bind') + ->willReturn(false); + + // LDAP_INVALID_CREDENTIALS + $this->ldap->expects($this->any()) + ->method('errno') + ->willReturn(0x31); + + try { + $this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.'); + } catch (ServerNotAvailableException $e) { + $this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.'); + } + } + + public function testStartTlsNegotiationFailure(): void { + // background: If Start TLS negotiation fails, + // a ServerNotAvailableException should be thrown. + + $host = 'ldap://nixda.ldap'; + $port = 389; + $config = [ + 'ldapConfigurationActive' => true, + 'ldapHost' => $host, + 'ldapPort' => $port, + 'ldapTLS' => true, + 'ldapBackupHost' => '', + 'ldapAgentName' => 'user', + 'ldapAgentPassword' => 'password' + ]; + + $this->connection->setIgnoreValidation(true); + $this->connection->setConfiguration($config); + + $this->ldap->expects($this->any()) + ->method('isResource') + ->willReturn(true); + + $this->ldap->expects($this->any()) + ->method('connect') + ->willReturn(ldap_connect('ldap://example.com')); + + $this->ldap->expects($this->any()) + ->method('setOption') + ->willReturn(true); + + $this->ldap->expects($this->any()) + ->method('bind') + ->willReturn(true); + + $this->ldap->expects($this->any()) + ->method('errno') + ->willReturn(0); + + $this->ldap->expects($this->any()) + ->method('startTls') + ->willReturn(false); + + $this->expectException(ServerNotAvailableException::class); + $this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.'); + + $this->connection->init(); + } +} |