ConnectionTest.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\User_LDAP\Tests;
  8. use OCA\User_LDAP\Connection;
  9. use OCA\User_LDAP\ILDAPWrapper;
  10. /**
  11. * Class Test_Connection
  12. *
  13. * @group DB
  14. *
  15. * @package OCA\User_LDAP\Tests
  16. */
  17. class ConnectionTest extends \Test\TestCase {
  18. /** @var \OCA\User_LDAP\ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject */
  19. protected $ldap;
  20. /** @var Connection */
  21. protected $connection;
  22. protected function setUp(): void {
  23. parent::setUp();
  24. $this->ldap = $this->createMock(ILDAPWrapper::class);
  25. // we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend.
  26. $this->connection = $this->getMockBuilder('OCA\User_LDAP\Connection')
  27. ->setMethods(['getFromCache', 'writeToCache'])
  28. ->setConstructorArgs([$this->ldap, '', null])
  29. ->getMock();
  30. $this->ldap->expects($this->any())
  31. ->method('areLDAPFunctionsAvailable')
  32. ->willReturn(true);
  33. }
  34. public function testOriginalAgentUnchangedOnClone(): void {
  35. //background: upon login a bind is done with the user credentials
  36. //which is valid for the whole LDAP resource. It needs to be reset
  37. //to the agent's credentials
  38. $lw = $this->createMock(ILDAPWrapper::class);
  39. $connection = new Connection($lw, '', null);
  40. $agent = [
  41. 'ldapAgentName' => 'agent',
  42. 'ldapAgentPassword' => '123456',
  43. ];
  44. $connection->setConfiguration($agent);
  45. $testConnection = clone $connection;
  46. $user = [
  47. 'ldapAgentName' => 'user',
  48. 'ldapAgentPassword' => 'password',
  49. ];
  50. $testConnection->setConfiguration($user);
  51. $agentName = $connection->ldapAgentName;
  52. $agentPawd = $connection->ldapAgentPassword;
  53. $this->assertSame($agentName, $agent['ldapAgentName']);
  54. $this->assertSame($agentPawd, $agent['ldapAgentPassword']);
  55. }
  56. public function testUseBackupServer(): void {
  57. $mainHost = 'ldap://nixda.ldap';
  58. $backupHost = 'ldap://fallback.ldap';
  59. $config = [
  60. 'ldapConfigurationActive' => true,
  61. 'ldapHost' => $mainHost,
  62. 'ldapPort' => 389,
  63. 'ldapBackupHost' => $backupHost,
  64. 'ldapBackupPort' => 389,
  65. 'ldapAgentName' => 'uid=agent',
  66. 'ldapAgentPassword' => 'SuchASecret'
  67. ];
  68. $this->connection->setIgnoreValidation(true);
  69. $this->connection->setConfiguration($config);
  70. $this->ldap->expects($this->any())
  71. ->method('isResource')
  72. ->willReturn(true);
  73. $this->ldap->expects($this->any())
  74. ->method('setOption')
  75. ->willReturn(true);
  76. $this->ldap->expects($this->exactly(3))
  77. ->method('connect')
  78. ->willReturn(ldap_connect('ldap://example.com'));
  79. $this->ldap->expects($this->any())
  80. ->method('errno')
  81. ->willReturn(0);
  82. // Not called often enough? Then, the fallback to the backup server is broken.
  83. $this->connection->expects($this->exactly(2))
  84. ->method('getFromCache')
  85. ->with('overrideMainServer')
  86. ->will($this->onConsecutiveCalls(false, false, true, true));
  87. $this->connection->expects($this->once())
  88. ->method('writeToCache')
  89. ->with('overrideMainServer', true);
  90. $isThrown = false;
  91. $this->ldap->expects($this->exactly(3))
  92. ->method('bind')
  93. ->willReturnCallback(function () use (&$isThrown) {
  94. if (!$isThrown) {
  95. $isThrown = true;
  96. throw new \OC\ServerNotAvailableException();
  97. }
  98. return true;
  99. });
  100. $this->connection->init();
  101. $this->connection->resetConnectionResource();
  102. // with the second init() we test whether caching works
  103. $this->connection->init();
  104. }
  105. public function testDontUseBackupServerOnFailedAuth(): void {
  106. $mainHost = 'ldap://nixda.ldap';
  107. $backupHost = 'ldap://fallback.ldap';
  108. $config = [
  109. 'ldapConfigurationActive' => true,
  110. 'ldapHost' => $mainHost,
  111. 'ldapPort' => 389,
  112. 'ldapBackupHost' => $backupHost,
  113. 'ldapBackupPort' => 389,
  114. 'ldapAgentName' => 'uid=agent',
  115. 'ldapAgentPassword' => 'SuchASecret'
  116. ];
  117. $this->connection->setIgnoreValidation(true);
  118. $this->connection->setConfiguration($config);
  119. $this->ldap->expects($this->any())
  120. ->method('isResource')
  121. ->willReturn(true);
  122. $this->ldap->expects($this->any())
  123. ->method('setOption')
  124. ->willReturn(true);
  125. $this->ldap->expects($this->once())
  126. ->method('connect')
  127. ->willReturn(ldap_connect('ldap://example.com'));
  128. $this->ldap->expects($this->any())
  129. ->method('errno')
  130. ->willReturn(49);
  131. $this->connection->expects($this->any())
  132. ->method('getFromCache')
  133. ->with('overrideMainServer')
  134. ->willReturn(false);
  135. $this->connection->expects($this->never())
  136. ->method('writeToCache');
  137. $this->ldap->expects($this->exactly(1))
  138. ->method('bind')
  139. ->willReturn(false);
  140. $this->connection->init();
  141. }
  142. public function testBindWithInvalidCredentials(): void {
  143. // background: Bind with invalid credentials should return false
  144. // and not throw a ServerNotAvailableException.
  145. $host = 'ldap://nixda.ldap';
  146. $config = [
  147. 'ldapConfigurationActive' => true,
  148. 'ldapHost' => $host,
  149. 'ldapPort' => 389,
  150. 'ldapBackupHost' => '',
  151. 'ldapAgentName' => 'user',
  152. 'ldapAgentPassword' => 'password'
  153. ];
  154. $this->connection->setIgnoreValidation(true);
  155. $this->connection->setConfiguration($config);
  156. $this->ldap->expects($this->any())
  157. ->method('isResource')
  158. ->willReturn(true);
  159. $this->ldap->expects($this->any())
  160. ->method('setOption')
  161. ->willReturn(true);
  162. $this->ldap->expects($this->any())
  163. ->method('connect')
  164. ->willReturn(ldap_connect('ldap://example.com'));
  165. $this->ldap->expects($this->once())
  166. ->method('bind')
  167. ->willReturn(false);
  168. // LDAP_INVALID_CREDENTIALS
  169. $this->ldap->expects($this->any())
  170. ->method('errno')
  171. ->willReturn(0x31);
  172. try {
  173. $this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.');
  174. } catch (\OC\ServerNotAvailableException $e) {
  175. $this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.');
  176. }
  177. }
  178. public function testStartTlsNegotiationFailure(): void {
  179. // background: If Start TLS negotiation fails,
  180. // a ServerNotAvailableException should be thrown.
  181. $host = 'ldap://nixda.ldap';
  182. $port = 389;
  183. $config = [
  184. 'ldapConfigurationActive' => true,
  185. 'ldapHost' => $host,
  186. 'ldapPort' => $port,
  187. 'ldapTLS' => true,
  188. 'ldapBackupHost' => '',
  189. 'ldapAgentName' => 'user',
  190. 'ldapAgentPassword' => 'password'
  191. ];
  192. $this->connection->setIgnoreValidation(true);
  193. $this->connection->setConfiguration($config);
  194. $this->ldap->expects($this->any())
  195. ->method('isResource')
  196. ->willReturn(true);
  197. $this->ldap->expects($this->any())
  198. ->method('connect')
  199. ->willReturn(ldap_connect('ldap://example.com'));
  200. $this->ldap->expects($this->any())
  201. ->method('setOption')
  202. ->willReturn(true);
  203. $this->ldap->expects($this->any())
  204. ->method('bind')
  205. ->willReturn(true);
  206. $this->ldap->expects($this->any())
  207. ->method('errno')
  208. ->willReturn(0);
  209. $this->ldap->expects($this->any())
  210. ->method('startTls')
  211. ->willReturn(false);
  212. $this->expectException(\OC\ServerNotAvailableException::class);
  213. $this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.');
  214. $this->connection->init();
  215. }
  216. }