From e4f71eacd6f3aa6775ac233c868ba7022422dd19 Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Fri, 27 Feb 2015 17:11:12 +0100 Subject: [PATCH] Add unit tests for ldap connection behavior It is important that we test handling of protocol extensions properly, to prohibit errors that are difficult to reproduce like this in the future. fixes #7993 --- .../Icinga/Protocol/Ldap/ConnectionTest.php | 258 ++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 test/php/library/Icinga/Protocol/Ldap/ConnectionTest.php diff --git a/test/php/library/Icinga/Protocol/Ldap/ConnectionTest.php b/test/php/library/Icinga/Protocol/Ldap/ConnectionTest.php new file mode 100644 index 000000000..182004703 --- /dev/null +++ b/test/php/library/Icinga/Protocol/Ldap/ConnectionTest.php @@ -0,0 +1,258 @@ +getAttributesMock; + } + + function ldap_start_tls() + { + global $self; + $self->startTlsCalled = true; + } + + function ldap_set_option($ds, $option, $value) + { + global $self; + $self->activatedOptions[$option] = $value; + return true; + } + + function ldap_set($ds, $option) + { + global $self; + $self->activatedOptions[] = $option; + } + + function ldap_control_paged_result() + { + global $self; + $self->pagedResultsCalled = true; + return true; + } + + function ldap_control_paged_result_response() + { + return true; + } + + function ldap_get_dn() + { + return NULL; + } + + function ldap_free_result() + { + return NULL; + } + } + + private function node(&$element, $name) + { + $element['count']++; + $element[$name] = array('count' => 0); + $element[] = $name; + } + + private function addEntry(&$element, $name, $entry) + { + $element[$name]['count']++; + $element[$name][] = $entry; + } + + private function mockQuery() + { + return Mockery::mock('overload:Icinga\Protocol\Ldap\Query') + ->shouldReceive(array( + 'from' => Mockery::self(), + 'create' => array('count' => 1), + 'listFields' => array('count' => 1), + 'getLimit' => 1, + 'hasOffset' => false, + 'hasBase' => false, + 'getSortColumns' => array(), + 'getUsePagedResults' => true + )); + } + + private function connectionFetchAll() + { + $this->mockQuery(); + $this->connection->connect(); + $this->connection->fetchAll(Mockery::self()); + } + + public function setUp() + { + $this->pagedResultsCalled = false; + $this->startTlsCalled = false; + $this->activatedOptions = array(); + + $this->mockLdapFunctions(); + + $config = new ConfigObject( + array( + 'hostname' => 'localhost', + 'root_dn' => 'dc=example,dc=com', + 'bind_dn' => 'cn=user,ou=users,dc=example,dc=com', + 'bind_pw' => '***' + ) + ); + $this->connection = new Connection($config); + + $caps = array('count' => 0); + $this->node($caps, 'defaultNamingContext'); + $this->node($caps, 'namingContexts'); + $this->node($caps, 'supportedCapabilities'); + $this->node($caps, 'supportedControl'); + $this->node($caps, 'supportedLDAPVersion'); + $this->node($caps, 'supportedExtension'); + $this->getAttributesMock = $caps; + } + + public function testUsePageControlWhenAnnounced() + { + if (version_compare(PHP_VERSION, '5.4.0') < 0) { + $this->markTestSkipped('Page control needs at least PHP_VERSION 5.4.0'); + } + + $this->addEntry($this->getAttributesMock, 'supportedControl', Capability::LDAP_PAGED_RESULT_OID_STRING); + $this->connectionFetchAll(); + + // see ticket #7993 + $this->assertEquals(true, $this->pagedResultsCalled, "Use paged result when capability is present."); + } + + public function testDontUsePagecontrolWhenNotAnnounced() + { + if (version_compare(PHP_VERSION, '5.4.0') < 0) { + $this->markTestSkipped('Page control needs at least PHP_VERSION 5.4.0'); + } + $this->connectionFetchAll(); + + // see ticket #8490 + $this->assertEquals(false, $this->pagedResultsCalled, "Don't use paged result when capability is not announced."); + } + + public function testUseLdapV2WhenAnnounced() + { + // TODO: Test turned off, see other TODO in Ldap/Connection. + $this->markTestSkipped('LdapV2 currently turned off.'); + + $this->addEntry($this->getAttributesMock, 'supportedLDAPVersion', 2); + $this->connectionFetchAll(); + + $this->assertArrayHasKey(LDAP_OPT_PROTOCOL_VERSION, $this->activatedOptions, "LDAP version must be set"); + $this->assertEquals($this->activatedOptions[LDAP_OPT_PROTOCOL_VERSION], 2); + } + + public function testUseLdapV3WhenAnnounced() + { + $this->addEntry($this->getAttributesMock, 'supportedLDAPVersion', 3); + $this->connectionFetchAll(); + + $this->assertArrayHasKey(LDAP_OPT_PROTOCOL_VERSION, $this->activatedOptions, "LDAP version must be set"); + $this->assertEquals($this->activatedOptions[LDAP_OPT_PROTOCOL_VERSION], 3, "LDAPv3 must be active"); + } + + public function testDefaultSettings() + { + $this->connectionFetchAll(); + + $this->assertArrayHasKey(LDAP_OPT_PROTOCOL_VERSION, $this->activatedOptions, "LDAP version must be set"); + $this->assertEquals($this->activatedOptions[LDAP_OPT_PROTOCOL_VERSION], 3, "LDAPv3 must be active"); + + $this->assertArrayHasKey(LDAP_OPT_REFERRALS, $this->activatedOptions, "Following referrals must be turned off"); + $this->assertEquals($this->activatedOptions[LDAP_OPT_REFERRALS], 0, "Following referrals must be turned off"); + } + + + public function testActiveDirectoryDiscovery() + { + $this->addEntry($this->getAttributesMock, 'supportedCapabilities', Capability::LDAP_CAP_ACTIVE_DIRECTORY_OID); + $this->connectionFetchAll(); + + $this->assertEquals(true, $this->connection->getCapabilities()->hasAdOid(), + "Server with LDAP_CAP_ACTIVE_DIRECTORY_OID must be recognized as Active Directory."); + } + + public function testDefaultNamingContext() + { + $this->addEntry($this->getAttributesMock, 'defaultNamingContext', 'dn=default,dn=contex'); + $this->connectionFetchAll(); + + $this->assertEquals('dn=default,dn=contex', $this->connection->getCapabilities()->getDefaultNamingContext(), + 'Default naming context must be correctly recognized.'); + } + + public function testDefaultNamingContextFallback() + { + $this->addEntry($this->getAttributesMock, 'namingContexts', 'dn=some,dn=other,dn=context'); + $this->addEntry($this->getAttributesMock, 'namingContexts', 'dn=default,dn=context'); + $this->connectionFetchAll(); + + $this->assertEquals('dn=some,dn=other,dn=context', $this->connection->getCapabilities()->getDefaultNamingContext(), + 'If defaultNamingContext is missing, the connection must fallback to first namingContext.'); + } +}