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 * @return string[] 164 */ 165 abstract public function getGroups(); 166 167 /** 168 * Helper method to get the first value of the given attribute 169 * 170 * The given attribute may be null, an empty string is returned then 171 * 172 * @param Attribute|null $attribute 173 * @return string 174 */ 175 protected function attr2str($attribute) 176 { 177 if ($attribute !== null) { 178 return $attribute->firstValue(); 179 } 180 return ''; 181 } 182 183 /** 184 * Handle fatal exceptions 185 * 186 * @param \Exception $e 187 */ 188 protected function fatal(\Exception $e) 189 { 190 if (defined('DOKU_UNITTEST')) { 191 throw new \RuntimeException('', 0, $e); 192 } 193 msg('[pureldap] ' . hsc($e->getMessage()) . ' at ' . $e->getFile() . ':' . $e->getLine(), -1); 194 } 195 196 /** 197 * Handle debug output 198 * 199 * @param string $msg 200 * @param string $file 201 * @param int $line 202 */ 203 protected function debug($msg, $file, $line) 204 { 205 msg('[pureldap] ' . hsc($msg) . ' at ' . $file . ':' . $line, 1); 206 } 207} 208