1<?php 2 3namespace dokuwiki\plugin\pureldap\classes; 4 5use FreeDSx\Ldap\Entry\Attribute; 6use FreeDSx\Ldap\Exception\BindException; 7use FreeDSx\Ldap\Exception\ConnectionException; 8use FreeDSx\Ldap\Exception\OperationException; 9use FreeDSx\Ldap\LdapClient; 10 11require_once __DIR__ . '/../vendor/autoload.php'; 12 13abstract class Client 14{ 15 /** @var array the configuration */ 16 protected $config; 17 18 /** @var LdapClient */ 19 protected $ldap; 20 21 /** @var bool is this client authenticated already? */ 22 protected $isAuthenticated = false; 23 24 /** @var array cached user info */ 25 protected $userCache = []; 26 27 /** @var array cached group list */ 28 protected $groupCache = []; 29 30 /** 31 * Client constructor. 32 * @param array $config 33 */ 34 public function __construct($config) 35 { 36 $this->config = $this->prepareConfig($config); 37 $this->ldap = new LdapClient($this->config); 38 } 39 40 /** 41 * Setup sane config defaults 42 * 43 * @param array $config 44 * @return array 45 */ 46 protected function prepareConfig($config) 47 { 48 $defaults = [ 49 'defaultgroup' => 'user', // we expect this to be passed from global conf 50 'use_tls' => false, 51 'use_ssl' => false, 52 'port' => '', 53 'admin_username' => '', 54 'admin_password' => '', 55 'page_size' => 1000, 56 ]; 57 58 $config = array_merge($defaults, $config); 59 60 // default port depends on SSL setting 61 if (!$config['port']) { 62 $config['port'] = $config['use_ssl'] ? 636 : 389; 63 } 64 65 return $config; 66 } 67 68 /** 69 * Authenticate as admin 70 */ 71 public function autoAuth() 72 { 73 if ($this->isAuthenticated) return true; 74 return $this->authenticate($this->config['admin_username'], $this->config['admin_password']); 75 } 76 77 /** 78 * Authenticates a given user. This client will remain authenticated 79 * 80 * @param string $user 81 * @param string $pass 82 * @return bool was the authentication successful? 83 * @noinspection PhpRedundantCatchClauseInspection 84 */ 85 public function authenticate($user, $pass) 86 { 87 if ($this->config['use_tls']) { 88 try { 89 $this->ldap->startTls(); 90 } catch (OperationException $e) { 91 $this->fatal($e); 92 } 93 } 94 95 try { 96 $this->ldap->bind($user, $pass); 97 } catch (BindException $e) { 98 return false; 99 } catch (ConnectionException $e) { 100 $this->fatal($e); 101 return false; 102 } catch (OperationException $e) { 103 $this->fatal($e); 104 return false; 105 } 106 107 $this->isAuthenticated = true; 108 return true; 109 } 110 111 /** 112 * Get info for a single user, use cache if available 113 * 114 * @param string $username 115 * @param bool $fetchgroups Are groups needed? 116 * @return array|null 117 */ 118 public function getCachedUser($username, $fetchgroups = true) 119 { 120 if (isset($this->userCache[$username])) { 121 if (!$fetchgroups || is_array($this->userCache[$username]['grps'])) { 122 return $this->userCache[$username]; 123 } 124 } 125 126 // fetch fresh data 127 $info = $this->getUser($username, $fetchgroups); 128 129 // store in cache 130 if ($info !== null) { 131 $this->userCache[$username] = $info; 132 } 133 134 return $info; 135 } 136 137 /** 138 * Fetch a single user 139 * 140 * @param string $username 141 * @param bool $fetchgroups Shall groups be fetched, too? 142 * @return null|array 143 */ 144 abstract public function getUser($username, $fetchgroups = true); 145 146 /** 147 * Return a list of all available groups, use cache if available 148 * 149 * @return string[] 150 */ 151 public function getCachedGroups() 152 { 153 if (empty($this->groupCache)) { 154 $this->groupCache = $this->getGroups(); 155 } 156 157 return $this->groupCache; 158 } 159 160 /** 161 * Return a list of all available groups 162 * 163 * Optionally filter the list 164 * 165 * @param null|string $match Filter for this, null for all groups 166 * @param string $filtermethod How to match the groups 167 * @return string[] 168 */ 169 abstract public function getGroups($match = null, $filtermethod = 'equal'); 170 171 /** 172 * Helper method to get the first value of the given attribute 173 * 174 * The given attribute may be null, an empty string is returned then 175 * 176 * @param Attribute|null $attribute 177 * @return string 178 */ 179 protected function attr2str($attribute) 180 { 181 if ($attribute !== null) { 182 return $attribute->firstValue(); 183 } 184 return ''; 185 } 186 187 /** 188 * Handle fatal exceptions 189 * 190 * @param \Exception $e 191 */ 192 protected function fatal(\Exception $e) 193 { 194 if (defined('DOKU_UNITTEST')) { 195 throw new \RuntimeException('', 0, $e); 196 } 197 msg('[pureldap] ' . hsc($e->getMessage()) . ' at ' . $e->getFile() . ':' . $e->getLine(), -1); 198 } 199 200 /** 201 * Handle debug output 202 * 203 * @param string $msg 204 * @param string $file 205 * @param int $line 206 */ 207 protected function debug($msg, $file, $line) 208 { 209 msg('[pureldap] ' . hsc($msg) . ' at ' . $file . ':' . $line, 1); 210 } 211} 212