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