]> BookStack Code Mirror - bookstack/blobdiff - app/Services/LdapService.php
Trying to make the tests green.
[bookstack] / app / Services / LdapService.php
index cd80290e48b39a1c90b718c2b4e884b6a1f23686..598efc19dd68828fab45da38304509056f215189 100644 (file)
@@ -4,10 +4,27 @@
 use BookStack\Exceptions\LdapException;
 use Illuminate\Contracts\Auth\Authenticatable;
 
+/**
+ * Class LdapService
+ * Handles any app-specific LDAP tasks.
+ * @package BookStack\Services
+ */
 class LdapService
 {
 
+    protected $ldap;
     protected $ldapConnection;
+    protected $config;
+
+    /**
+     * LdapService constructor.
+     * @param Ldap $ldap
+     */
+    public function __construct(Ldap $ldap)
+    {
+        $this->ldap = $ldap;
+        $this->config = config('services.ldap');
+    }
 
     /**
      * Get the details of a user from LDAP using the given username.
@@ -19,20 +36,23 @@ class LdapService
     public function getUserDetails($userName)
     {
         $ldapConnection = $this->getConnection();
+        $this->bindSystemUser($ldapConnection);
 
         // Find user
-        $userFilter = $this->buildFilter(config('services.ldap.user_filter'), ['user' => $userName]);
-        $baseDn = config('services.ldap.base_dn');
-        $ldapSearch = ldap_search($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', 'mail']);
-        $users = ldap_get_entries($ldapConnection, $ldapSearch);
+        $userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]);
+        $baseDn = $this->config['base_dn'];
+        $emailAttr = $this->config['email_attribute'];
+        $followReferrals = $this->config['follow_referrals'] ? 1 : 0;
+        $this->ldap->setOption($ldapConnection, LDAP_OPT_REFERRALS, $followReferrals);
+        $users = $this->ldap->searchAndGetEntries($ldapConnection, $baseDn, $userFilter, ['cn', 'uid', 'dn', $emailAttr]);
         if ($users['count'] === 0) return null;
 
         $user = $users[0];
         return [
-            'uid'  => $user['uid'][0],
-            'name' => $user['cn'][0],
-            'dn'   => $user['dn'],
-            'email' => (isset($user['mail'])) ? $user['mail'][0] : null
+            'uid'   => (isset($user['uid'])) ? $user['uid'][0] : $user['dn'],
+            'name'  => $user['cn'][0],
+            'dn'    => $user['dn'],
+            'email' => (isset($user[$emailAttr])) ? (is_array($user[$emailAttr]) ? $user[$emailAttr][0] : $user[$emailAttr]) : null
         ];
     }
 
@@ -50,7 +70,12 @@ class LdapService
         if ($ldapUser['uid'] !== $user->external_auth_id) return false;
 
         $ldapConnection = $this->getConnection();
-        $ldapBind = @ldap_bind($ldapConnection, $ldapUser['dn'], $password);
+        try {
+            $ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password);
+        } catch (\ErrorException $e) {
+            $ldapBind = false;
+        }
+
         return $ldapBind;
     }
 
@@ -62,17 +87,17 @@ class LdapService
      */
     protected function bindSystemUser($connection)
     {
-        $ldapDn = config('services.ldap.dn');
-        $ldapPass = config('services.ldap.pass');
+        $ldapDn = $this->config['dn'];
+        $ldapPass = $this->config['pass'];
 
         $isAnonymous = ($ldapDn === false || $ldapPass === false);
         if ($isAnonymous) {
-            $ldapBind = ldap_bind($connection);
+            $ldapBind = $this->ldap->bind($connection);
         } else {
-            $ldapBind = ldap_bind($connection, $ldapDn, $ldapPass);
+            $ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);
         }
 
-        if (!$ldapBind) throw new LdapException('LDAP access failed using ' . $isAnonymous ? ' anonymous bind.' : ' given dn & pass details');
+        if (!$ldapBind) throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed')));
     }
 
     /**
@@ -86,20 +111,26 @@ class LdapService
         if ($this->ldapConnection !== null) return $this->ldapConnection;
 
         // Check LDAP extension in installed
-        if (!function_exists('ldap_connect')) {
-            throw new LdapException('LDAP PHP extension not installed');
+        if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
+            throw new LdapException(trans('errors.ldap_extension_not_installed'));
         }
 
-        // Get port from server string if specified.
-        $ldapServer = explode(':', config('services.ldap.server'));
-        $ldapConnection = ldap_connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389);
+        // Get port from server string and protocol if specified.
+        $ldapServer = explode(':', $this->config['server']);
+        $hasProtocol = preg_match('/^ldaps{0,1}\:\/\//', $this->config['server']) === 1;
+        if (!$hasProtocol) array_unshift($ldapServer, '');
+        $hostName = $ldapServer[0] . ($hasProtocol?':':'') . $ldapServer[1];
+        $defaultPort = $ldapServer[0] === 'ldaps' ? 636 : 389;
+        $ldapConnection = $this->ldap->connect($hostName, count($ldapServer) > 2 ? intval($ldapServer[2]) : $defaultPort);
 
         if ($ldapConnection === false) {
-            throw new LdapException('Cannot connect to ldap server, Initial connection failed');
+            throw new LdapException(trans('errors.ldap_cannot_connect'));
         }
 
         // Set any required options
-        ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); // TODO - make configurable
+        if ($this->config['version']) {
+            $this->ldap->setVersion($ldapConnection, $this->config['version']);
+        }
 
         $this->ldapConnection = $ldapConnection;
         return $this->ldapConnection;
@@ -107,7 +138,7 @@ class LdapService
 
     /**
      * Build a filter string by injecting common variables.
-     * @param       $filterString
+     * @param string $filterString
      * @param array $attrs
      * @return string
      */