1*1078ec26SAndreas Gohr<?php 2*1078ec26SAndreas Gohr 3*1078ec26SAndreas Gohrnamespace dokuwiki\plugin\pureldap\classes; 4*1078ec26SAndreas Gohr 5*1078ec26SAndreas Gohruse FreeDSx\Ldap\Entry\Attribute; 6*1078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\BindException; 7*1078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\ConnectionException; 8*1078ec26SAndreas Gohruse FreeDSx\Ldap\Exception\OperationException; 9*1078ec26SAndreas Gohruse FreeDSx\Ldap\LdapClient; 10*1078ec26SAndreas Gohr 11*1078ec26SAndreas Gohrrequire_once __DIR__ . '/../vendor/autoload.php'; 12*1078ec26SAndreas Gohr 13*1078ec26SAndreas Gohrabstract class Client 14*1078ec26SAndreas Gohr{ 15*1078ec26SAndreas Gohr /** @var array the configuration */ 16*1078ec26SAndreas Gohr protected $config; 17*1078ec26SAndreas Gohr 18*1078ec26SAndreas Gohr /** @var LdapClient */ 19*1078ec26SAndreas Gohr protected $ldap; 20*1078ec26SAndreas Gohr 21*1078ec26SAndreas Gohr /** @var bool is this client authenticated already? */ 22*1078ec26SAndreas Gohr protected $isAuthenticated = false; 23*1078ec26SAndreas Gohr 24*1078ec26SAndreas Gohr /** @var array cached user info */ 25*1078ec26SAndreas Gohr protected $userCache = []; 26*1078ec26SAndreas Gohr 27*1078ec26SAndreas Gohr /** 28*1078ec26SAndreas Gohr * Client constructor. 29*1078ec26SAndreas Gohr * @param array $config 30*1078ec26SAndreas Gohr */ 31*1078ec26SAndreas Gohr public function __construct($config) 32*1078ec26SAndreas Gohr { 33*1078ec26SAndreas Gohr $this->config = $this->prepareConfig($config); 34*1078ec26SAndreas Gohr $this->ldap = new LdapClient($this->config); 35*1078ec26SAndreas Gohr } 36*1078ec26SAndreas Gohr 37*1078ec26SAndreas Gohr /** 38*1078ec26SAndreas Gohr * Setup sane config defaults 39*1078ec26SAndreas Gohr * 40*1078ec26SAndreas Gohr * @param array $config 41*1078ec26SAndreas Gohr * @return array 42*1078ec26SAndreas Gohr */ 43*1078ec26SAndreas Gohr protected function prepareConfig($config) 44*1078ec26SAndreas Gohr { 45*1078ec26SAndreas Gohr $defaults = [ 46*1078ec26SAndreas Gohr 'defaultgroup' => 'user', // we expect this to be passed from global conf 47*1078ec26SAndreas Gohr 'use_tls' => false, 48*1078ec26SAndreas Gohr 'use_ssl' => false, 49*1078ec26SAndreas Gohr 'port' => '', 50*1078ec26SAndreas Gohr 'admin_username' => '', 51*1078ec26SAndreas Gohr 'admin_password' => '', 52*1078ec26SAndreas Gohr ]; 53*1078ec26SAndreas Gohr 54*1078ec26SAndreas Gohr $config = array_merge($defaults, $config); 55*1078ec26SAndreas Gohr 56*1078ec26SAndreas Gohr // default port depends on SSL setting 57*1078ec26SAndreas Gohr if (!$config['port']) { 58*1078ec26SAndreas Gohr $config['port'] = $config['use_ssl'] ? 636 : 389; 59*1078ec26SAndreas Gohr } 60*1078ec26SAndreas Gohr 61*1078ec26SAndreas Gohr return $config; 62*1078ec26SAndreas Gohr } 63*1078ec26SAndreas Gohr 64*1078ec26SAndreas Gohr /** 65*1078ec26SAndreas Gohr * Authenticate as admin 66*1078ec26SAndreas Gohr */ 67*1078ec26SAndreas Gohr public function autoAuth() 68*1078ec26SAndreas Gohr { 69*1078ec26SAndreas Gohr if ($this->isAuthenticated) return true; 70*1078ec26SAndreas Gohr return $this->authenticate($this->config['admin_username'], $this->config['admin_password']); 71*1078ec26SAndreas Gohr } 72*1078ec26SAndreas Gohr 73*1078ec26SAndreas Gohr /** 74*1078ec26SAndreas Gohr * Authenticates a given user. This client will remain authenticated 75*1078ec26SAndreas Gohr * 76*1078ec26SAndreas Gohr * @param string $user 77*1078ec26SAndreas Gohr * @param string $pass 78*1078ec26SAndreas Gohr * @return bool was the authentication successful? 79*1078ec26SAndreas Gohr */ 80*1078ec26SAndreas Gohr public function authenticate($user, $pass) 81*1078ec26SAndreas Gohr { 82*1078ec26SAndreas Gohr if ($this->config['use_tls']) { 83*1078ec26SAndreas Gohr try { 84*1078ec26SAndreas Gohr $this->ldap->startTls(); 85*1078ec26SAndreas Gohr } catch (OperationException $e) { 86*1078ec26SAndreas Gohr $this->debug($e); 87*1078ec26SAndreas Gohr } 88*1078ec26SAndreas Gohr } 89*1078ec26SAndreas Gohr 90*1078ec26SAndreas Gohr try { 91*1078ec26SAndreas Gohr $this->ldap->bind($user, $pass); 92*1078ec26SAndreas Gohr } catch (BindException $e) { 93*1078ec26SAndreas Gohr return false; 94*1078ec26SAndreas Gohr } catch (ConnectionException $e) { 95*1078ec26SAndreas Gohr $this->debug($e); 96*1078ec26SAndreas Gohr return false; 97*1078ec26SAndreas Gohr } catch (OperationException $e) { 98*1078ec26SAndreas Gohr $this->debug($e); 99*1078ec26SAndreas Gohr return false; 100*1078ec26SAndreas Gohr } 101*1078ec26SAndreas Gohr 102*1078ec26SAndreas Gohr $this->isAuthenticated = true; 103*1078ec26SAndreas Gohr return true; 104*1078ec26SAndreas Gohr } 105*1078ec26SAndreas Gohr 106*1078ec26SAndreas Gohr /** 107*1078ec26SAndreas Gohr * Get info for a single user, use cache if available 108*1078ec26SAndreas Gohr * 109*1078ec26SAndreas Gohr * @param string $username 110*1078ec26SAndreas Gohr * @param bool $fetchgroups Are groups needed? 111*1078ec26SAndreas Gohr * @return array|null 112*1078ec26SAndreas Gohr */ 113*1078ec26SAndreas Gohr public function getCachedUser($username, $fetchgroups = true) 114*1078ec26SAndreas Gohr { 115*1078ec26SAndreas Gohr if (isset($this->userCache[$username])) { 116*1078ec26SAndreas Gohr if (!$fetchgroups || is_array($this->userCache[$username]['grps'])) { 117*1078ec26SAndreas Gohr return $this->userCache[$username]; 118*1078ec26SAndreas Gohr } 119*1078ec26SAndreas Gohr } 120*1078ec26SAndreas Gohr 121*1078ec26SAndreas Gohr // fetch fresh data 122*1078ec26SAndreas Gohr $info = $this->getUser($username, $fetchgroups); 123*1078ec26SAndreas Gohr 124*1078ec26SAndreas Gohr // store in cache 125*1078ec26SAndreas Gohr if ($info !== null) { 126*1078ec26SAndreas Gohr $this->userCache[$username] = $info; 127*1078ec26SAndreas Gohr } 128*1078ec26SAndreas Gohr 129*1078ec26SAndreas Gohr return $info; 130*1078ec26SAndreas Gohr } 131*1078ec26SAndreas Gohr 132*1078ec26SAndreas Gohr /** 133*1078ec26SAndreas Gohr * Fetch a single user 134*1078ec26SAndreas Gohr * 135*1078ec26SAndreas Gohr * @param string $username 136*1078ec26SAndreas Gohr * @param bool $fetchgroups Shall groups be fetched, too? 137*1078ec26SAndreas Gohr * @return null|array 138*1078ec26SAndreas Gohr */ 139*1078ec26SAndreas Gohr abstract public function getUser($username, $fetchgroups = true); 140*1078ec26SAndreas Gohr 141*1078ec26SAndreas Gohr /** 142*1078ec26SAndreas Gohr * Helper method to get the first value of the given attribute 143*1078ec26SAndreas Gohr * 144*1078ec26SAndreas Gohr * The given attribute may be null, an empty string is returned then 145*1078ec26SAndreas Gohr * 146*1078ec26SAndreas Gohr * @param Attribute|null $attribute 147*1078ec26SAndreas Gohr * @return string 148*1078ec26SAndreas Gohr */ 149*1078ec26SAndreas Gohr protected function attr2str($attribute) { 150*1078ec26SAndreas Gohr if($attribute !== null) { 151*1078ec26SAndreas Gohr return $attribute->firstValue(); 152*1078ec26SAndreas Gohr } 153*1078ec26SAndreas Gohr return ''; 154*1078ec26SAndreas Gohr } 155*1078ec26SAndreas Gohr 156*1078ec26SAndreas Gohr 157*1078ec26SAndreas Gohr /** 158*1078ec26SAndreas Gohr * Handle debugging 159*1078ec26SAndreas Gohr * 160*1078ec26SAndreas Gohr * @param \Exception $e 161*1078ec26SAndreas Gohr * @todo more output, better handling if it should be shown or what 162*1078ec26SAndreas Gohr */ 163*1078ec26SAndreas Gohr protected function debug(\Exception $e) 164*1078ec26SAndreas Gohr { 165*1078ec26SAndreas Gohr if(defined('DOKU_UNITTEST')) { 166*1078ec26SAndreas Gohr throw $e; 167*1078ec26SAndreas Gohr } 168*1078ec26SAndreas Gohr 169*1078ec26SAndreas Gohr msg($e->getMessage(), -1); 170*1078ec26SAndreas Gohr } 171*1078ec26SAndreas Gohr} 172