]> BookStack Code Mirror - bookstack/commitdiff
multiple ldap server update
authorKhazhinov Vladislav <redacted>
Fri, 30 Sep 2022 06:52:12 +0000 (09:52 +0300)
committerKhazhinov Vladislav <redacted>
Fri, 30 Sep 2022 06:52:12 +0000 (09:52 +0300)
.env.example.complete
app/Auth/Access/LdapService.php

index 09d863d93ed7301929e54dd187ed7c2906696173..d84d58d9da26c2e829a0ece728dec09202b1dd9b 100644 (file)
@@ -207,7 +207,6 @@ 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
index aa4c997728610e23ab0711c161d8730fcba080f2..ddd7c6280574efa26066bf67ba24f5f13dd1719c 100644 (file)
@@ -216,105 +216,87 @@ class LdapService
             $this->ldap->setOption(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
         }
 
-        $serverDetails = $this->parseServerString($this->config['server']);
-        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'));
-                    }
+        $serverDetails = $this->parseEnvironmentServer($this->config['server']);
+        $this->ldapConnection = $this->prepareServerConnection($serverDetails);
 
-                    // Set any required options
-                    if ($this->config['version']) {
-                        $this->ldap->setVersion($ldapConnection, $this->config['version']);
-                    }
+        return $this->ldapConnection;
+    }
+
+    /**
+     * Processes an array of received servers and returns the first working connection.
+     *
+     * @param  array  $serverDetails
+     * @return resource
+     * @throws LdapException
+     */
+    protected function prepareServerConnection(array $serverDetails)
+    {
+        $lastException = null;
+        foreach ($serverDetails as $server) {
+            try {
+                $ldapConnection = $this->ldap->connect($server['host'], $server['port']);
 
-                    // 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');
-                        }
+                if (!$ldapConnection) {
+                    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 ($fail_counter == count($serverDetails['hosts'])) {
-                throw new LdapException(trans('errors.ldap_cannot_connect'));
+                return $ldapConnection;
+            } catch (LdapException $exception) {
+                $lastException = $exception;
             }
-        } else {
-            $ldapConnection = $this->ldap->connect($serverDetails['host'], $serverDetails['port']);
+        }
 
-            if ($ldapConnection === false) {
-                throw new LdapException(trans('errors.ldap_cannot_connect'));
-            }
+        throw $lastException;
+    }
 
-            // Set any required options
-            if ($this->config['version']) {
-                $this->ldap->setVersion($ldapConnection, $this->config['version']);
-            }
+    /**
+     * Parse environment variable with LDAP server and returns an array of recognized servers.
+     * If you need to use multiple addresses, separate them with a semicolon.
+     * Ex: 'ldap.example.com:8069;ldaps://ldap.example.com'
+     */
+    protected function parseEnvironmentServer(string $environmentServer): array
+    {
+        $explodedEnvironmentServer = explode(';', $environmentServer);
+        $result_servers = [];
 
-            // 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');
-                }
-            }
+        foreach ($explodedEnvironmentServer as $serverString) {
+            $result_servers[] = $this->parseServerString($serverString);
         }
 
-        $this->ldapConnection = $ldapConnection;
-
-        return $this->ldapConnection;
+        return $result_servers;
     }
 
     /**
      * 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
     {
-        $explodedServerString = explode(';', $serverString);
-        if (count($explodedServerString) > 1) {
-            $result = ['hosts' => []];
-
-            foreach ($explodedServerString as $serverString) {
-                $serverNameParts = explode(':', $serverString);
+        $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;
-
-                $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];
-            }
+        // 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;
+        // Otherwise, extract the port out
+        $hostName = $serverNameParts[0];
+        $ldapPort = (count($serverNameParts) > 1) ? intval($serverNameParts[1]) : 389;
 
-            return ['host' => $hostName, 'port' => $ldapPort];
-        }
+        return ['host' => $hostName, 'port' => $ldapPort];
     }
 
     /**