From 392eef82730478000e6a87060f02e88111fd02a1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 16 Oct 2022 22:15:15 +0100 Subject: [PATCH] Added ldap host failover test, updated error handling Error handling updated after testing, since the ldap 'starttls' operation can throw an error, or maybe return false. The PHP docs are quite under-documented in regards to this function. --- app/Auth/Access/LdapService.php | 9 +++++++-- tests/Auth/LdapTest.php | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index ddd7c6280..a45c07c2f 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -247,8 +247,13 @@ class LdapService // Start and verify TLS if it's enabled if ($this->config['start_tls']) { - $started = $this->ldap->startTls($ldapConnection); - if (!$started) { + try { + $tlsStarted = $this->ldap->startTls($ldapConnection); + } catch (ErrorException $exception) { + $tlsStarted = false; + } + + if (!$tlsStarted) { throw new LdapException('Could not start TLS connection'); } } diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 978420f86..3721898bd 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -29,6 +29,7 @@ class LdapTest extends TestCase config()->set([ 'auth.method' => 'ldap', 'auth.defaults.guard' => 'ldap', + 'services.ldap.server' => 'ldap.example.com', 'services.ldap.base_dn' => 'dc=ldap,dc=local', 'services.ldap.email_attribute' => 'mail', 'services.ldap.display_name_attribute' => 'cn', @@ -581,6 +582,39 @@ class LdapTest extends TestCase $this->checkLdapReceivesCorrectDetails('ldap.bookstack.com', 'ldap.bookstack.com', 389); } + public function test_host_fail_over_by_using_semicolon_seperated_hosts() + { + app('config')->set([ + 'services.ldap.server' => 'ldap-tiger.example.com;ldap-donkey.example.com:8080', + ]); + + // Standard mocks + $this->commonLdapMocks(0, 1, 1, 2, 1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)->andReturn(['count' => 1, 0 => [ + 'uid' => [$this->mockUser->name], + 'cn' => [$this->mockUser->name], + 'dn' => ['dc=test' . config('services.ldap.base_dn')], + ]]); + + $this->mockLdap->shouldReceive('connect')->once()->with('ldap-tiger.example.com', 389)->andReturn(false); + $this->mockLdap->shouldReceive('connect')->once()->with('ldap-donkey.example.com', 8080)->andReturn($this->resourceId); + $this->mockUserLogin(); + } + + public function test_host_fail_over_by_using_semicolon_seperated_hosts_still_throws_error() + { + app('config')->set([ + 'services.ldap.server' => 'ldap-tiger.example.com;ldap-donkey.example.com:8080', + ]); + + $this->mockLdap->shouldReceive('connect')->once()->with('ldap-tiger.example.com', 389)->andReturn(false); + $this->mockLdap->shouldReceive('connect')->once()->with('ldap-donkey.example.com', 8080)->andReturn(false); + + $resp = $this->mockUserLogin(); + $resp->assertStatus(500); + $resp->assertSee('Cannot connect to ldap server, Initial connection failed'); + } + public function test_forgot_password_routes_inaccessible() { $resp = $this->get('/password/email');