]> BookStack Code Mirror - bookstack/commitdiff
multiple ldap server
authorKhazhinov Vladislav <redacted>
Wed, 21 Sep 2022 12:24:57 +0000 (15:24 +0300)
committerKhazhinov Vladislav <redacted>
Wed, 21 Sep 2022 12:24:57 +0000 (15:24 +0300)
.env.example.complete
app/Auth/Access/LdapService.php

index 03e52d6bb673d05e99cd20f9b7eeac2dd399a2c4..09d863d93ed7301929e54dd187ed7c2906696173 100644 (file)
@@ -207,6 +207,7 @@ TWITTER_AUTO_CONFIRM_EMAIL=false
 
 # LDAP authentication configuration
 # Refer to https://www.bookstackapp.com/docs/admin/ldap-auth/
+# If you need to use multiple addresses, separate them with a semicolon. Ex: dc1.domain.local:389;dc2.domain.local:389
 LDAP_SERVER=false
 LDAP_BASE_DN=false
 LDAP_DN=false
@@ -368,4 +369,4 @@ LOG_FAILED_LOGIN_CHANNEL=errorlog_plain_webserver
 # IP address '146.191.42.4' would result in '146.191.x.x' being logged.
 # For the IPv6 address '2001:db8:85a3:8d3:1319:8a2e:370:7348' this would result as:
 # '2001:db8:85a3:8d3:x:x:x:x'
-IP_ADDRESS_PRECISION=4
\ No newline at end of file
+IP_ADDRESS_PRECISION=4
index 359eeca2f5e863ab229c102a15880cce00580823..aa4c997728610e23ab0711c161d8730fcba080f2 100644 (file)
@@ -217,22 +217,54 @@ class LdapService
         }
 
         $serverDetails = $this->parseServerString($this->config['server']);
-        $ldapConnection = $this->ldap->connect($serverDetails['host'], $serverDetails['port']);
+        if (array_key_exists('hosts', $serverDetails)) {
+            $fail_counter = 0;
+            foreach ($serverDetails['hosts'] as $serverDetailsItem) {
+                try {
+                    $ldapConnection = $this->ldap->connect($serverDetailsItem['host'], $serverDetailsItem['port']);
+
+                    if ($ldapConnection === false) {
+                        throw new LdapException(trans('errors.ldap_cannot_connect'));
+                    }
+
+                    // Set any required options
+                    if ($this->config['version']) {
+                        $this->ldap->setVersion($ldapConnection, $this->config['version']);
+                    }
+
+                    // Start and verify TLS if it's enabled
+                    if ($this->config['start_tls']) {
+                        $started = $this->ldap->startTls($ldapConnection);
+                        if (!$started) {
+                            throw new LdapException('Could not start TLS connection');
+                        }
+                    }
+                } catch (\Throwable $exception) {
+                    $fail_counter++;
+                }
+            }
 
-        if ($ldapConnection === false) {
-            throw new LdapException(trans('errors.ldap_cannot_connect'));
-        }
+            if ($fail_counter == count($serverDetails['hosts'])) {
+                throw new LdapException(trans('errors.ldap_cannot_connect'));
+            }
+        } else {
+            $ldapConnection = $this->ldap->connect($serverDetails['host'], $serverDetails['port']);
 
-        // Set any required options
-        if ($this->config['version']) {
-            $this->ldap->setVersion($ldapConnection, $this->config['version']);
-        }
+            if ($ldapConnection === false) {
+                throw new LdapException(trans('errors.ldap_cannot_connect'));
+            }
+
+            // Set any required options
+            if ($this->config['version']) {
+                $this->ldap->setVersion($ldapConnection, $this->config['version']);
+            }
 
-        // Start and verify TLS if it's enabled
-        if ($this->config['start_tls']) {
-            $started = $this->ldap->startTls($ldapConnection);
-            if (!$started) {
-                throw new LdapException('Could not start TLS connection');
+            // Start and verify TLS if it's enabled
+            if ($this->config['start_tls']) {
+                $started = $this->ldap->startTls($ldapConnection);
+                if (!$started) {
+                    throw new LdapException('Could not start TLS connection');
+                }
             }
         }
 
@@ -244,21 +276,45 @@ class LdapService
     /**
      * Parse a LDAP server string and return the host and port for a connection.
      * Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com'.
+     * If you need to use multiple addresses, separate them with a semicolon.
+     * Ex: dc1.domain.local:389;dc2.domain.local:389
      */
     protected function parseServerString(string $serverString): array
     {
-        $serverNameParts = explode(':', $serverString);
+        $explodedServerString = explode(';', $serverString);
+        if (count($explodedServerString) > 1) {
+            $result = ['hosts' => []];
 
-        // If we have a protocol just return the full string since PHP will ignore a separate port.
-        if ($serverNameParts[0] === 'ldaps' || $serverNameParts[0] === 'ldap') {
-            return ['host' => $serverString, 'port' => 389];
-        }
+            foreach ($explodedServerString as $serverString) {
+                $serverNameParts = explode(':', $serverString);
 
-        // Otherwise, extract the port out
-        $hostName = $serverNameParts[0];
-        $ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
+                // If we have a protocol just return the full string since PHP will ignore a separate port.
+                if ($serverNameParts[0] === 'ldaps' || $serverNameParts[0] === 'ldap') {
+                    return ['host' => $serverString, 'port' => 389];
+                }
 
-        return ['host' => $hostName, 'port' => $ldapPort];
+                // Otherwise, extract the port out
+                $hostName = $serverNameParts[0];
+                $ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
+
+                $result['hosts'][] = ['host' => $hostName, 'port' => $ldapPort];
+            }
+
+            return $result;
+        } else {
+            $serverNameParts = explode(':', $serverString);
+
+            // If we have a protocol just return the full string since PHP will ignore a separate port.
+            if ($serverNameParts[0] === 'ldaps' || $serverNameParts[0] === 'ldap') {
+                return ['host' => $serverString, 'port' => 389];
+            }
+
+            // Otherwise, extract the port out
+            $hostName = $serverNameParts[0];
+            $ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
+
+            return ['host' => $hostName, 'port' => $ldapPort];
+        }
     }
 
     /**