ConnectionTest.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Jarkko Lehtoranta <devel@jlranta.com>
  8. * @author Joas Schilling <coding@schilljs.com>
  9. * @author Julius Härtl <jus@bitgrid.net>
  10. * @author Morris Jobke <hey@morrisjobke.de>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. * @author Victor Dubiniuk <dubiniuk@owncloud.com>
  14. *
  15. * @license AGPL-3.0
  16. *
  17. * This code is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License, version 3,
  19. * as published by the Free Software Foundation.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License, version 3,
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>
  28. *
  29. */
  30. namespace OCA\User_LDAP\Tests;
  31. use OCA\User_LDAP\Connection;
  32. use OCA\User_LDAP\ILDAPWrapper;
  33. /**
  34. * Class Test_Connection
  35. *
  36. * @group DB
  37. *
  38. * @package OCA\User_LDAP\Tests
  39. */
  40. class ConnectionTest extends \Test\TestCase {
  41. /** @var \OCA\User_LDAP\ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject */
  42. protected $ldap;
  43. /** @var Connection */
  44. protected $connection;
  45. protected function setUp(): void {
  46. parent::setUp();
  47. $this->ldap = $this->createMock(ILDAPWrapper::class);
  48. // we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend.
  49. $this->connection = $this->getMockBuilder('OCA\User_LDAP\Connection')
  50. ->setMethods(['getFromCache', 'writeToCache'])
  51. ->setConstructorArgs([$this->ldap, '', null])
  52. ->getMock();
  53. $this->ldap->expects($this->any())
  54. ->method('areLDAPFunctionsAvailable')
  55. ->willReturn(true);
  56. }
  57. public function testOriginalAgentUnchangedOnClone() {
  58. //background: upon login a bind is done with the user credentials
  59. //which is valid for the whole LDAP resource. It needs to be reset
  60. //to the agent's credentials
  61. $lw = $this->createMock(ILDAPWrapper::class);
  62. $connection = new Connection($lw, '', null);
  63. $agent = [
  64. 'ldapAgentName' => 'agent',
  65. 'ldapAgentPassword' => '123456',
  66. ];
  67. $connection->setConfiguration($agent);
  68. $testConnection = clone $connection;
  69. $user = [
  70. 'ldapAgentName' => 'user',
  71. 'ldapAgentPassword' => 'password',
  72. ];
  73. $testConnection->setConfiguration($user);
  74. $agentName = $connection->ldapAgentName;
  75. $agentPawd = $connection->ldapAgentPassword;
  76. $this->assertSame($agentName, $agent['ldapAgentName']);
  77. $this->assertSame($agentPawd, $agent['ldapAgentPassword']);
  78. }
  79. public function testUseBackupServer() {
  80. $mainHost = 'ldap://nixda.ldap';
  81. $backupHost = 'ldap://fallback.ldap';
  82. $config = [
  83. 'ldapConfigurationActive' => true,
  84. 'ldapHost' => $mainHost,
  85. 'ldapPort' => 389,
  86. 'ldapBackupHost' => $backupHost,
  87. 'ldapBackupPort' => 389,
  88. 'ldapAgentName' => 'uid=agent',
  89. 'ldapAgentPassword' => 'SuchASecret'
  90. ];
  91. $this->connection->setIgnoreValidation(true);
  92. $this->connection->setConfiguration($config);
  93. $this->ldap->expects($this->any())
  94. ->method('isResource')
  95. ->willReturn(true);
  96. $this->ldap->expects($this->any())
  97. ->method('setOption')
  98. ->willReturn(true);
  99. $this->ldap->expects($this->exactly(3))
  100. ->method('connect')
  101. ->willReturn('ldapResource');
  102. $this->ldap->expects($this->any())
  103. ->method('errno')
  104. ->willReturn(0);
  105. // Not called often enough? Then, the fallback to the backup server is broken.
  106. $this->connection->expects($this->exactly(4))
  107. ->method('getFromCache')
  108. ->with('overrideMainServer')
  109. ->will($this->onConsecutiveCalls(false, false, true, true));
  110. $this->connection->expects($this->once())
  111. ->method('writeToCache')
  112. ->with('overrideMainServer', true);
  113. $isThrown = false;
  114. $this->ldap->expects($this->exactly(3))
  115. ->method('bind')
  116. ->willReturnCallback(function () use (&$isThrown) {
  117. if (!$isThrown) {
  118. $isThrown = true;
  119. throw new \OC\ServerNotAvailableException();
  120. }
  121. return true;
  122. });
  123. $this->connection->init();
  124. $this->connection->resetConnectionResource();
  125. // with the second init() we test whether caching works
  126. $this->connection->init();
  127. }
  128. public function testDontUseBackupServerOnFailedAuth() {
  129. $mainHost = 'ldap://nixda.ldap';
  130. $backupHost = 'ldap://fallback.ldap';
  131. $config = [
  132. 'ldapConfigurationActive' => true,
  133. 'ldapHost' => $mainHost,
  134. 'ldapPort' => 389,
  135. 'ldapBackupHost' => $backupHost,
  136. 'ldapBackupPort' => 389,
  137. 'ldapAgentName' => 'uid=agent',
  138. 'ldapAgentPassword' => 'SuchASecret'
  139. ];
  140. $this->connection->setIgnoreValidation(true);
  141. $this->connection->setConfiguration($config);
  142. $this->ldap->expects($this->any())
  143. ->method('isResource')
  144. ->willReturn(true);
  145. $this->ldap->expects($this->any())
  146. ->method('setOption')
  147. ->willReturn(true);
  148. $this->ldap->expects($this->once())
  149. ->method('connect')
  150. ->willReturn('ldapResource');
  151. $this->ldap->expects($this->any())
  152. ->method('errno')
  153. ->willReturn(49);
  154. $this->connection->expects($this->any())
  155. ->method('getFromCache')
  156. ->with('overrideMainServer')
  157. ->willReturn(false);
  158. $this->connection->expects($this->never())
  159. ->method('writeToCache');
  160. $this->ldap->expects($this->exactly(1))
  161. ->method('bind')
  162. ->willReturn(false);
  163. $this->connection->init();
  164. }
  165. public function testBindWithInvalidCredentials() {
  166. // background: Bind with invalid credentials should return false
  167. // and not throw a ServerNotAvailableException.
  168. $host = 'ldap://nixda.ldap';
  169. $config = [
  170. 'ldapConfigurationActive' => true,
  171. 'ldapHost' => $host,
  172. 'ldapPort' => 389,
  173. 'ldapBackupHost' => '',
  174. 'ldapAgentName' => 'user',
  175. 'ldapAgentPassword' => 'password'
  176. ];
  177. $this->connection->setIgnoreValidation(true);
  178. $this->connection->setConfiguration($config);
  179. $this->ldap->expects($this->any())
  180. ->method('isResource')
  181. ->willReturn(true);
  182. $this->ldap->expects($this->any())
  183. ->method('setOption')
  184. ->willReturn(true);
  185. $this->ldap->expects($this->any())
  186. ->method('connect')
  187. ->willReturn('ldapResource');
  188. $this->ldap->expects($this->once())
  189. ->method('bind')
  190. ->willReturn(false);
  191. // LDAP_INVALID_CREDENTIALS
  192. $this->ldap->expects($this->any())
  193. ->method('errno')
  194. ->willReturn(0x31);
  195. try {
  196. $this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.');
  197. } catch (\OC\ServerNotAvailableException $e) {
  198. $this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.');
  199. }
  200. }
  201. public function testStartTlsNegotiationFailure() {
  202. // background: If Start TLS negotiation fails,
  203. // a ServerNotAvailableException should be thrown.
  204. $host = 'ldap://nixda.ldap';
  205. $port = 389;
  206. $config = [
  207. 'ldapConfigurationActive' => true,
  208. 'ldapHost' => $host,
  209. 'ldapPort' => $port,
  210. 'ldapTLS' => true,
  211. 'ldapBackupHost' => '',
  212. 'ldapAgentName' => 'user',
  213. 'ldapAgentPassword' => 'password'
  214. ];
  215. $this->connection->setIgnoreValidation(true);
  216. $this->connection->setConfiguration($config);
  217. $this->ldap->expects($this->any())
  218. ->method('isResource')
  219. ->willReturn(true);
  220. $this->ldap->expects($this->any())
  221. ->method('connect')
  222. ->willReturn('ldapResource');
  223. $this->ldap->expects($this->any())
  224. ->method('setOption')
  225. ->willReturn(true);
  226. $this->ldap->expects($this->any())
  227. ->method('bind')
  228. ->willReturn(true);
  229. $this->ldap->expects($this->any())
  230. ->method('errno')
  231. ->willReturn(0);
  232. $this->ldap->expects($this->any())
  233. ->method('startTls')
  234. ->willReturn(false);
  235. $this->expectException(\OC\ServerNotAvailableException::class);
  236. $this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.');
  237. $this->connection->init();
  238. }
  239. }