]> BookStack Code Mirror - bookstack/blobdiff - app/Services/LdapService.php
Removes some unused code.
[bookstack] / app / Services / LdapService.php
index a540ab58bb1e26c165376b2c22673fc1b3fcdf30..598efc19dd68828fab45da38304509056f215189 100644 (file)
 
 
 use BookStack\Exceptions\LdapException;
+use Illuminate\Contracts\Auth\Authenticatable;
 
+/**
+ * Class LdapService
+ * Handles any app-specific LDAP tasks.
+ * @package BookStack\Services
+ */
 class LdapService
 {
 
-    public function getUserDetails($userName)
-    {
+    protected $ldap;
+    protected $ldapConnection;
+    protected $config;
 
-        if(!function_exists('ldap_connect')) {
-            throw new LdapException('LDAP PHP extension not installed');
-        }
+    /**
+     * 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.
+     * User found via configurable user filter.
+     * @param $userName
+     * @return array|null
+     * @throws LdapException
+     */
+    public function getUserDetails($userName)
+    {
+        $ldapConnection = $this->getConnection();
+        $this->bindSystemUser($ldapConnection);
 
-        $ldapServer = explode(':', config('services.ldap.server'));
-        $ldapConnection = ldap_connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389);
+        // Find user
+        $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'   => (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
+        ];
+    }
 
-        if ($ldapConnection === false) {
-            throw new LdapException('Cannot connect to ldap server, Initial connection failed');
+    /**
+     * @param Authenticatable $user
+     * @param string          $username
+     * @param string          $password
+     * @return bool
+     * @throws LdapException
+     */
+    public function validateUserCredentials(Authenticatable $user, $username, $password)
+    {
+        $ldapUser = $this->getUserDetails($username);
+        if ($ldapUser === null) return false;
+        if ($ldapUser['uid'] !== $user->external_auth_id) return false;
+
+        $ldapConnection = $this->getConnection();
+        try {
+            $ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password);
+        } catch (\ErrorException $e) {
+            $ldapBind = false;
         }
 
-        // Options
+        return $ldapBind;
+    }
 
-        ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); // TODO - make configurable
+    /**
+     * Bind the system user to the LDAP connection using the given credentials
+     * otherwise anonymous access is attempted.
+     * @param $connection
+     * @throws LdapException
+     */
+    protected function bindSystemUser($connection)
+    {
+        $ldapDn = $this->config['dn'];
+        $ldapPass = $this->config['pass'];
 
-        $ldapDn = config('services.ldap.dn');
-        $ldapPass = config('services.ldap.pass');
         $isAnonymous = ($ldapDn === false || $ldapPass === false);
         if ($isAnonymous) {
-            $ldapBind = ldap_bind($ldapConnection);
+            $ldapBind = $this->ldap->bind($connection);
         } else {
-            $ldapBind = ldap_bind($ldapConnection, $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')));
+    }
 
-        // Find user
-        $userFilter = $this->buildFilter(config('services.ldap.user_filter'), ['user' => $userName]);
-        //dd($userFilter);
-        $baseDn = config('services.ldap.base_dn');
-        $ldapSearch = ldap_search($ldapConnection, $baseDn, $userFilter);
-        $users = ldap_get_entries($ldapConnection, $ldapSearch);
+    /**
+     * Get the connection to the LDAP server.
+     * Creates a new connection if one does not exist.
+     * @return resource
+     * @throws LdapException
+     */
+    protected function getConnection()
+    {
+        if ($this->ldapConnection !== null) return $this->ldapConnection;
 
-        dd($users);
-    }
+        // Check LDAP extension in installed
+        if (!function_exists('ldap_connect') && config('app.env') !== 'testing') {
+            throw new LdapException(trans('errors.ldap_extension_not_installed'));
+        }
+
+        // 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(trans('errors.ldap_cannot_connect'));
+        }
+
+        // Set any required options
+        if ($this->config['version']) {
+            $this->ldap->setVersion($ldapConnection, $this->config['version']);
+        }
+
+        $this->ldapConnection = $ldapConnection;
+        return $this->ldapConnection;
+    }
 
-    private function buildFilter($filterString, $attrs)
+    /**
+     * Build a filter string by injecting common variables.
+     * @param string $filterString
+     * @param array $attrs
+     * @return string
+     */
+    protected function buildFilter($filterString, array $attrs)
     {
         $newAttrs = [];
         foreach ($attrs as $key => $attrText) {
-            $newKey = '${'.$key.'}';
+            $newKey = '${' . $key . '}';
             $newAttrs[$newKey] = $attrText;
         }
         return strtr($filterString, $newAttrs);