This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | use dokuwiki\Utf8\Sort; |
||
3 | use dokuwiki\Logger; |
||
4 | |||
5 | /** |
||
6 | * Active Directory authentication backend for DokuWiki |
||
7 | * |
||
8 | * This makes authentication with a Active Directory server much easier |
||
9 | * than when using the normal LDAP backend by utilizing the adLDAP library |
||
10 | * |
||
11 | * Usage: |
||
12 | * Set DokuWiki's local.protected.php auth setting to read |
||
13 | * |
||
14 | * $conf['authtype'] = 'authad'; |
||
15 | * |
||
16 | * $conf['plugin']['authad']['account_suffix'] = '@my.domain.org'; |
||
17 | * $conf['plugin']['authad']['base_dn'] = 'DC=my,DC=domain,DC=org'; |
||
18 | * $conf['plugin']['authad']['domain_controllers'] = 'srv1.domain.org,srv2.domain.org'; |
||
19 | * |
||
20 | * //optional: |
||
21 | * $conf['plugin']['authad']['sso'] = 1; |
||
22 | * $conf['plugin']['authad']['admin_username'] = 'root'; |
||
23 | * $conf['plugin']['authad']['admin_password'] = 'pass'; |
||
24 | * $conf['plugin']['authad']['real_primarygroup'] = 1; |
||
25 | * $conf['plugin']['authad']['use_ssl'] = 1; |
||
26 | * $conf['plugin']['authad']['use_tls'] = 1; |
||
27 | * $conf['plugin']['authad']['debug'] = 1; |
||
28 | * // warn user about expiring password this many days in advance: |
||
29 | * $conf['plugin']['authad']['expirywarn'] = 5; |
||
30 | * |
||
31 | * // get additional information to the userinfo array |
||
32 | * // add a list of comma separated ldap contact fields. |
||
33 | * $conf['plugin']['authad']['additional'] = 'field1,field2'; |
||
34 | * |
||
35 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
36 | * @author James Van Lommel <[email protected]> |
||
37 | * @link http://www.nosq.com/blog/2005/08/ldap-activedirectory-and-dokuwiki/ |
||
38 | * @author Andreas Gohr <[email protected]> |
||
39 | * @author Jan Schumann <[email protected]> |
||
40 | */ |
||
41 | class auth_plugin_authad extends DokuWiki_Auth_Plugin |
||
42 | { |
||
43 | |||
44 | /** |
||
45 | * @var array hold connection data for a specific AD domain |
||
46 | */ |
||
47 | protected $opts = array(); |
||
48 | |||
49 | /** |
||
50 | * @var array open connections for each AD domain, as adLDAP objects |
||
51 | */ |
||
52 | protected $adldap = array(); |
||
53 | |||
54 | /** |
||
55 | * @var bool message state |
||
56 | */ |
||
57 | protected $msgshown = false; |
||
58 | |||
59 | /** |
||
60 | * @var array user listing cache |
||
61 | */ |
||
62 | protected $users = array(); |
||
63 | |||
64 | /** |
||
65 | * @var array filter patterns for listing users |
||
66 | */ |
||
67 | protected $pattern = array(); |
||
68 | |||
69 | protected $grpsusers = array(); |
||
70 | |||
71 | /** |
||
72 | * Constructor |
||
73 | */ |
||
74 | public function __construct() |
||
75 | { |
||
76 | global $INPUT; |
||
77 | parent::__construct(); |
||
78 | |||
79 | require_once(DOKU_PLUGIN.'authad/adLDAP/adLDAP.php'); |
||
80 | require_once(DOKU_PLUGIN.'authad/adLDAP/classes/adLDAPUtils.php'); |
||
81 | |||
82 | // we load the config early to modify it a bit here |
||
83 | $this->loadConfig(); |
||
84 | |||
85 | // additional information fields |
||
86 | if (isset($this->conf['additional'])) { |
||
87 | $this->conf['additional'] = str_replace(' ', '', $this->conf['additional']); |
||
88 | $this->conf['additional'] = explode(',', $this->conf['additional']); |
||
89 | } else $this->conf['additional'] = array(); |
||
90 | |||
91 | // ldap extension is needed |
||
92 | if (!function_exists('ldap_connect')) { |
||
93 | if ($this->conf['debug']) |
||
94 | msg("AD Auth: PHP LDAP extension not found.", -1); |
||
95 | $this->success = false; |
||
96 | return; |
||
97 | } |
||
98 | |||
99 | // Prepare SSO |
||
100 | if (!empty($_SERVER['REMOTE_USER'])) { |
||
101 | // make sure the right encoding is used |
||
102 | if ($this->getConf('sso_charset')) { |
||
103 | $_SERVER['REMOTE_USER'] = iconv($this->getConf('sso_charset'), 'UTF-8', $_SERVER['REMOTE_USER']); |
||
104 | } elseif (!\dokuwiki\Utf8\Clean::isUtf8($_SERVER['REMOTE_USER'])) { |
||
105 | $_SERVER['REMOTE_USER'] = utf8_encode($_SERVER['REMOTE_USER']); |
||
106 | } |
||
107 | |||
108 | // trust the incoming user |
||
109 | if ($this->conf['sso']) { |
||
110 | $_SERVER['REMOTE_USER'] = $this->cleanUser($_SERVER['REMOTE_USER']); |
||
111 | |||
112 | // we need to simulate a login |
||
113 | if (empty($_COOKIE[DOKU_COOKIE])) { |
||
114 | $INPUT->set('u', $_SERVER['REMOTE_USER']); |
||
115 | $INPUT->set('p', 'sso_only'); |
||
116 | } |
||
117 | } |
||
118 | } |
||
119 | |||
120 | // other can do's are changed in $this->_loadServerConfig() base on domain setup |
||
121 | $this->cando['modName'] = (bool)$this->conf['update_name']; |
||
122 | $this->cando['modMail'] = (bool)$this->conf['update_mail']; |
||
123 | $this->cando['getUserCount'] = true; |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * Load domain config on capability check |
||
128 | * |
||
129 | * @param string $cap |
||
130 | * @return bool |
||
131 | */ |
||
132 | public function canDo($cap) |
||
133 | { |
||
134 | //capabilities depend on config, which may change depending on domain |
||
135 | $domain = $this->getUserDomain($_SERVER['REMOTE_USER']); |
||
136 | $this->loadServerConfig($domain); |
||
137 | return parent::canDo($cap); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Check user+password [required auth function] |
||
142 | * |
||
143 | * Checks if the given user exists and the given |
||
144 | * plaintext password is correct by trying to bind |
||
145 | * to the LDAP server |
||
146 | * |
||
147 | * @author James Van Lommel <[email protected]> |
||
148 | * @param string $user |
||
149 | * @param string $pass |
||
150 | * @return bool |
||
151 | */ |
||
152 | public function checkPass($user, $pass) |
||
153 | { |
||
154 | if ($_SERVER['REMOTE_USER'] && |
||
155 | $_SERVER['REMOTE_USER'] == $user && |
||
156 | $this->conf['sso'] |
||
157 | ) return true; |
||
158 | |||
159 | $adldap = $this->initAdLdap($this->getUserDomain($user)); |
||
160 | if (!$adldap) return false; |
||
161 | |||
162 | try { |
||
163 | return $adldap->authenticate($this->getUserName($user), $pass); |
||
164 | } catch (adLDAPException $e) { |
||
0 ignored issues
–
show
|
|||
165 | // shouldn't really happen |
||
166 | return false; |
||
167 | } |
||
168 | } |
||
169 | |||
170 | /** |
||
171 | * Return user info [required auth function] |
||
172 | * |
||
173 | * Returns info about the given user needs to contain |
||
174 | * at least these fields: |
||
175 | * |
||
176 | * name string full name of the user |
||
177 | * mail string email address of the user |
||
178 | * grps array list of groups the user is in |
||
179 | * |
||
180 | * This AD specific function returns the following |
||
181 | * addional fields: |
||
182 | * |
||
183 | * dn string distinguished name (DN) |
||
184 | * uid string samaccountname |
||
185 | * lastpwd int timestamp of the date when the password was set |
||
186 | * expires true if the password expires |
||
187 | * expiresin int seconds until the password expires |
||
188 | * any fields specified in the 'additional' config option |
||
189 | * |
||
190 | * @author James Van Lommel <[email protected]> |
||
191 | * @param string $user |
||
192 | * @param bool $requireGroups (optional) - ignored, groups are always supplied by this plugin |
||
193 | * @return array |
||
194 | */ |
||
195 | public function getUserData($user, $requireGroups = true) |
||
196 | { |
||
197 | global $conf; |
||
198 | global $lang; |
||
199 | global $ID; |
||
200 | $adldap = $this->initAdLdap($this->getUserDomain($user)); |
||
201 | if (!$adldap) return array(); |
||
202 | |||
203 | if ($user == '') return array(); |
||
204 | |||
205 | $fields = array('mail', 'displayname', 'samaccountname', 'lastpwd', 'pwdlastset', 'useraccountcontrol'); |
||
206 | |||
207 | // add additional fields to read |
||
208 | $fields = array_merge($fields, $this->conf['additional']); |
||
209 | $fields = array_unique($fields); |
||
210 | $fields = array_filter($fields); |
||
211 | |||
212 | //get info for given user |
||
213 | $result = $adldap->user()->info($this->getUserName($user), $fields); |
||
214 | if ($result == false) { |
||
215 | return array(); |
||
216 | } |
||
217 | |||
218 | //general user info |
||
219 | $info = array(); |
||
220 | $info['name'] = $result[0]['displayname'][0]; |
||
221 | $info['mail'] = $result[0]['mail'][0]; |
||
222 | $info['uid'] = $result[0]['samaccountname'][0]; |
||
223 | $info['dn'] = $result[0]['dn']; |
||
224 | //last password set (Windows counts from January 1st 1601) |
||
225 | $info['lastpwd'] = $result[0]['pwdlastset'][0] / 10000000 - 11644473600; |
||
226 | //will it expire? |
||
227 | $info['expires'] = !($result[0]['useraccountcontrol'][0] & 0x10000); //ADS_UF_DONT_EXPIRE_PASSWD |
||
228 | |||
229 | // additional information |
||
230 | foreach ($this->conf['additional'] as $field) { |
||
231 | if (isset($result[0][strtolower($field)])) { |
||
232 | $info[$field] = $result[0][strtolower($field)][0]; |
||
233 | } |
||
234 | } |
||
235 | |||
236 | // handle ActiveDirectory memberOf |
||
237 | $info['grps'] = $adldap->user()->groups($this->getUserName($user), (bool) $this->opts['recursive_groups']); |
||
238 | |||
239 | if (is_array($info['grps'])) { |
||
240 | foreach ($info['grps'] as $ndx => $group) { |
||
241 | $info['grps'][$ndx] = $this->cleanGroup($group); |
||
242 | } |
||
243 | } |
||
244 | |||
245 | // always add the default group to the list of groups |
||
246 | if (!is_array($info['grps']) || !in_array($conf['defaultgroup'], $info['grps'])) { |
||
247 | $info['grps'][] = $conf['defaultgroup']; |
||
248 | } |
||
249 | |||
250 | // add the user's domain to the groups |
||
251 | $domain = $this->getUserDomain($user); |
||
252 | if ($domain && !in_array("domain-$domain", (array) $info['grps'])) { |
||
253 | $info['grps'][] = $this->cleanGroup("domain-$domain"); |
||
254 | } |
||
255 | |||
256 | // check expiry time |
||
257 | if ($info['expires'] && $this->conf['expirywarn']) { |
||
258 | try { |
||
259 | $expiry = $adldap->user()->passwordExpiry($user); |
||
260 | if (is_array($expiry)) { |
||
261 | $info['expiresat'] = $expiry['expiryts']; |
||
262 | $info['expiresin'] = round(($info['expiresat'] - time())/(24*60*60)); |
||
263 | |||
264 | // if this is the current user, warn him (once per request only) |
||
265 | if (($_SERVER['REMOTE_USER'] == $user) && |
||
266 | ($info['expiresin'] <= $this->conf['expirywarn']) && |
||
267 | !$this->msgshown |
||
268 | ) { |
||
269 | $msg = sprintf($this->getLang('authpwdexpire'), $info['expiresin']); |
||
270 | if ($this->canDo('modPass')) { |
||
271 | $url = wl($ID, array('do'=> 'profile')); |
||
272 | $msg .= ' <a href="'.$url.'">'.$lang['btn_profile'].'</a>'; |
||
273 | } |
||
274 | msg($msg); |
||
275 | $this->msgshown = true; |
||
276 | } |
||
277 | } |
||
278 | } catch (adLDAPException $e) { |
||
0 ignored issues
–
show
The class
adLDAPException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
279 | // ignore. should usually not happen |
||
280 | } |
||
281 | } |
||
282 | |||
283 | return $info; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Make AD group names usable by DokuWiki. |
||
288 | * |
||
289 | * Removes backslashes ('\'), pound signs ('#'), and converts spaces to underscores. |
||
290 | * |
||
291 | * @author James Van Lommel ([email protected]) |
||
292 | * @param string $group |
||
293 | * @return string |
||
294 | */ |
||
295 | public function cleanGroup($group) |
||
296 | { |
||
297 | $group = str_replace('\\', '', $group); |
||
298 | $group = str_replace('#', '', $group); |
||
299 | $group = preg_replace('[\s]', '_', $group); |
||
300 | $group = \dokuwiki\Utf8\PhpString::strtolower(trim($group)); |
||
301 | return $group; |
||
302 | } |
||
303 | |||
304 | /** |
||
305 | * Sanitize user names |
||
306 | * |
||
307 | * Normalizes domain parts, does not modify the user name itself (unlike cleanGroup) |
||
308 | * |
||
309 | * @author Andreas Gohr <[email protected]> |
||
310 | * @param string $user |
||
311 | * @return string |
||
312 | */ |
||
313 | public function cleanUser($user) |
||
314 | { |
||
315 | $domain = ''; |
||
316 | |||
317 | // get NTLM or Kerberos domain part |
||
318 | list($dom, $user) = explode('\\', $user, 2); |
||
319 | if (!$user) $user = $dom; |
||
320 | if ($dom) $domain = $dom; |
||
321 | list($user, $dom) = explode('@', $user, 2); |
||
322 | if ($dom) $domain = $dom; |
||
323 | |||
324 | // clean up both |
||
325 | $domain = \dokuwiki\Utf8\PhpString::strtolower(trim($domain)); |
||
326 | $user = \dokuwiki\Utf8\PhpString::strtolower(trim($user)); |
||
327 | |||
328 | // is this a known, valid domain or do we work without account suffix? if not discard |
||
329 | if (!is_array($this->conf[$domain]) && $this->conf['account_suffix'] !== '') { |
||
330 | $domain = ''; |
||
331 | } |
||
332 | |||
333 | // reattach domain |
||
334 | if ($domain) $user = "$user@$domain"; |
||
335 | return $user; |
||
336 | } |
||
337 | |||
338 | /** |
||
339 | * Most values in LDAP are case-insensitive |
||
340 | * |
||
341 | * @return bool |
||
342 | */ |
||
343 | public function isCaseSensitive() |
||
344 | { |
||
345 | return false; |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * Create a Search-String useable by adLDAPUsers::all($includeDescription = false, $search = "*", $sorted = true) |
||
350 | * |
||
351 | * @param array $filter |
||
352 | * @return string |
||
353 | */ |
||
354 | protected function constructSearchString($filter) |
||
355 | { |
||
356 | if (!$filter) { |
||
0 ignored issues
–
show
The expression
$filter of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
357 | return '*'; |
||
358 | } |
||
359 | $adldapUtils = new adLDAPUtils($this->initAdLdap(null)); |
||
360 | $result = '*'; |
||
361 | if (isset($filter['name'])) { |
||
362 | $result .= ')(displayname=*' . $adldapUtils->ldapSlashes($filter['name']) . '*'; |
||
363 | unset($filter['name']); |
||
364 | } |
||
365 | |||
366 | if (isset($filter['user'])) { |
||
367 | $result .= ')(samAccountName=*' . $adldapUtils->ldapSlashes($filter['user']) . '*'; |
||
368 | unset($filter['user']); |
||
369 | } |
||
370 | |||
371 | if (isset($filter['mail'])) { |
||
372 | $result .= ')(mail=*' . $adldapUtils->ldapSlashes($filter['mail']) . '*'; |
||
373 | unset($filter['mail']); |
||
374 | } |
||
375 | return $result; |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * Return a count of the number of user which meet $filter criteria |
||
380 | * |
||
381 | * @param array $filter $filter array of field/pattern pairs, empty array for no filter |
||
382 | * @return int number of users |
||
383 | */ |
||
384 | public function getUserCount($filter = array()) |
||
385 | { |
||
386 | $adldap = $this->initAdLdap(null); |
||
387 | if (!$adldap) { |
||
388 | Logger::debug("authad/auth.php getUserCount(): _adldap not set."); |
||
389 | return -1; |
||
390 | } |
||
391 | if ($filter == array()) { |
||
392 | $result = $adldap->user()->all(); |
||
393 | } else { |
||
394 | $searchString = $this->constructSearchString($filter); |
||
395 | $result = $adldap->user()->all(false, $searchString); |
||
396 | if (isset($filter['grps'])) { |
||
397 | $this->users = array_fill_keys($result, false); |
||
398 | /** @var admin_plugin_usermanager $usermanager */ |
||
399 | $usermanager = plugin_load("admin", "usermanager", false); |
||
400 | $usermanager->setLastdisabled(true); |
||
401 | if (!isset($this->grpsusers[$this->filterToString($filter)])) { |
||
402 | $this->fillGroupUserArray($filter, $usermanager->getStart() + 3*$usermanager->getPagesize()); |
||
403 | } elseif (count($this->grpsusers[$this->filterToString($filter)]) < |
||
404 | $usermanager->getStart() + 3*$usermanager->getPagesize() |
||
405 | ) { |
||
406 | $this->fillGroupUserArray( |
||
407 | $filter, |
||
408 | $usermanager->getStart() + |
||
409 | 3*$usermanager->getPagesize() - |
||
410 | count($this->grpsusers[$this->filterToString($filter)]) |
||
411 | ); |
||
412 | } |
||
413 | $result = $this->grpsusers[$this->filterToString($filter)]; |
||
414 | } else { |
||
415 | /** @var admin_plugin_usermanager $usermanager */ |
||
416 | $usermanager = plugin_load("admin", "usermanager", false); |
||
417 | $usermanager->setLastdisabled(false); |
||
418 | } |
||
419 | } |
||
420 | |||
421 | if (!$result) { |
||
422 | return 0; |
||
423 | } |
||
424 | return count($result); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * |
||
429 | * create a unique string for each filter used with a group |
||
430 | * |
||
431 | * @param array $filter |
||
432 | * @return string |
||
433 | */ |
||
434 | protected function filterToString($filter) |
||
435 | { |
||
436 | $result = ''; |
||
437 | if (isset($filter['user'])) { |
||
438 | $result .= 'user-' . $filter['user']; |
||
439 | } |
||
440 | if (isset($filter['name'])) { |
||
441 | $result .= 'name-' . $filter['name']; |
||
442 | } |
||
443 | if (isset($filter['mail'])) { |
||
444 | $result .= 'mail-' . $filter['mail']; |
||
445 | } |
||
446 | if (isset($filter['grps'])) { |
||
447 | $result .= 'grps-' . $filter['grps']; |
||
448 | } |
||
449 | return $result; |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * Create an array of $numberOfAdds users passing a certain $filter, including belonging |
||
454 | * to a certain group and save them to a object-wide array. If the array |
||
455 | * already exists try to add $numberOfAdds further users to it. |
||
456 | * |
||
457 | * @param array $filter |
||
458 | * @param int $numberOfAdds additional number of users requested |
||
459 | * @return int number of Users actually add to Array |
||
460 | */ |
||
461 | protected function fillGroupUserArray($filter, $numberOfAdds) |
||
462 | { |
||
463 | if (isset($this->grpsusers[$this->filterToString($filter)])) { |
||
464 | $actualstart = count($this->grpsusers[$this->filterToString($filter)]); |
||
465 | } else { |
||
466 | $this->grpsusers[$this->filterToString($filter)] = []; |
||
467 | $actualstart = 0; |
||
468 | } |
||
469 | |||
470 | $i=0; |
||
471 | $count = 0; |
||
472 | $this->constructPattern($filter); |
||
473 | foreach ($this->users as $user => &$info) { |
||
474 | if ($i++ < $actualstart) { |
||
475 | continue; |
||
476 | } |
||
477 | if ($info === false) { |
||
478 | $info = $this->getUserData($user); |
||
479 | } |
||
480 | if ($this->filter($user, $info)) { |
||
481 | $this->grpsusers[$this->filterToString($filter)][$user] = $info; |
||
482 | if (($numberOfAdds > 0) && (++$count >= $numberOfAdds)) break; |
||
483 | } |
||
484 | } |
||
485 | return $count; |
||
486 | } |
||
487 | |||
488 | /** |
||
489 | * Bulk retrieval of user data |
||
490 | * |
||
491 | * @author Dominik Eckelmann <[email protected]> |
||
492 | * |
||
493 | * @param int $start index of first user to be returned |
||
494 | * @param int $limit max number of users to be returned |
||
495 | * @param array $filter array of field/pattern pairs, null for no filter |
||
496 | * @return array userinfo (refer getUserData for internal userinfo details) |
||
497 | */ |
||
498 | public function retrieveUsers($start = 0, $limit = 0, $filter = array()) |
||
499 | { |
||
500 | $adldap = $this->initAdLdap(null); |
||
501 | if (!$adldap) return array(); |
||
502 | |||
503 | //if (!$this->users) { |
||
504 | //get info for given user |
||
505 | $result = $adldap->user()->all(false, $this->constructSearchString($filter)); |
||
506 | if (!$result) return array(); |
||
507 | $this->users = array_fill_keys($result, false); |
||
508 | //} |
||
509 | |||
510 | $i = 0; |
||
511 | $count = 0; |
||
512 | $result = array(); |
||
513 | |||
514 | if (!isset($filter['grps'])) { |
||
515 | /** @var admin_plugin_usermanager $usermanager */ |
||
516 | $usermanager = plugin_load("admin", "usermanager", false); |
||
517 | $usermanager->setLastdisabled(false); |
||
518 | $this->constructPattern($filter); |
||
519 | foreach ($this->users as $user => &$info) { |
||
520 | if ($i++ < $start) { |
||
521 | continue; |
||
522 | } |
||
523 | if ($info === false) { |
||
524 | $info = $this->getUserData($user); |
||
525 | } |
||
526 | $result[$user] = $info; |
||
527 | if (($limit > 0) && (++$count >= $limit)) break; |
||
528 | } |
||
529 | } else { |
||
530 | /** @var admin_plugin_usermanager $usermanager */ |
||
531 | $usermanager = plugin_load("admin", "usermanager", false); |
||
532 | $usermanager->setLastdisabled(true); |
||
533 | if (!isset($this->grpsusers[$this->filterToString($filter)]) || |
||
534 | count($this->grpsusers[$this->filterToString($filter)]) < ($start+$limit) |
||
535 | ) { |
||
536 | if(!isset($this->grpsusers[$this->filterToString($filter)])) { |
||
537 | $this->grpsusers[$this->filterToString($filter)] = []; |
||
538 | } |
||
539 | |||
540 | $this->fillGroupUserArray( |
||
541 | $filter, |
||
542 | $start+$limit - count($this->grpsusers[$this->filterToString($filter)]) +1 |
||
543 | ); |
||
544 | } |
||
545 | if (!$this->grpsusers[$this->filterToString($filter)]) return array(); |
||
546 | foreach ($this->grpsusers[$this->filterToString($filter)] as $user => &$info) { |
||
547 | if ($i++ < $start) { |
||
548 | continue; |
||
549 | } |
||
550 | $result[$user] = $info; |
||
551 | if (($limit > 0) && (++$count >= $limit)) break; |
||
552 | } |
||
553 | } |
||
554 | return $result; |
||
555 | } |
||
556 | |||
557 | /** |
||
558 | * Modify user data |
||
559 | * |
||
560 | * @param string $user nick of the user to be changed |
||
561 | * @param array $changes array of field/value pairs to be changed |
||
562 | * @return bool |
||
563 | */ |
||
564 | public function modifyUser($user, $changes) |
||
565 | { |
||
566 | $return = true; |
||
567 | $adldap = $this->initAdLdap($this->getUserDomain($user)); |
||
568 | if (!$adldap) { |
||
569 | msg($this->getLang('connectfail'), -1); |
||
570 | return false; |
||
571 | } |
||
572 | |||
573 | // password changing |
||
574 | if (isset($changes['pass'])) { |
||
575 | try { |
||
576 | $return = $adldap->user()->password($this->getUserName($user), $changes['pass']); |
||
577 | } catch (adLDAPException $e) { |
||
0 ignored issues
–
show
The class
adLDAPException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
578 | if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1); |
||
579 | $return = false; |
||
580 | } |
||
581 | if (!$return) msg($this->getLang('passchangefail'), -1); |
||
582 | } |
||
583 | |||
584 | // changing user data |
||
585 | $adchanges = array(); |
||
586 | if (isset($changes['name'])) { |
||
587 | // get first and last name |
||
588 | $parts = explode(' ', $changes['name']); |
||
589 | $adchanges['surname'] = array_pop($parts); |
||
590 | $adchanges['firstname'] = join(' ', $parts); |
||
591 | $adchanges['display_name'] = $changes['name']; |
||
592 | } |
||
593 | if (isset($changes['mail'])) { |
||
594 | $adchanges['email'] = $changes['mail']; |
||
595 | } |
||
596 | if (count($adchanges)) { |
||
597 | try { |
||
598 | $return = $return & $adldap->user()->modify($this->getUserName($user), $adchanges); |
||
599 | } catch (adLDAPException $e) { |
||
0 ignored issues
–
show
The class
adLDAPException does not exist. Did you forget a USE statement, or did you not list all dependencies?
Scrutinizer analyzes your It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis. ![]() |
|||
600 | if ($this->conf['debug']) msg('AD Auth: '.$e->getMessage(), -1); |
||
601 | $return = false; |
||
602 | } |
||
603 | if (!$return) msg($this->getLang('userchangefail'), -1); |
||
604 | } |
||
605 | |||
606 | return $return; |
||
607 | } |
||
608 | |||
609 | /** |
||
610 | * Initialize the AdLDAP library and connect to the server |
||
611 | * |
||
612 | * When you pass null as domain, it will reuse any existing domain. |
||
613 | * Eg. the one of the logged in user. It falls back to the default |
||
614 | * domain if no current one is available. |
||
615 | * |
||
616 | * @param string|null $domain The AD domain to use |
||
617 | * @return adLDAP|bool true if a connection was established |
||
618 | */ |
||
619 | protected function initAdLdap($domain) |
||
620 | { |
||
621 | if (is_null($domain) && is_array($this->opts)) { |
||
622 | $domain = $this->opts['domain']; |
||
623 | } |
||
624 | |||
625 | $this->opts = $this->loadServerConfig((string) $domain); |
||
626 | if (isset($this->adldap[$domain])) return $this->adldap[$domain]; |
||
627 | |||
628 | // connect |
||
629 | try { |
||
630 | $this->adldap[$domain] = new adLDAP($this->opts); |
||
631 | return $this->adldap[$domain]; |
||
632 | } catch (Exception $e) { |
||
633 | if ($this->conf['debug']) { |
||
634 | msg('AD Auth: '.$e->getMessage(), -1); |
||
635 | } |
||
636 | $this->success = false; |
||
637 | $this->adldap[$domain] = null; |
||
638 | } |
||
639 | return false; |
||
640 | } |
||
641 | |||
642 | /** |
||
643 | * Get the domain part from a user |
||
644 | * |
||
645 | * @param string $user |
||
646 | * @return string |
||
647 | */ |
||
648 | public function getUserDomain($user) |
||
649 | { |
||
650 | list(, $domain) = explode('@', $user, 2); |
||
651 | return $domain; |
||
652 | } |
||
653 | |||
654 | /** |
||
655 | * Get the user part from a user |
||
656 | * |
||
657 | * When an account suffix is set, we strip the domain part from the user |
||
658 | * |
||
659 | * @param string $user |
||
660 | * @return string |
||
661 | */ |
||
662 | public function getUserName($user) |
||
663 | { |
||
664 | if ($this->conf['account_suffix'] !== '') { |
||
665 | list($user) = explode('@', $user, 2); |
||
666 | } |
||
667 | return $user; |
||
668 | } |
||
669 | |||
670 | /** |
||
671 | * Fetch the configuration for the given AD domain |
||
672 | * |
||
673 | * @param string $domain current AD domain |
||
674 | * @return array |
||
675 | */ |
||
676 | protected function loadServerConfig($domain) |
||
677 | { |
||
678 | // prepare adLDAP standard configuration |
||
679 | $opts = $this->conf; |
||
680 | |||
681 | $opts['domain'] = $domain; |
||
682 | |||
683 | // add possible domain specific configuration |
||
684 | if ($domain && is_array($this->conf[$domain])) foreach ($this->conf[$domain] as $key => $val) { |
||
685 | $opts[$key] = $val; |
||
686 | } |
||
687 | |||
688 | // handle multiple AD servers |
||
689 | $opts['domain_controllers'] = explode(',', $opts['domain_controllers']); |
||
690 | $opts['domain_controllers'] = array_map('trim', $opts['domain_controllers']); |
||
691 | $opts['domain_controllers'] = array_filter($opts['domain_controllers']); |
||
692 | |||
693 | // compatibility with old option name |
||
694 | if (empty($opts['admin_username']) && !empty($opts['ad_username'])) { |
||
695 | $opts['admin_username'] = $opts['ad_username']; |
||
696 | } |
||
697 | if (empty($opts['admin_password']) && !empty($opts['ad_password'])) { |
||
698 | $opts['admin_password'] = $opts['ad_password']; |
||
699 | } |
||
700 | $opts['admin_password'] = conf_decodeString($opts['admin_password']); // deobfuscate |
||
701 | |||
702 | // we can change the password if SSL is set |
||
703 | if ($opts['use_ssl'] || $opts['use_tls']) { |
||
704 | $this->cando['modPass'] = true; |
||
705 | } else { |
||
706 | $this->cando['modPass'] = false; |
||
707 | } |
||
708 | |||
709 | // adLDAP expects empty user/pass as NULL, we're less strict FS#2781 |
||
710 | if (empty($opts['admin_username'])) $opts['admin_username'] = null; |
||
711 | if (empty($opts['admin_password'])) $opts['admin_password'] = null; |
||
712 | |||
713 | // user listing needs admin priviledges |
||
714 | if (!empty($opts['admin_username']) && !empty($opts['admin_password'])) { |
||
715 | $this->cando['getUsers'] = true; |
||
716 | } else { |
||
717 | $this->cando['getUsers'] = false; |
||
718 | } |
||
719 | |||
720 | return $opts; |
||
721 | } |
||
722 | |||
723 | /** |
||
724 | * Returns a list of configured domains |
||
725 | * |
||
726 | * The default domain has an empty string as key |
||
727 | * |
||
728 | * @return array associative array(key => domain) |
||
729 | */ |
||
730 | public function getConfiguredDomains() |
||
731 | { |
||
732 | $domains = array(); |
||
733 | if (empty($this->conf['account_suffix'])) return $domains; // not configured yet |
||
734 | |||
735 | // add default domain, using the name from account suffix |
||
736 | $domains[''] = ltrim($this->conf['account_suffix'], '@'); |
||
737 | |||
738 | // find additional domains |
||
739 | foreach ($this->conf as $key => $val) { |
||
740 | if (is_array($val) && isset($val['account_suffix'])) { |
||
741 | $domains[$key] = ltrim($val['account_suffix'], '@'); |
||
742 | } |
||
743 | } |
||
744 | Sort::ksort($domains); |
||
745 | |||
746 | return $domains; |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * Check provided user and userinfo for matching patterns |
||
751 | * |
||
752 | * The patterns are set up with $this->_constructPattern() |
||
753 | * |
||
754 | * @author Chris Smith <[email protected]> |
||
755 | * |
||
756 | * @param string $user |
||
757 | * @param array $info |
||
758 | * @return bool |
||
759 | */ |
||
760 | protected function filter($user, $info) |
||
761 | { |
||
762 | foreach ($this->pattern as $item => $pattern) { |
||
763 | if ($item == 'user') { |
||
764 | if (!preg_match($pattern, $user)) return false; |
||
765 | } elseif ($item == 'grps') { |
||
766 | if (!count(preg_grep($pattern, $info['grps']))) return false; |
||
767 | } else { |
||
768 | if (!preg_match($pattern, $info[$item])) return false; |
||
769 | } |
||
770 | } |
||
771 | return true; |
||
772 | } |
||
773 | |||
774 | /** |
||
775 | * Create a pattern for $this->_filter() |
||
776 | * |
||
777 | * @author Chris Smith <[email protected]> |
||
778 | * |
||
779 | * @param array $filter |
||
780 | */ |
||
781 | protected function constructPattern($filter) |
||
782 | { |
||
783 | $this->pattern = array(); |
||
784 | foreach ($filter as $item => $pattern) { |
||
785 | $this->pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters |
||
786 | } |
||
787 | } |
||
788 | } |
||
789 |
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.