11078ec26SAndreas Gohr<?php 21078ec26SAndreas Gohr 31078ec26SAndreas Gohrnamespace dokuwiki\plugin\pureldap\classes; 41078ec26SAndreas Gohr 51078ec26SAndreas Gohruse FreeDSx\Ldap\Entry\Attribute; 61078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\BindException; 71078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\ConnectionException; 81078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\OperationException; 91078ec26SAndreas Gohruse FreeDSx\Ldap\LdapClient; 101078ec26SAndreas Gohr 111078ec26SAndreas Gohrrequire_once __DIR__ . '/../vendor/autoload.php'; 121078ec26SAndreas Gohr 131078ec26SAndreas Gohrabstract class Client 141078ec26SAndreas Gohr{ 151078ec26SAndreas Gohr /** @var array the configuration */ 161078ec26SAndreas Gohr protected $config; 171078ec26SAndreas Gohr 181078ec26SAndreas Gohr /** @var LdapClient */ 191078ec26SAndreas Gohr protected $ldap; 201078ec26SAndreas Gohr 211078ec26SAndreas Gohr /** @var bool is this client authenticated already? */ 221078ec26SAndreas Gohr protected $isAuthenticated = false; 231078ec26SAndreas Gohr 241078ec26SAndreas Gohr /** @var array cached user info */ 251078ec26SAndreas Gohr protected $userCache = []; 261078ec26SAndreas Gohr 27*5a3b9122SAndreas Gohr /** @var array cached group list */ 28*5a3b9122SAndreas Gohr protected $groupCache = []; 29*5a3b9122SAndreas Gohr 301078ec26SAndreas Gohr /** 311078ec26SAndreas Gohr * Client constructor. 321078ec26SAndreas Gohr * @param array $config 331078ec26SAndreas Gohr */ 341078ec26SAndreas Gohr public function __construct($config) 351078ec26SAndreas Gohr { 361078ec26SAndreas Gohr $this->config = $this->prepareConfig($config); 371078ec26SAndreas Gohr $this->ldap = new LdapClient($this->config); 381078ec26SAndreas Gohr } 391078ec26SAndreas Gohr 401078ec26SAndreas Gohr /** 411078ec26SAndreas Gohr * Setup sane config defaults 421078ec26SAndreas Gohr * 431078ec26SAndreas Gohr * @param array $config 441078ec26SAndreas Gohr * @return array 451078ec26SAndreas Gohr */ 461078ec26SAndreas Gohr protected function prepareConfig($config) 471078ec26SAndreas Gohr { 481078ec26SAndreas Gohr $defaults = [ 491078ec26SAndreas Gohr 'defaultgroup' => 'user', // we expect this to be passed from global conf 501078ec26SAndreas Gohr 'use_tls' => false, 511078ec26SAndreas Gohr 'use_ssl' => false, 521078ec26SAndreas Gohr 'port' => '', 531078ec26SAndreas Gohr 'admin_username' => '', 541078ec26SAndreas Gohr 'admin_password' => '', 55*5a3b9122SAndreas Gohr 'page_size' => 1000, 561078ec26SAndreas Gohr ]; 571078ec26SAndreas Gohr 581078ec26SAndreas Gohr $config = array_merge($defaults, $config); 591078ec26SAndreas Gohr 601078ec26SAndreas Gohr // default port depends on SSL setting 611078ec26SAndreas Gohr if (!$config['port']) { 621078ec26SAndreas Gohr $config['port'] = $config['use_ssl'] ? 636 : 389; 631078ec26SAndreas Gohr } 641078ec26SAndreas Gohr 651078ec26SAndreas Gohr return $config; 661078ec26SAndreas Gohr } 671078ec26SAndreas Gohr 681078ec26SAndreas Gohr /** 691078ec26SAndreas Gohr * Authenticate as admin 701078ec26SAndreas Gohr */ 711078ec26SAndreas Gohr public function autoAuth() 721078ec26SAndreas Gohr { 731078ec26SAndreas Gohr if ($this->isAuthenticated) return true; 741078ec26SAndreas Gohr return $this->authenticate($this->config['admin_username'], $this->config['admin_password']); 751078ec26SAndreas Gohr } 761078ec26SAndreas Gohr 771078ec26SAndreas Gohr /** 781078ec26SAndreas Gohr * Authenticates a given user. This client will remain authenticated 791078ec26SAndreas Gohr * 801078ec26SAndreas Gohr * @param string $user 811078ec26SAndreas Gohr * @param string $pass 821078ec26SAndreas Gohr * @return bool was the authentication successful? 83*5a3b9122SAndreas Gohr * @noinspection PhpRedundantCatchClauseInspection 841078ec26SAndreas Gohr */ 851078ec26SAndreas Gohr public function authenticate($user, $pass) 861078ec26SAndreas Gohr { 871078ec26SAndreas Gohr if ($this->config['use_tls']) { 881078ec26SAndreas Gohr try { 891078ec26SAndreas Gohr $this->ldap->startTls(); 901078ec26SAndreas Gohr } catch (OperationException $e) { 911078ec26SAndreas Gohr $this->debug($e); 921078ec26SAndreas Gohr } 931078ec26SAndreas Gohr } 941078ec26SAndreas Gohr 951078ec26SAndreas Gohr try { 961078ec26SAndreas Gohr $this->ldap->bind($user, $pass); 971078ec26SAndreas Gohr } catch (BindException $e) { 981078ec26SAndreas Gohr return false; 991078ec26SAndreas Gohr } catch (ConnectionException $e) { 1001078ec26SAndreas Gohr $this->debug($e); 1011078ec26SAndreas Gohr return false; 1021078ec26SAndreas Gohr } catch (OperationException $e) { 1031078ec26SAndreas Gohr $this->debug($e); 1041078ec26SAndreas Gohr return false; 1051078ec26SAndreas Gohr } 1061078ec26SAndreas Gohr 1071078ec26SAndreas Gohr $this->isAuthenticated = true; 1081078ec26SAndreas Gohr return true; 1091078ec26SAndreas Gohr } 1101078ec26SAndreas Gohr 1111078ec26SAndreas Gohr /** 1121078ec26SAndreas Gohr * Get info for a single user, use cache if available 1131078ec26SAndreas Gohr * 1141078ec26SAndreas Gohr * @param string $username 1151078ec26SAndreas Gohr * @param bool $fetchgroups Are groups needed? 1161078ec26SAndreas Gohr * @return array|null 1171078ec26SAndreas Gohr */ 1181078ec26SAndreas Gohr public function getCachedUser($username, $fetchgroups = true) 1191078ec26SAndreas Gohr { 1201078ec26SAndreas Gohr if (isset($this->userCache[$username])) { 1211078ec26SAndreas Gohr if (!$fetchgroups || is_array($this->userCache[$username]['grps'])) { 1221078ec26SAndreas Gohr return $this->userCache[$username]; 1231078ec26SAndreas Gohr } 1241078ec26SAndreas Gohr } 1251078ec26SAndreas Gohr 1261078ec26SAndreas Gohr // fetch fresh data 1271078ec26SAndreas Gohr $info = $this->getUser($username, $fetchgroups); 1281078ec26SAndreas Gohr 1291078ec26SAndreas Gohr // store in cache 1301078ec26SAndreas Gohr if ($info !== null) { 1311078ec26SAndreas Gohr $this->userCache[$username] = $info; 1321078ec26SAndreas Gohr } 1331078ec26SAndreas Gohr 1341078ec26SAndreas Gohr return $info; 1351078ec26SAndreas Gohr } 1361078ec26SAndreas Gohr 1371078ec26SAndreas Gohr /** 1381078ec26SAndreas Gohr * Fetch a single user 1391078ec26SAndreas Gohr * 1401078ec26SAndreas Gohr * @param string $username 1411078ec26SAndreas Gohr * @param bool $fetchgroups Shall groups be fetched, too? 1421078ec26SAndreas Gohr * @return null|array 1431078ec26SAndreas Gohr */ 1441078ec26SAndreas Gohr abstract public function getUser($username, $fetchgroups = true); 1451078ec26SAndreas Gohr 1461078ec26SAndreas Gohr /** 147*5a3b9122SAndreas Gohr * Return a list of all available groups, use cache if available 148*5a3b9122SAndreas Gohr * 149*5a3b9122SAndreas Gohr * @return string[] 150*5a3b9122SAndreas Gohr */ 151*5a3b9122SAndreas Gohr public function getCachedGroups() 152*5a3b9122SAndreas Gohr { 153*5a3b9122SAndreas Gohr if (empty($this->groupCache)) { 154*5a3b9122SAndreas Gohr $this->groupCache = $this->getGroups(); 155*5a3b9122SAndreas Gohr } 156*5a3b9122SAndreas Gohr 157*5a3b9122SAndreas Gohr return $this->groupCache; 158*5a3b9122SAndreas Gohr } 159*5a3b9122SAndreas Gohr 160*5a3b9122SAndreas Gohr /** 161*5a3b9122SAndreas Gohr * Return a list of all available groups 162*5a3b9122SAndreas Gohr * 163*5a3b9122SAndreas Gohr * @return string[] 164*5a3b9122SAndreas Gohr */ 165*5a3b9122SAndreas Gohr abstract public function getGroups(); 166*5a3b9122SAndreas Gohr 167*5a3b9122SAndreas Gohr /** 1681078ec26SAndreas Gohr * Helper method to get the first value of the given attribute 1691078ec26SAndreas Gohr * 1701078ec26SAndreas Gohr * The given attribute may be null, an empty string is returned then 1711078ec26SAndreas Gohr * 1721078ec26SAndreas Gohr * @param Attribute|null $attribute 1731078ec26SAndreas Gohr * @return string 1741078ec26SAndreas Gohr */ 175*5a3b9122SAndreas Gohr protected function attr2str($attribute) 176*5a3b9122SAndreas Gohr { 1771078ec26SAndreas Gohr if ($attribute !== null) { 1781078ec26SAndreas Gohr return $attribute->firstValue(); 1791078ec26SAndreas Gohr } 1801078ec26SAndreas Gohr return ''; 1811078ec26SAndreas Gohr } 1821078ec26SAndreas Gohr 1831078ec26SAndreas Gohr /** 1841078ec26SAndreas Gohr * Handle debugging 1851078ec26SAndreas Gohr * 1861078ec26SAndreas Gohr * @param \Exception $e 1871078ec26SAndreas Gohr */ 1881078ec26SAndreas Gohr protected function debug(\Exception $e) 1891078ec26SAndreas Gohr { 1901078ec26SAndreas Gohr if (defined('DOKU_UNITTEST')) { 1918595f73eSAndreas Gohr throw new \RuntimeException('', 0, $e); 1921078ec26SAndreas Gohr } 1931078ec26SAndreas Gohr 1941078ec26SAndreas Gohr msg($e->getMessage(), -1); 1951078ec26SAndreas Gohr } 1961078ec26SAndreas Gohr} 197