settings->enableLdap(); $ldap_connect = $this->getFunctionMock('App\\Models', 'ldap_connect'); $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock('App\\Models', 'ldap_set_option'); $ldap_set_option->expects($this->exactly(4)); $blah = Ldap::connectToLdap(); $this->assertEquals('hello', $blah, "LDAP_connect should return 'hello'"); } // other test cases - with/without client-side certs? // with/without LDAP version 3? // with/without ignore cert validation? // test (and mock) ldap_start_tls() ? public function test_bind_admin() { $this->settings->enableLdap(); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->once())->willReturn(true); $this->assertNull(Ldap::bindAdminToLdap('dummy')); } public function test_bind_bad() { $this->settings->enableLdap(); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->once())->willReturn(false); $this->getFunctionMock('App\\Models', 'ldap_error')->expects($this->once())->willReturn('exception'); $this->expectExceptionMessage('Could not bind to LDAP:'); $this->assertNull(Ldap::bindAdminToLdap('dummy')); } // other test cases - test donked password? public function test_anonymous_bind() { // todo - would be nice to introspect somehow to make sure the right parameters were passed? $this->settings->enableAnonymousLdap(); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->once())->willReturn(true); $this->assertNull(Ldap::bindAdminToLdap('dummy')); } public function test_bad_anonymous_bind() { $this->settings->enableAnonymousLdap(); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->once())->willReturn(false); $this->getFunctionMock('App\\Models', 'ldap_error')->expects($this->once())->willReturn('exception'); $this->expectExceptionMessage('Could not bind to LDAP:'); $this->assertNull(Ldap::bindAdminToLdap('dummy')); } public function test_bad_encrypted_password() { $this->settings->enableBadPasswordLdap(); $this->expectExceptionMessage('Your app key has changed'); $this->assertNull(Ldap::bindAdminToLdap('dummy')); } public function test_find_and_bind() { $this->settings->enableLdap(); $ldap_connect = $this->getFunctionMock('App\\Models', 'ldap_connect'); $ldap_connect->expects($this->exactly(3))->willReturn('hello'); $ldap_set_option = $this->getFunctionMock('App\\Models', 'ldap_set_option'); $ldap_set_option->expects($this->exactly(12)); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->exactly(2))->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_search')->expects($this->exactly(1))->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_first_entry')->expects($this->exactly(1))->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_unbind')->expects($this->exactly(2)); $this->getFunctionMock('App\\Models', 'ldap_count_entries')->expects($this->once())->willReturn(1); $this->getFunctionMock('App\\Models', 'ldap_get_dn')->expects($this->once())->willReturn('dn=FirstName Surname,ou=Org,dc=example,dc=com'); $this->getFunctionMock('App\\Models', 'ldap_get_attributes')->expects($this->exactly(1))->willReturn( [ 'count' => 1, 0 => [ 'sn' => 'Surname', 'firstname' => 'FirstName', ], ] ); $results = Ldap::findAndBindUserLdap('username', 'password'); $this->assertEqualsCanonicalizing(['count' => 1, 0 => ['sn' => 'Surname', 'firstname' => 'FirstName']], $results); } public function test_find_and_bind_bad_password() { $this->settings->enableLdap(); $ldap_connect = $this->getFunctionMock('App\\Models', 'ldap_connect'); $ldap_connect->expects($this->exactly(3))->willReturn('hello'); $ldap_set_option = $this->getFunctionMock('App\\Models', 'ldap_set_option'); $ldap_set_option->expects($this->exactly(12)); // $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->exactly(3))->willReturn( true, /* initial admin connection for 'fast path' */ false, /* the actual login for the user */ false, /* the direct login for the user binding-as-themselves in the legacy path */ true /* the admin login afterwards (which is weird and doesn't make sense) */ ); $this->getFunctionMock('App\\Models', 'ldap_unbind')->expects($this->exactly(2)); $this->getFunctionMock('App\\Models', 'ldap_error')->expects($this->never())->willReturn('exception'); $this->getFunctionMock('App\\Models', 'ldap_search')->expects($this->exactly(1))->willReturn(false); // uhm? $this->getFunctionMock('App\\Models', 'ldap_count_entries')->expects($this->exactly(1))->willReturn(1); $this->getFunctionMock('App\\Models', 'ldap_first_entry')->expects($this->exactly(1))->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_get_attributes')->expects($this->exactly(1))->willReturn(1); $this->getFunctionMock('App\\Models', 'ldap_get_dn')->expects($this->exactly(1))->willReturn('dn=FirstName Surname,ou=Org,dc=example,dc=com'); // $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception"); // $this->expectExceptionMessage("exception"); $results = Ldap::findAndBindUserLdap('username', 'password'); $this->assertFalse($results); } public function test_find_and_bind_cannot_find_self() { $this->settings->enableLdap(); $ldap_connect = $this->getFunctionMock('App\\Models', 'ldap_connect'); $ldap_connect->expects($this->exactly(2))->willReturn('hello'); $ldap_set_option = $this->getFunctionMock('App\\Models', 'ldap_set_option'); $ldap_set_option->expects($this->exactly(8)); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->exactly(2))->willReturn(true); // I think this is OK $this->getFunctionMock('App\\Models', 'ldap_search')->expects($this->exactly(2))->willReturn(false); // uhm? $this->getFunctionMock('App\\Models', 'ldap_unbind')->expects($this->once()); $this->getFunctionMock('App\\Models', 'ldap_count_entries')->expects($this->once())->willReturn(0); $this->expectExceptionMessage('Could not search LDAP:'); $results = Ldap::findAndBindUserLdap('username', 'password'); $this->assertFalse($results); } // maybe should do an AD test as well? public function test_find_ldap_users() { $this->settings->enableLdap(); $ldap_connect = $this->getFunctionMock('App\\Models', 'ldap_connect'); $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock('App\\Models', 'ldap_set_option'); $ldap_set_option->expects($this->exactly(4)); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->once())->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_search')->expects($this->once())->willReturn(['stuff']); $this->getFunctionMock('App\\Models', 'ldap_parse_result')->expects($this->once())->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_get_entries')->expects($this->once())->willReturn(['count' => 1]); $results = Ldap::findLdapUsers(); $this->assertEqualsCanonicalizing(['count' => 1], $results); } public function test_find_ldap_users_paginated() { $this->settings->enableLdap(); $ldap_connect = $this->getFunctionMock('App\\Models', 'ldap_connect'); $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock('App\\Models', 'ldap_set_option'); $ldap_set_option->expects($this->exactly(4)); $this->getFunctionMock('App\\Models', 'ldap_bind')->expects($this->once())->willReturn(true); $this->getFunctionMock('App\\Models', 'ldap_search')->expects($this->exactly(2))->willReturn(['stuff']); $this->getFunctionMock('App\\Models', 'ldap_parse_result')->expects($this->exactly(2))->willReturnCallback( function ($ldapconn, $search_results, $errcode, $matcheddn, $errmsg, $referrals, &$controls) { static $count = 0; if ($count == 0) { $count++; $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] = 'cookie'; return ['count' => 1]; } else { $controls = []; return ['count' => 1]; } } ); $this->getFunctionMock('App\\Models', 'ldap_get_entries')->expects($this->exactly(2))->willReturn(['count' => 1]); $results = Ldap::findLdapUsers(); $this->assertEqualsCanonicalizing(['count' => 2], $results); } public function test_nonexistent_tls_file() { $this->settings->enableLdap()->set(['ldap_client_tls_cert' => 'SAMPLE CERT TEXT']); $certfile = Setting::get_client_side_cert_path(); $this->assertStringEqualsFile($certfile, 'SAMPLE CERT TEXT'); } public function test_stale_tls_file() { file_put_contents(Setting::get_client_side_cert_path(), 'STALE CERT FILE'); sleep(1); // FIXME - this is going to slow down tests $this->settings->enableLdap()->set(['ldap_client_tls_cert' => 'SAMPLE CERT TEXT']); $certfile = Setting::get_client_side_cert_path(); $this->assertStringEqualsFile($certfile, 'SAMPLE CERT TEXT'); } public function test_fresh_tls_file() { $this->settings->enableLdap()->set(['ldap_client_tls_cert' => 'SAMPLE CERT TEXT']); $client_side_cert_path = Setting::get_client_side_cert_path(); file_put_contents($client_side_cert_path, 'WEIRDLY UPDATED CERT FILE'); clearstatcache(); // the system should respect our cache-file, since the settings haven't been updated $possibly_recached_cert_file = Setting::get_client_side_cert_path(); // this should *NOT* re-cache from the Settings $this->assertStringEqualsFile($possibly_recached_cert_file, 'WEIRDLY UPDATED CERT FILE'); } }