1*76ce1169SAndreas Gohr<?php 2*76ce1169SAndreas Gohr/** 3*76ce1169SAndreas Gohr * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY 4*76ce1169SAndreas Gohr * Version 4.0.4 5*76ce1169SAndreas Gohr * 6*76ce1169SAndreas Gohr * PHP Version 5 with SSL and LDAP support 7*76ce1169SAndreas Gohr * 8*76ce1169SAndreas Gohr * Written by Scott Barnett, Richard Hyland 9*76ce1169SAndreas Gohr * email: scott@wiggumworld.com, adldap@richardhyland.com 10*76ce1169SAndreas Gohr * http://adldap.sourceforge.net/ 11*76ce1169SAndreas Gohr * 12*76ce1169SAndreas Gohr * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland 13*76ce1169SAndreas Gohr * 14*76ce1169SAndreas Gohr * We'd appreciate any improvements or additions to be submitted back 15*76ce1169SAndreas Gohr * to benefit the entire community :) 16*76ce1169SAndreas Gohr * 17*76ce1169SAndreas Gohr * This library is free software; you can redistribute it and/or 18*76ce1169SAndreas Gohr * modify it under the terms of the GNU Lesser General Public 19*76ce1169SAndreas Gohr * License as published by the Free Software Foundation; either 20*76ce1169SAndreas Gohr * version 2.1 of the License. 21*76ce1169SAndreas Gohr * 22*76ce1169SAndreas Gohr * This library is distributed in the hope that it will be useful, 23*76ce1169SAndreas Gohr * but WITHOUT ANY WARRANTY; without even the implied warranty of 24*76ce1169SAndreas Gohr * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 25*76ce1169SAndreas Gohr * Lesser General Public License for more details. 26*76ce1169SAndreas Gohr * 27*76ce1169SAndreas Gohr * @category ToolsAndUtilities 28*76ce1169SAndreas Gohr * @package adLDAP 29*76ce1169SAndreas Gohr * @author Scott Barnett, Richard Hyland 30*76ce1169SAndreas Gohr * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland 31*76ce1169SAndreas Gohr * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1 32*76ce1169SAndreas Gohr * @revision $Revision: 169 $ 33*76ce1169SAndreas Gohr * @version 4.0.4 34*76ce1169SAndreas Gohr * @link http://adldap.sourceforge.net/ 35*76ce1169SAndreas Gohr */ 36*76ce1169SAndreas Gohr 37*76ce1169SAndreas Gohr/** 38*76ce1169SAndreas Gohr* Main adLDAP class 39*76ce1169SAndreas Gohr* 40*76ce1169SAndreas Gohr* Can be initialised using $adldap = new adLDAP(); 41*76ce1169SAndreas Gohr* 42*76ce1169SAndreas Gohr* Something to keep in mind is that Active Directory is a permissions 43*76ce1169SAndreas Gohr* based directory. If you bind as a domain user, you can't fetch as 44*76ce1169SAndreas Gohr* much information on other users as you could as a domain admin. 45*76ce1169SAndreas Gohr* 46*76ce1169SAndreas Gohr* Before asking questions, please read the Documentation at 47*76ce1169SAndreas Gohr* http://adldap.sourceforge.net/wiki/doku.php?id=api 48*76ce1169SAndreas Gohr*/ 49*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/collections/adLDAPCollection.php'); 50*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPGroups.php'); 51*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPUsers.php'); 52*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPFolders.php'); 53*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPUtils.php'); 54*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPContacts.php'); 55*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPExchange.php'); 56*76ce1169SAndreas Gohrrequire_once(dirname(__FILE__) . '/classes/adLDAPComputers.php'); 57*76ce1169SAndreas Gohr 58*76ce1169SAndreas Gohrclass adLDAP { 59*76ce1169SAndreas Gohr 60*76ce1169SAndreas Gohr /** 61*76ce1169SAndreas Gohr * Define the different types of account in AD 62*76ce1169SAndreas Gohr */ 63*76ce1169SAndreas Gohr const ADLDAP_NORMAL_ACCOUNT = 805306368; 64*76ce1169SAndreas Gohr const ADLDAP_WORKSTATION_TRUST = 805306369; 65*76ce1169SAndreas Gohr const ADLDAP_INTERDOMAIN_TRUST = 805306370; 66*76ce1169SAndreas Gohr const ADLDAP_SECURITY_GLOBAL_GROUP = 268435456; 67*76ce1169SAndreas Gohr const ADLDAP_DISTRIBUTION_GROUP = 268435457; 68*76ce1169SAndreas Gohr const ADLDAP_SECURITY_LOCAL_GROUP = 536870912; 69*76ce1169SAndreas Gohr const ADLDAP_DISTRIBUTION_LOCAL_GROUP = 536870913; 70*76ce1169SAndreas Gohr const ADLDAP_FOLDER = 'OU'; 71*76ce1169SAndreas Gohr const ADLDAP_CONTAINER = 'CN'; 72*76ce1169SAndreas Gohr 73*76ce1169SAndreas Gohr /** 74*76ce1169SAndreas Gohr * The default port for LDAP non-SSL connections 75*76ce1169SAndreas Gohr */ 76*76ce1169SAndreas Gohr const ADLDAP_LDAP_PORT = '389'; 77*76ce1169SAndreas Gohr /** 78*76ce1169SAndreas Gohr * The default port for LDAPS SSL connections 79*76ce1169SAndreas Gohr */ 80*76ce1169SAndreas Gohr const ADLDAP_LDAPS_PORT = '636'; 81*76ce1169SAndreas Gohr 82*76ce1169SAndreas Gohr /** 83*76ce1169SAndreas Gohr * The account suffix for your domain, can be set when the class is invoked 84*76ce1169SAndreas Gohr * 85*76ce1169SAndreas Gohr * @var string 86*76ce1169SAndreas Gohr */ 87*76ce1169SAndreas Gohr protected $accountSuffix = "@mydomain.local"; 88*76ce1169SAndreas Gohr 89*76ce1169SAndreas Gohr /** 90*76ce1169SAndreas Gohr * The base dn for your domain 91*76ce1169SAndreas Gohr * 92*76ce1169SAndreas Gohr * If this is set to null then adLDAP will attempt to obtain this automatically from the rootDSE 93*76ce1169SAndreas Gohr * 94*76ce1169SAndreas Gohr * @var string 95*76ce1169SAndreas Gohr */ 96*76ce1169SAndreas Gohr protected $baseDn = "DC=mydomain,DC=local"; 97*76ce1169SAndreas Gohr 98*76ce1169SAndreas Gohr /** 99*76ce1169SAndreas Gohr * Port used to talk to the domain controllers. 100*76ce1169SAndreas Gohr * 101*76ce1169SAndreas Gohr * @var int 102*76ce1169SAndreas Gohr */ 103*76ce1169SAndreas Gohr protected $adPort = self::ADLDAP_LDAP_PORT; 104*76ce1169SAndreas Gohr 105*76ce1169SAndreas Gohr /** 106*76ce1169SAndreas Gohr * Array of domain controllers. Specifiy multiple controllers if you 107*76ce1169SAndreas Gohr * would like the class to balance the LDAP queries amongst multiple servers 108*76ce1169SAndreas Gohr * 109*76ce1169SAndreas Gohr * @var array 110*76ce1169SAndreas Gohr */ 111*76ce1169SAndreas Gohr protected $domainControllers = array("dc01.mydomain.local"); 112*76ce1169SAndreas Gohr 113*76ce1169SAndreas Gohr /** 114*76ce1169SAndreas Gohr * Optional account with higher privileges for searching 115*76ce1169SAndreas Gohr * This should be set to a domain admin account 116*76ce1169SAndreas Gohr * 117*76ce1169SAndreas Gohr * @var string 118*76ce1169SAndreas Gohr * @var string 119*76ce1169SAndreas Gohr */ 120*76ce1169SAndreas Gohr protected $adminUsername = NULL; 121*76ce1169SAndreas Gohr protected $adminPassword = NULL; 122*76ce1169SAndreas Gohr 123*76ce1169SAndreas Gohr /** 124*76ce1169SAndreas Gohr * AD does not return the primary group. http://support.microsoft.com/?kbid=321360 125*76ce1169SAndreas Gohr * This tweak will resolve the real primary group. 126*76ce1169SAndreas Gohr * Setting to false will fudge "Domain Users" and is much faster. Keep in mind though that if 127*76ce1169SAndreas Gohr * someone's primary group is NOT domain users, this is obviously going to mess up the results 128*76ce1169SAndreas Gohr * 129*76ce1169SAndreas Gohr * @var bool 130*76ce1169SAndreas Gohr */ 131*76ce1169SAndreas Gohr protected $realPrimaryGroup = true; 132*76ce1169SAndreas Gohr 133*76ce1169SAndreas Gohr /** 134*76ce1169SAndreas Gohr * Use SSL (LDAPS), your server needs to be setup, please see 135*76ce1169SAndreas Gohr * http://adldap.sourceforge.net/wiki/doku.php?id=ldap_over_ssl 136*76ce1169SAndreas Gohr * 137*76ce1169SAndreas Gohr * @var bool 138*76ce1169SAndreas Gohr */ 139*76ce1169SAndreas Gohr protected $useSSL = false; 140*76ce1169SAndreas Gohr 141*76ce1169SAndreas Gohr /** 142*76ce1169SAndreas Gohr * Use TLS 143*76ce1169SAndreas Gohr * If you wish to use TLS you should ensure that $useSSL is set to false and vice-versa 144*76ce1169SAndreas Gohr * 145*76ce1169SAndreas Gohr * @var bool 146*76ce1169SAndreas Gohr */ 147*76ce1169SAndreas Gohr protected $useTLS = false; 148*76ce1169SAndreas Gohr 149*76ce1169SAndreas Gohr /** 150*76ce1169SAndreas Gohr * Use SSO 151*76ce1169SAndreas Gohr * To indicate to adLDAP to reuse password set by the brower through NTLM or Kerberos 152*76ce1169SAndreas Gohr * 153*76ce1169SAndreas Gohr * @var bool 154*76ce1169SAndreas Gohr */ 155*76ce1169SAndreas Gohr protected $useSSO = false; 156*76ce1169SAndreas Gohr 157*76ce1169SAndreas Gohr /** 158*76ce1169SAndreas Gohr * When querying group memberships, do it recursively 159*76ce1169SAndreas Gohr * eg. User Fred is a member of Group A, which is a member of Group B, which is a member of Group C 160*76ce1169SAndreas Gohr * user_ingroup("Fred","C") will returns true with this option turned on, false if turned off 161*76ce1169SAndreas Gohr * 162*76ce1169SAndreas Gohr * @var bool 163*76ce1169SAndreas Gohr */ 164*76ce1169SAndreas Gohr protected $recursiveGroups = true; 165*76ce1169SAndreas Gohr 166*76ce1169SAndreas Gohr // You should not need to edit anything below this line 167*76ce1169SAndreas Gohr //****************************************************************************************** 168*76ce1169SAndreas Gohr 169*76ce1169SAndreas Gohr /** 170*76ce1169SAndreas Gohr * Connection and bind default variables 171*76ce1169SAndreas Gohr * 172*76ce1169SAndreas Gohr * @var mixed 173*76ce1169SAndreas Gohr * @var mixed 174*76ce1169SAndreas Gohr */ 175*76ce1169SAndreas Gohr protected $ldapConnection; 176*76ce1169SAndreas Gohr protected $ldapBind; 177*76ce1169SAndreas Gohr 178*76ce1169SAndreas Gohr /** 179*76ce1169SAndreas Gohr * Get the active LDAP Connection 180*76ce1169SAndreas Gohr * 181*76ce1169SAndreas Gohr * @return resource 182*76ce1169SAndreas Gohr */ 183*76ce1169SAndreas Gohr public function getLdapConnection() { 184*76ce1169SAndreas Gohr if ($this->ldapConnection) { 185*76ce1169SAndreas Gohr return $this->ldapConnection; 186*76ce1169SAndreas Gohr } 187*76ce1169SAndreas Gohr return false; 188*76ce1169SAndreas Gohr } 189*76ce1169SAndreas Gohr 190*76ce1169SAndreas Gohr /** 191*76ce1169SAndreas Gohr * Get the bind status 192*76ce1169SAndreas Gohr * 193*76ce1169SAndreas Gohr * @return bool 194*76ce1169SAndreas Gohr */ 195*76ce1169SAndreas Gohr public function getLdapBind() { 196*76ce1169SAndreas Gohr return $this->ldapBind; 197*76ce1169SAndreas Gohr } 198*76ce1169SAndreas Gohr 199*76ce1169SAndreas Gohr /** 200*76ce1169SAndreas Gohr * Get the current base DN 201*76ce1169SAndreas Gohr * 202*76ce1169SAndreas Gohr * @return string 203*76ce1169SAndreas Gohr */ 204*76ce1169SAndreas Gohr public function getBaseDn() { 205*76ce1169SAndreas Gohr return $this->baseDn; 206*76ce1169SAndreas Gohr } 207*76ce1169SAndreas Gohr 208*76ce1169SAndreas Gohr /** 209*76ce1169SAndreas Gohr * The group class 210*76ce1169SAndreas Gohr * 211*76ce1169SAndreas Gohr * @var adLDAPGroups 212*76ce1169SAndreas Gohr */ 213*76ce1169SAndreas Gohr protected $groupClass; 214*76ce1169SAndreas Gohr 215*76ce1169SAndreas Gohr /** 216*76ce1169SAndreas Gohr * Get the group class interface 217*76ce1169SAndreas Gohr * 218*76ce1169SAndreas Gohr * @return adLDAPGroups 219*76ce1169SAndreas Gohr */ 220*76ce1169SAndreas Gohr public function group() { 221*76ce1169SAndreas Gohr if (!$this->groupClass) { 222*76ce1169SAndreas Gohr $this->groupClass = new adLDAPGroups($this); 223*76ce1169SAndreas Gohr } 224*76ce1169SAndreas Gohr return $this->groupClass; 225*76ce1169SAndreas Gohr } 226*76ce1169SAndreas Gohr 227*76ce1169SAndreas Gohr /** 228*76ce1169SAndreas Gohr * The user class 229*76ce1169SAndreas Gohr * 230*76ce1169SAndreas Gohr * @var adLDAPUsers 231*76ce1169SAndreas Gohr */ 232*76ce1169SAndreas Gohr protected $userClass; 233*76ce1169SAndreas Gohr 234*76ce1169SAndreas Gohr /** 235*76ce1169SAndreas Gohr * Get the userclass interface 236*76ce1169SAndreas Gohr * 237*76ce1169SAndreas Gohr * @return adLDAPUsers 238*76ce1169SAndreas Gohr */ 239*76ce1169SAndreas Gohr public function user() { 240*76ce1169SAndreas Gohr if (!$this->userClass) { 241*76ce1169SAndreas Gohr $this->userClass = new adLDAPUsers($this); 242*76ce1169SAndreas Gohr } 243*76ce1169SAndreas Gohr return $this->userClass; 244*76ce1169SAndreas Gohr } 245*76ce1169SAndreas Gohr 246*76ce1169SAndreas Gohr /** 247*76ce1169SAndreas Gohr * The folders class 248*76ce1169SAndreas Gohr * 249*76ce1169SAndreas Gohr * @var adLDAPFolders 250*76ce1169SAndreas Gohr */ 251*76ce1169SAndreas Gohr protected $folderClass; 252*76ce1169SAndreas Gohr 253*76ce1169SAndreas Gohr /** 254*76ce1169SAndreas Gohr * Get the folder class interface 255*76ce1169SAndreas Gohr * 256*76ce1169SAndreas Gohr * @return adLDAPFolders 257*76ce1169SAndreas Gohr */ 258*76ce1169SAndreas Gohr public function folder() { 259*76ce1169SAndreas Gohr if (!$this->folderClass) { 260*76ce1169SAndreas Gohr $this->folderClass = new adLDAPFolders($this); 261*76ce1169SAndreas Gohr } 262*76ce1169SAndreas Gohr return $this->folderClass; 263*76ce1169SAndreas Gohr } 264*76ce1169SAndreas Gohr 265*76ce1169SAndreas Gohr /** 266*76ce1169SAndreas Gohr * The utils class 267*76ce1169SAndreas Gohr * 268*76ce1169SAndreas Gohr * @var adLDAPUtils 269*76ce1169SAndreas Gohr */ 270*76ce1169SAndreas Gohr protected $utilClass; 271*76ce1169SAndreas Gohr 272*76ce1169SAndreas Gohr /** 273*76ce1169SAndreas Gohr * Get the utils class interface 274*76ce1169SAndreas Gohr * 275*76ce1169SAndreas Gohr * @return adLDAPUtils 276*76ce1169SAndreas Gohr */ 277*76ce1169SAndreas Gohr public function utilities() { 278*76ce1169SAndreas Gohr if (!$this->utilClass) { 279*76ce1169SAndreas Gohr $this->utilClass = new adLDAPUtils($this); 280*76ce1169SAndreas Gohr } 281*76ce1169SAndreas Gohr return $this->utilClass; 282*76ce1169SAndreas Gohr } 283*76ce1169SAndreas Gohr 284*76ce1169SAndreas Gohr /** 285*76ce1169SAndreas Gohr * The contacts class 286*76ce1169SAndreas Gohr * 287*76ce1169SAndreas Gohr * @var adLDAPContacts 288*76ce1169SAndreas Gohr */ 289*76ce1169SAndreas Gohr protected $contactClass; 290*76ce1169SAndreas Gohr 291*76ce1169SAndreas Gohr /** 292*76ce1169SAndreas Gohr * Get the contacts class interface 293*76ce1169SAndreas Gohr * 294*76ce1169SAndreas Gohr * @return adLDAPContacts 295*76ce1169SAndreas Gohr */ 296*76ce1169SAndreas Gohr public function contact() { 297*76ce1169SAndreas Gohr if (!$this->contactClass) { 298*76ce1169SAndreas Gohr $this->contactClass = new adLDAPContacts($this); 299*76ce1169SAndreas Gohr } 300*76ce1169SAndreas Gohr return $this->contactClass; 301*76ce1169SAndreas Gohr } 302*76ce1169SAndreas Gohr 303*76ce1169SAndreas Gohr /** 304*76ce1169SAndreas Gohr * The exchange class 305*76ce1169SAndreas Gohr * 306*76ce1169SAndreas Gohr * @var adLDAPExchange 307*76ce1169SAndreas Gohr */ 308*76ce1169SAndreas Gohr protected $exchangeClass; 309*76ce1169SAndreas Gohr 310*76ce1169SAndreas Gohr /** 311*76ce1169SAndreas Gohr * Get the exchange class interface 312*76ce1169SAndreas Gohr * 313*76ce1169SAndreas Gohr * @return adLDAPExchange 314*76ce1169SAndreas Gohr */ 315*76ce1169SAndreas Gohr public function exchange() { 316*76ce1169SAndreas Gohr if (!$this->exchangeClass) { 317*76ce1169SAndreas Gohr $this->exchangeClass = new adLDAPExchange($this); 318*76ce1169SAndreas Gohr } 319*76ce1169SAndreas Gohr return $this->exchangeClass; 320*76ce1169SAndreas Gohr } 321*76ce1169SAndreas Gohr 322*76ce1169SAndreas Gohr /** 323*76ce1169SAndreas Gohr * The computers class 324*76ce1169SAndreas Gohr * 325*76ce1169SAndreas Gohr * @var adLDAPComputers 326*76ce1169SAndreas Gohr */ 327*76ce1169SAndreas Gohr protected $computersClass; 328*76ce1169SAndreas Gohr 329*76ce1169SAndreas Gohr /** 330*76ce1169SAndreas Gohr * Get the computers class interface 331*76ce1169SAndreas Gohr * 332*76ce1169SAndreas Gohr * @return adLDAPComputers 333*76ce1169SAndreas Gohr */ 334*76ce1169SAndreas Gohr public function computer() { 335*76ce1169SAndreas Gohr if (!$this->computerClass) { 336*76ce1169SAndreas Gohr $this->computerClass = new adLDAPComputers($this); 337*76ce1169SAndreas Gohr } 338*76ce1169SAndreas Gohr return $this->computerClass; 339*76ce1169SAndreas Gohr } 340*76ce1169SAndreas Gohr 341*76ce1169SAndreas Gohr /** 342*76ce1169SAndreas Gohr * Getters and Setters 343*76ce1169SAndreas Gohr */ 344*76ce1169SAndreas Gohr 345*76ce1169SAndreas Gohr /** 346*76ce1169SAndreas Gohr * Set the account suffix 347*76ce1169SAndreas Gohr * 348*76ce1169SAndreas Gohr * @param string $accountSuffix 349*76ce1169SAndreas Gohr * @return void 350*76ce1169SAndreas Gohr */ 351*76ce1169SAndreas Gohr public function setAccountSuffix($accountSuffix) 352*76ce1169SAndreas Gohr { 353*76ce1169SAndreas Gohr $this->accountSuffix = $accountSuffix; 354*76ce1169SAndreas Gohr } 355*76ce1169SAndreas Gohr 356*76ce1169SAndreas Gohr /** 357*76ce1169SAndreas Gohr * Get the account suffix 358*76ce1169SAndreas Gohr * 359*76ce1169SAndreas Gohr * @return string 360*76ce1169SAndreas Gohr */ 361*76ce1169SAndreas Gohr public function getAccountSuffix() 362*76ce1169SAndreas Gohr { 363*76ce1169SAndreas Gohr return $this->accountSuffix; 364*76ce1169SAndreas Gohr } 365*76ce1169SAndreas Gohr 366*76ce1169SAndreas Gohr /** 367*76ce1169SAndreas Gohr * Set the domain controllers array 368*76ce1169SAndreas Gohr * 369*76ce1169SAndreas Gohr * @param array $domainControllers 370*76ce1169SAndreas Gohr * @return void 371*76ce1169SAndreas Gohr */ 372*76ce1169SAndreas Gohr public function setDomainControllers(array $domainControllers) 373*76ce1169SAndreas Gohr { 374*76ce1169SAndreas Gohr $this->domainControllers = $domainControllers; 375*76ce1169SAndreas Gohr } 376*76ce1169SAndreas Gohr 377*76ce1169SAndreas Gohr /** 378*76ce1169SAndreas Gohr * Get the list of domain controllers 379*76ce1169SAndreas Gohr * 380*76ce1169SAndreas Gohr * @return void 381*76ce1169SAndreas Gohr */ 382*76ce1169SAndreas Gohr public function getDomainControllers() 383*76ce1169SAndreas Gohr { 384*76ce1169SAndreas Gohr return $this->domainControllers; 385*76ce1169SAndreas Gohr } 386*76ce1169SAndreas Gohr 387*76ce1169SAndreas Gohr /** 388*76ce1169SAndreas Gohr * Sets the port number your domain controller communicates over 389*76ce1169SAndreas Gohr * 390*76ce1169SAndreas Gohr * @param int $adPort 391*76ce1169SAndreas Gohr */ 392*76ce1169SAndreas Gohr public function setPort($adPort) 393*76ce1169SAndreas Gohr { 394*76ce1169SAndreas Gohr $this->adPort = $adPort; 395*76ce1169SAndreas Gohr } 396*76ce1169SAndreas Gohr 397*76ce1169SAndreas Gohr /** 398*76ce1169SAndreas Gohr * Gets the port number your domain controller communicates over 399*76ce1169SAndreas Gohr * 400*76ce1169SAndreas Gohr * @return int 401*76ce1169SAndreas Gohr */ 402*76ce1169SAndreas Gohr public function getPort() 403*76ce1169SAndreas Gohr { 404*76ce1169SAndreas Gohr return $this->adPort; 405*76ce1169SAndreas Gohr } 406*76ce1169SAndreas Gohr 407*76ce1169SAndreas Gohr /** 408*76ce1169SAndreas Gohr * Set the username of an account with higher priviledges 409*76ce1169SAndreas Gohr * 410*76ce1169SAndreas Gohr * @param string $adminUsername 411*76ce1169SAndreas Gohr * @return void 412*76ce1169SAndreas Gohr */ 413*76ce1169SAndreas Gohr public function setAdminUsername($adminUsername) 414*76ce1169SAndreas Gohr { 415*76ce1169SAndreas Gohr $this->adminUsername = $adminUsername; 416*76ce1169SAndreas Gohr } 417*76ce1169SAndreas Gohr 418*76ce1169SAndreas Gohr /** 419*76ce1169SAndreas Gohr * Get the username of the account with higher priviledges 420*76ce1169SAndreas Gohr * 421*76ce1169SAndreas Gohr * This will throw an exception for security reasons 422*76ce1169SAndreas Gohr */ 423*76ce1169SAndreas Gohr public function getAdminUsername() 424*76ce1169SAndreas Gohr { 425*76ce1169SAndreas Gohr throw new adLDAPException('For security reasons you cannot access the domain administrator account details'); 426*76ce1169SAndreas Gohr } 427*76ce1169SAndreas Gohr 428*76ce1169SAndreas Gohr /** 429*76ce1169SAndreas Gohr * Set the password of an account with higher priviledges 430*76ce1169SAndreas Gohr * 431*76ce1169SAndreas Gohr * @param string $adminPassword 432*76ce1169SAndreas Gohr * @return void 433*76ce1169SAndreas Gohr */ 434*76ce1169SAndreas Gohr public function setAdminPassword($adminPassword) 435*76ce1169SAndreas Gohr { 436*76ce1169SAndreas Gohr $this->adminPassword = $adminPassword; 437*76ce1169SAndreas Gohr } 438*76ce1169SAndreas Gohr 439*76ce1169SAndreas Gohr /** 440*76ce1169SAndreas Gohr * Get the password of the account with higher priviledges 441*76ce1169SAndreas Gohr * 442*76ce1169SAndreas Gohr * This will throw an exception for security reasons 443*76ce1169SAndreas Gohr */ 444*76ce1169SAndreas Gohr public function getAdminPassword() 445*76ce1169SAndreas Gohr { 446*76ce1169SAndreas Gohr throw new adLDAPException('For security reasons you cannot access the domain administrator account details'); 447*76ce1169SAndreas Gohr } 448*76ce1169SAndreas Gohr 449*76ce1169SAndreas Gohr /** 450*76ce1169SAndreas Gohr * Set whether to detect the true primary group 451*76ce1169SAndreas Gohr * 452*76ce1169SAndreas Gohr * @param bool $realPrimaryGroup 453*76ce1169SAndreas Gohr * @return void 454*76ce1169SAndreas Gohr */ 455*76ce1169SAndreas Gohr public function setRealPrimaryGroup($realPrimaryGroup) 456*76ce1169SAndreas Gohr { 457*76ce1169SAndreas Gohr $this->realPrimaryGroup = $realPrimaryGroup; 458*76ce1169SAndreas Gohr } 459*76ce1169SAndreas Gohr 460*76ce1169SAndreas Gohr /** 461*76ce1169SAndreas Gohr * Get the real primary group setting 462*76ce1169SAndreas Gohr * 463*76ce1169SAndreas Gohr * @return bool 464*76ce1169SAndreas Gohr */ 465*76ce1169SAndreas Gohr public function getRealPrimaryGroup() 466*76ce1169SAndreas Gohr { 467*76ce1169SAndreas Gohr return $this->realPrimaryGroup; 468*76ce1169SAndreas Gohr } 469*76ce1169SAndreas Gohr 470*76ce1169SAndreas Gohr /** 471*76ce1169SAndreas Gohr * Set whether to use SSL 472*76ce1169SAndreas Gohr * 473*76ce1169SAndreas Gohr * @param bool $useSSL 474*76ce1169SAndreas Gohr * @return void 475*76ce1169SAndreas Gohr */ 476*76ce1169SAndreas Gohr public function setUseSSL($useSSL) 477*76ce1169SAndreas Gohr { 478*76ce1169SAndreas Gohr $this->useSSL = $useSSL; 479*76ce1169SAndreas Gohr // Set the default port correctly 480*76ce1169SAndreas Gohr if($this->useSSL) { 481*76ce1169SAndreas Gohr $this->setPort(self::ADLDAP_LDAPS_PORT); 482*76ce1169SAndreas Gohr } 483*76ce1169SAndreas Gohr else { 484*76ce1169SAndreas Gohr $this->setPort(self::ADLDAP_LDAP_PORT); 485*76ce1169SAndreas Gohr } 486*76ce1169SAndreas Gohr } 487*76ce1169SAndreas Gohr 488*76ce1169SAndreas Gohr /** 489*76ce1169SAndreas Gohr * Get the SSL setting 490*76ce1169SAndreas Gohr * 491*76ce1169SAndreas Gohr * @return bool 492*76ce1169SAndreas Gohr */ 493*76ce1169SAndreas Gohr public function getUseSSL() 494*76ce1169SAndreas Gohr { 495*76ce1169SAndreas Gohr return $this->useSSL; 496*76ce1169SAndreas Gohr } 497*76ce1169SAndreas Gohr 498*76ce1169SAndreas Gohr /** 499*76ce1169SAndreas Gohr * Set whether to use TLS 500*76ce1169SAndreas Gohr * 501*76ce1169SAndreas Gohr * @param bool $useTLS 502*76ce1169SAndreas Gohr * @return void 503*76ce1169SAndreas Gohr */ 504*76ce1169SAndreas Gohr public function setUseTLS($useTLS) 505*76ce1169SAndreas Gohr { 506*76ce1169SAndreas Gohr $this->useTLS = $useTLS; 507*76ce1169SAndreas Gohr } 508*76ce1169SAndreas Gohr 509*76ce1169SAndreas Gohr /** 510*76ce1169SAndreas Gohr * Get the TLS setting 511*76ce1169SAndreas Gohr * 512*76ce1169SAndreas Gohr * @return bool 513*76ce1169SAndreas Gohr */ 514*76ce1169SAndreas Gohr public function getUseTLS() 515*76ce1169SAndreas Gohr { 516*76ce1169SAndreas Gohr return $this->useTLS; 517*76ce1169SAndreas Gohr } 518*76ce1169SAndreas Gohr 519*76ce1169SAndreas Gohr /** 520*76ce1169SAndreas Gohr * Set whether to use SSO 521*76ce1169SAndreas Gohr * Requires ldap_sasl_bind support. Be sure --with-ldap-sasl is used when configuring PHP otherwise this function will be undefined. 522*76ce1169SAndreas Gohr * 523*76ce1169SAndreas Gohr * @param bool $useSSO 524*76ce1169SAndreas Gohr * @return void 525*76ce1169SAndreas Gohr */ 526*76ce1169SAndreas Gohr public function setUseSSO($useSSO) 527*76ce1169SAndreas Gohr { 528*76ce1169SAndreas Gohr if ($useSSO === true && !$this->ldapSaslSupported()) { 529*76ce1169SAndreas Gohr throw new adLDAPException('No LDAP SASL support for PHP. See: http://www.php.net/ldap_sasl_bind'); 530*76ce1169SAndreas Gohr } 531*76ce1169SAndreas Gohr $this->useSSO = $useSSO; 532*76ce1169SAndreas Gohr } 533*76ce1169SAndreas Gohr 534*76ce1169SAndreas Gohr /** 535*76ce1169SAndreas Gohr * Get the SSO setting 536*76ce1169SAndreas Gohr * 537*76ce1169SAndreas Gohr * @return bool 538*76ce1169SAndreas Gohr */ 539*76ce1169SAndreas Gohr public function getUseSSO() 540*76ce1169SAndreas Gohr { 541*76ce1169SAndreas Gohr return $this->useSSO; 542*76ce1169SAndreas Gohr } 543*76ce1169SAndreas Gohr 544*76ce1169SAndreas Gohr /** 545*76ce1169SAndreas Gohr * Set whether to lookup recursive groups 546*76ce1169SAndreas Gohr * 547*76ce1169SAndreas Gohr * @param bool $recursiveGroups 548*76ce1169SAndreas Gohr * @return void 549*76ce1169SAndreas Gohr */ 550*76ce1169SAndreas Gohr public function setRecursiveGroups($recursiveGroups) 551*76ce1169SAndreas Gohr { 552*76ce1169SAndreas Gohr $this->recursiveGroups = $recursiveGroups; 553*76ce1169SAndreas Gohr } 554*76ce1169SAndreas Gohr 555*76ce1169SAndreas Gohr /** 556*76ce1169SAndreas Gohr * Get the recursive groups setting 557*76ce1169SAndreas Gohr * 558*76ce1169SAndreas Gohr * @return bool 559*76ce1169SAndreas Gohr */ 560*76ce1169SAndreas Gohr public function getRecursiveGroups() 561*76ce1169SAndreas Gohr { 562*76ce1169SAndreas Gohr return $this->recursiveGroups; 563*76ce1169SAndreas Gohr } 564*76ce1169SAndreas Gohr 565*76ce1169SAndreas Gohr /** 566*76ce1169SAndreas Gohr * Default Constructor 567*76ce1169SAndreas Gohr * 568*76ce1169SAndreas Gohr * Tries to bind to the AD domain over LDAP or LDAPs 569*76ce1169SAndreas Gohr * 570*76ce1169SAndreas Gohr * @param array $options Array of options to pass to the constructor 571*76ce1169SAndreas Gohr * @throws Exception - if unable to bind to Domain Controller 572*76ce1169SAndreas Gohr * @return bool 573*76ce1169SAndreas Gohr */ 574*76ce1169SAndreas Gohr function __construct($options = array()) { 575*76ce1169SAndreas Gohr // You can specifically overide any of the default configuration options setup above 576*76ce1169SAndreas Gohr if (count($options) > 0) { 577*76ce1169SAndreas Gohr if (array_key_exists("account_suffix",$options)){ $this->accountSuffix = $options["account_suffix"]; } 578*76ce1169SAndreas Gohr if (array_key_exists("base_dn",$options)){ $this->baseDn = $options["base_dn"]; } 579*76ce1169SAndreas Gohr if (array_key_exists("domain_controllers",$options)){ 580*76ce1169SAndreas Gohr if (!is_array($options["domain_controllers"])) { 581*76ce1169SAndreas Gohr throw new adLDAPException('[domain_controllers] option must be an array'); 582*76ce1169SAndreas Gohr } 583*76ce1169SAndreas Gohr $this->domainControllers = $options["domain_controllers"]; 584*76ce1169SAndreas Gohr } 585*76ce1169SAndreas Gohr if (array_key_exists("admin_username",$options)){ $this->adminUsername = $options["admin_username"]; } 586*76ce1169SAndreas Gohr if (array_key_exists("admin_password",$options)){ $this->adminPassword = $options["admin_password"]; } 587*76ce1169SAndreas Gohr if (array_key_exists("real_primarygroup",$options)){ $this->realPrimaryGroup = $options["real_primarygroup"]; } 588*76ce1169SAndreas Gohr if (array_key_exists("use_ssl",$options)){ $this->setUseSSL($options["use_ssl"]); } 589*76ce1169SAndreas Gohr if (array_key_exists("use_tls",$options)){ $this->useTLS = $options["use_tls"]; } 590*76ce1169SAndreas Gohr if (array_key_exists("recursive_groups",$options)){ $this->recursiveGroups = $options["recursive_groups"]; } 591*76ce1169SAndreas Gohr if (array_key_exists("ad_port",$options)){ $this->setPort($options["ad_port"]); } 592*76ce1169SAndreas Gohr if (array_key_exists("sso",$options)) { 593*76ce1169SAndreas Gohr $this->setUseSSO($options["sso"]); 594*76ce1169SAndreas Gohr if (!$this->ldapSaslSupported()) { 595*76ce1169SAndreas Gohr $this->setUseSSO(false); 596*76ce1169SAndreas Gohr } 597*76ce1169SAndreas Gohr } 598*76ce1169SAndreas Gohr } 599*76ce1169SAndreas Gohr 600*76ce1169SAndreas Gohr if ($this->ldapSupported() === false) { 601*76ce1169SAndreas Gohr throw new adLDAPException('No LDAP support for PHP. See: http://www.php.net/ldap'); 602*76ce1169SAndreas Gohr } 603*76ce1169SAndreas Gohr 604*76ce1169SAndreas Gohr return $this->connect(); 605*76ce1169SAndreas Gohr } 606*76ce1169SAndreas Gohr 607*76ce1169SAndreas Gohr /** 608*76ce1169SAndreas Gohr * Default Destructor 609*76ce1169SAndreas Gohr * 610*76ce1169SAndreas Gohr * Closes the LDAP connection 611*76ce1169SAndreas Gohr * 612*76ce1169SAndreas Gohr * @return void 613*76ce1169SAndreas Gohr */ 614*76ce1169SAndreas Gohr function __destruct() { 615*76ce1169SAndreas Gohr $this->close(); 616*76ce1169SAndreas Gohr } 617*76ce1169SAndreas Gohr 618*76ce1169SAndreas Gohr /** 619*76ce1169SAndreas Gohr * Connects and Binds to the Domain Controller 620*76ce1169SAndreas Gohr * 621*76ce1169SAndreas Gohr * @return bool 622*76ce1169SAndreas Gohr */ 623*76ce1169SAndreas Gohr public function connect() 624*76ce1169SAndreas Gohr { 625*76ce1169SAndreas Gohr // Connect to the AD/LDAP server as the username/password 626*76ce1169SAndreas Gohr $domainController = $this->randomController(); 627*76ce1169SAndreas Gohr if ($this->useSSL) { 628*76ce1169SAndreas Gohr $this->ldapConnection = ldap_connect("ldaps://" . $domainController, $this->adPort); 629*76ce1169SAndreas Gohr } else { 630*76ce1169SAndreas Gohr $this->ldapConnection = ldap_connect($domainController, $this->adPort); 631*76ce1169SAndreas Gohr } 632*76ce1169SAndreas Gohr 633*76ce1169SAndreas Gohr // Set some ldap options for talking to AD 634*76ce1169SAndreas Gohr ldap_set_option($this->ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); 635*76ce1169SAndreas Gohr ldap_set_option($this->ldapConnection, LDAP_OPT_REFERRALS, 0); 636*76ce1169SAndreas Gohr 637*76ce1169SAndreas Gohr if ($this->useTLS) { 638*76ce1169SAndreas Gohr ldap_start_tls($this->ldapConnection); 639*76ce1169SAndreas Gohr } 640*76ce1169SAndreas Gohr 641*76ce1169SAndreas Gohr // Bind as a domain admin if they've set it up 642*76ce1169SAndreas Gohr if ($this->adminUsername !== NULL && $this->adminPassword !== NULL) { 643*76ce1169SAndreas Gohr $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix, $this->adminPassword); 644*76ce1169SAndreas Gohr if (!$this->ldapBind) { 645*76ce1169SAndreas Gohr if ($this->useSSL && !$this->useTLS) { 646*76ce1169SAndreas Gohr // If you have problems troubleshooting, remove the @ character from the ldapldapBind command above to get the actual error message 647*76ce1169SAndreas Gohr throw new adLDAPException('Bind to Active Directory failed. Either the LDAPs connection failed or the login credentials are incorrect. AD said: ' . $this->getLastError()); 648*76ce1169SAndreas Gohr } 649*76ce1169SAndreas Gohr else { 650*76ce1169SAndreas Gohr throw new adLDAPException('Bind to Active Directory failed. Check the login credentials and/or server details. AD said: ' . $this->getLastError()); 651*76ce1169SAndreas Gohr } 652*76ce1169SAndreas Gohr } 653*76ce1169SAndreas Gohr } 654*76ce1169SAndreas Gohr if ($this->useSSO && $_SERVER['REMOTE_USER'] && $this->adminUsername === null && $_SERVER['KRB5CCNAME']) { 655*76ce1169SAndreas Gohr putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']); 656*76ce1169SAndreas Gohr $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 657*76ce1169SAndreas Gohr if (!$this->ldapBind){ 658*76ce1169SAndreas Gohr throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 659*76ce1169SAndreas Gohr } 660*76ce1169SAndreas Gohr else { 661*76ce1169SAndreas Gohr return true; 662*76ce1169SAndreas Gohr } 663*76ce1169SAndreas Gohr } 664*76ce1169SAndreas Gohr 665*76ce1169SAndreas Gohr 666*76ce1169SAndreas Gohr if ($this->baseDn == NULL) { 667*76ce1169SAndreas Gohr $this->baseDn = $this->findBaseDn(); 668*76ce1169SAndreas Gohr } 669*76ce1169SAndreas Gohr 670*76ce1169SAndreas Gohr return true; 671*76ce1169SAndreas Gohr } 672*76ce1169SAndreas Gohr 673*76ce1169SAndreas Gohr /** 674*76ce1169SAndreas Gohr * Closes the LDAP connection 675*76ce1169SAndreas Gohr * 676*76ce1169SAndreas Gohr * @return void 677*76ce1169SAndreas Gohr */ 678*76ce1169SAndreas Gohr public function close() { 679*76ce1169SAndreas Gohr if ($this->ldapConnection) { 680*76ce1169SAndreas Gohr @ldap_close($this->ldapConnection); 681*76ce1169SAndreas Gohr } 682*76ce1169SAndreas Gohr } 683*76ce1169SAndreas Gohr 684*76ce1169SAndreas Gohr /** 685*76ce1169SAndreas Gohr * Validate a user's login credentials 686*76ce1169SAndreas Gohr * 687*76ce1169SAndreas Gohr * @param string $username A user's AD username 688*76ce1169SAndreas Gohr * @param string $password A user's AD password 689*76ce1169SAndreas Gohr * @param bool optional $preventRebind 690*76ce1169SAndreas Gohr * @return bool 691*76ce1169SAndreas Gohr */ 692*76ce1169SAndreas Gohr public function authenticate($username, $password, $preventRebind = false) { 693*76ce1169SAndreas Gohr // Prevent null binding 694*76ce1169SAndreas Gohr if ($username === NULL || $password === NULL) { return false; } 695*76ce1169SAndreas Gohr if (empty($username) || empty($password)) { return false; } 696*76ce1169SAndreas Gohr 697*76ce1169SAndreas Gohr // Allow binding over SSO for Kerberos 698*76ce1169SAndreas Gohr if ($this->useSSO && $_SERVER['REMOTE_USER'] && $_SERVER['REMOTE_USER'] == $username && $this->adminUsername === NULL && $_SERVER['KRB5CCNAME']) { 699*76ce1169SAndreas Gohr putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']); 700*76ce1169SAndreas Gohr $this->ldapBind = @ldap_sasl_bind($this->ldapConnection, NULL, NULL, "GSSAPI"); 701*76ce1169SAndreas Gohr if (!$this->ldapBind) { 702*76ce1169SAndreas Gohr throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 703*76ce1169SAndreas Gohr } 704*76ce1169SAndreas Gohr else { 705*76ce1169SAndreas Gohr return true; 706*76ce1169SAndreas Gohr } 707*76ce1169SAndreas Gohr } 708*76ce1169SAndreas Gohr 709*76ce1169SAndreas Gohr // Bind as the user 710*76ce1169SAndreas Gohr $ret = true; 711*76ce1169SAndreas Gohr $this->ldapBind = @ldap_bind($this->ldapConnection, $username . $this->accountSuffix, $password); 712*76ce1169SAndreas Gohr if (!$this->ldapBind){ 713*76ce1169SAndreas Gohr $ret = false; 714*76ce1169SAndreas Gohr } 715*76ce1169SAndreas Gohr 716*76ce1169SAndreas Gohr // Cnce we've checked their details, kick back into admin mode if we have it 717*76ce1169SAndreas Gohr if ($this->adminUsername !== NULL && !$preventRebind) { 718*76ce1169SAndreas Gohr $this->ldapBind = @ldap_bind($this->ldapConnection, $this->adminUsername . $this->accountSuffix , $this->adminPassword); 719*76ce1169SAndreas Gohr if (!$this->ldapBind){ 720*76ce1169SAndreas Gohr // This should never happen in theory 721*76ce1169SAndreas Gohr throw new adLDAPException('Rebind to Active Directory failed. AD said: ' . $this->getLastError()); 722*76ce1169SAndreas Gohr } 723*76ce1169SAndreas Gohr } 724*76ce1169SAndreas Gohr 725*76ce1169SAndreas Gohr return $ret; 726*76ce1169SAndreas Gohr } 727*76ce1169SAndreas Gohr 728*76ce1169SAndreas Gohr /** 729*76ce1169SAndreas Gohr * Find the Base DN of your domain controller 730*76ce1169SAndreas Gohr * 731*76ce1169SAndreas Gohr * @return string 732*76ce1169SAndreas Gohr */ 733*76ce1169SAndreas Gohr public function findBaseDn() 734*76ce1169SAndreas Gohr { 735*76ce1169SAndreas Gohr $namingContext = $this->getRootDse(array('defaultnamingcontext')); 736*76ce1169SAndreas Gohr return $namingContext[0]['defaultnamingcontext'][0]; 737*76ce1169SAndreas Gohr } 738*76ce1169SAndreas Gohr 739*76ce1169SAndreas Gohr /** 740*76ce1169SAndreas Gohr * Get the RootDSE properties from a domain controller 741*76ce1169SAndreas Gohr * 742*76ce1169SAndreas Gohr * @param array $attributes The attributes you wish to query e.g. defaultnamingcontext 743*76ce1169SAndreas Gohr * @return array 744*76ce1169SAndreas Gohr */ 745*76ce1169SAndreas Gohr public function getRootDse($attributes = array("*", "+")) { 746*76ce1169SAndreas Gohr if (!$this->ldapBind){ return (false); } 747*76ce1169SAndreas Gohr 748*76ce1169SAndreas Gohr $sr = @ldap_read($this->ldapConnection, NULL, 'objectClass=*', $attributes); 749*76ce1169SAndreas Gohr $entries = @ldap_get_entries($this->ldapConnection, $sr); 750*76ce1169SAndreas Gohr return $entries; 751*76ce1169SAndreas Gohr } 752*76ce1169SAndreas Gohr 753*76ce1169SAndreas Gohr /** 754*76ce1169SAndreas Gohr * Get last error from Active Directory 755*76ce1169SAndreas Gohr * 756*76ce1169SAndreas Gohr * This function gets the last message from Active Directory 757*76ce1169SAndreas Gohr * This may indeed be a 'Success' message but if you get an unknown error 758*76ce1169SAndreas Gohr * it might be worth calling this function to see what errors were raised 759*76ce1169SAndreas Gohr * 760*76ce1169SAndreas Gohr * return string 761*76ce1169SAndreas Gohr */ 762*76ce1169SAndreas Gohr public function getLastError() { 763*76ce1169SAndreas Gohr return @ldap_error($this->ldapConnection); 764*76ce1169SAndreas Gohr } 765*76ce1169SAndreas Gohr 766*76ce1169SAndreas Gohr /** 767*76ce1169SAndreas Gohr * Detect LDAP support in php 768*76ce1169SAndreas Gohr * 769*76ce1169SAndreas Gohr * @return bool 770*76ce1169SAndreas Gohr */ 771*76ce1169SAndreas Gohr protected function ldapSupported() 772*76ce1169SAndreas Gohr { 773*76ce1169SAndreas Gohr if (!function_exists('ldap_connect')) { 774*76ce1169SAndreas Gohr return false; 775*76ce1169SAndreas Gohr } 776*76ce1169SAndreas Gohr return true; 777*76ce1169SAndreas Gohr } 778*76ce1169SAndreas Gohr 779*76ce1169SAndreas Gohr /** 780*76ce1169SAndreas Gohr * Detect ldap_sasl_bind support in PHP 781*76ce1169SAndreas Gohr * 782*76ce1169SAndreas Gohr * @return bool 783*76ce1169SAndreas Gohr */ 784*76ce1169SAndreas Gohr protected function ldapSaslSupported() 785*76ce1169SAndreas Gohr { 786*76ce1169SAndreas Gohr if (!function_exists('ldap_sasl_bind')) { 787*76ce1169SAndreas Gohr return false; 788*76ce1169SAndreas Gohr } 789*76ce1169SAndreas Gohr return true; 790*76ce1169SAndreas Gohr } 791*76ce1169SAndreas Gohr 792*76ce1169SAndreas Gohr /** 793*76ce1169SAndreas Gohr * Schema 794*76ce1169SAndreas Gohr * 795*76ce1169SAndreas Gohr * @param array $attributes Attributes to be queried 796*76ce1169SAndreas Gohr * @return array 797*76ce1169SAndreas Gohr */ 798*76ce1169SAndreas Gohr public function adldap_schema($attributes){ 799*76ce1169SAndreas Gohr 800*76ce1169SAndreas Gohr // LDAP doesn't like NULL attributes, only set them if they have values 801*76ce1169SAndreas Gohr // If you wish to remove an attribute you should set it to a space 802*76ce1169SAndreas Gohr // TO DO: Adapt user_modify to use ldap_mod_delete to remove a NULL attribute 803*76ce1169SAndreas Gohr $mod=array(); 804*76ce1169SAndreas Gohr 805*76ce1169SAndreas Gohr // Check every attribute to see if it contains 8bit characters and then UTF8 encode them 806*76ce1169SAndreas Gohr array_walk($attributes, array($this, 'encode8bit')); 807*76ce1169SAndreas Gohr 808*76ce1169SAndreas Gohr if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; } 809*76ce1169SAndreas Gohr if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; } 810*76ce1169SAndreas Gohr //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes? 811*76ce1169SAndreas Gohr if ($attributes["address_country"]){ $mod["c"][0]=$attributes["address_country"]; } 812*76ce1169SAndreas Gohr if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; } 813*76ce1169SAndreas Gohr if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; } 814*76ce1169SAndreas Gohr if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; } 815*76ce1169SAndreas Gohr if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; } 816*76ce1169SAndreas Gohr if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; } 817*76ce1169SAndreas Gohr if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; } 818*76ce1169SAndreas Gohr if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; } 819*76ce1169SAndreas Gohr if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; } 820*76ce1169SAndreas Gohr if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; } 821*76ce1169SAndreas Gohr if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format? 822*76ce1169SAndreas Gohr if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; } 823*76ce1169SAndreas Gohr if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; } 824*76ce1169SAndreas Gohr if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; } 825*76ce1169SAndreas Gohr if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; } 826*76ce1169SAndreas Gohr if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; } 827*76ce1169SAndreas Gohr if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; } //UNTESTED ***Use DistinguishedName*** 828*76ce1169SAndreas Gohr if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; } 829*76ce1169SAndreas Gohr if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->user()->encodePassword($attributes["password"]); } 830*76ce1169SAndreas Gohr if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; } 831*76ce1169SAndreas Gohr if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; } 832*76ce1169SAndreas Gohr if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; } 833*76ce1169SAndreas Gohr if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; } 834*76ce1169SAndreas Gohr if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; } 835*76ce1169SAndreas Gohr if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; } 836*76ce1169SAndreas Gohr if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; } 837*76ce1169SAndreas Gohr if ($attributes["ipphone"]){ $mod["ipphone"][0]=$attributes["ipphone"]; } 838*76ce1169SAndreas Gohr if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; } 839*76ce1169SAndreas Gohr if ($attributes["fax"]){ $mod["facsimileTelephoneNumber"][0]=$attributes["fax"]; } 840*76ce1169SAndreas Gohr if ($attributes["enabled"]){ $mod["userAccountControl"][0]=$attributes["enabled"]; } 841*76ce1169SAndreas Gohr if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; } 842*76ce1169SAndreas Gohr 843*76ce1169SAndreas Gohr // Distribution List specific schema 844*76ce1169SAndreas Gohr if ($attributes["group_sendpermission"]){ $mod["dlMemSubmitPerms"][0]=$attributes["group_sendpermission"]; } 845*76ce1169SAndreas Gohr if ($attributes["group_rejectpermission"]){ $mod["dlMemRejectPerms"][0]=$attributes["group_rejectpermission"]; } 846*76ce1169SAndreas Gohr 847*76ce1169SAndreas Gohr // Exchange Schema 848*76ce1169SAndreas Gohr if ($attributes["exchange_homemdb"]){ $mod["homeMDB"][0]=$attributes["exchange_homemdb"]; } 849*76ce1169SAndreas Gohr if ($attributes["exchange_mailnickname"]){ $mod["mailNickname"][0]=$attributes["exchange_mailnickname"]; } 850*76ce1169SAndreas Gohr if ($attributes["exchange_proxyaddress"]){ $mod["proxyAddresses"][0]=$attributes["exchange_proxyaddress"]; } 851*76ce1169SAndreas Gohr if ($attributes["exchange_usedefaults"]){ $mod["mDBUseDefaults"][0]=$attributes["exchange_usedefaults"]; } 852*76ce1169SAndreas Gohr if ($attributes["exchange_policyexclude"]){ $mod["msExchPoliciesExcluded"][0]=$attributes["exchange_policyexclude"]; } 853*76ce1169SAndreas Gohr if ($attributes["exchange_policyinclude"]){ $mod["msExchPoliciesIncluded"][0]=$attributes["exchange_policyinclude"]; } 854*76ce1169SAndreas Gohr if ($attributes["exchange_addressbook"]){ $mod["showInAddressBook"][0]=$attributes["exchange_addressbook"]; } 855*76ce1169SAndreas Gohr if ($attributes["exchange_altrecipient"]){ $mod["altRecipient"][0]=$attributes["exchange_altrecipient"]; } 856*76ce1169SAndreas Gohr if ($attributes["exchange_deliverandredirect"]){ $mod["deliverAndRedirect"][0]=$attributes["exchange_deliverandredirect"]; } 857*76ce1169SAndreas Gohr 858*76ce1169SAndreas Gohr // This schema is designed for contacts 859*76ce1169SAndreas Gohr if ($attributes["exchange_hidefromlists"]){ $mod["msExchHideFromAddressLists"][0]=$attributes["exchange_hidefromlists"]; } 860*76ce1169SAndreas Gohr if ($attributes["contact_email"]){ $mod["targetAddress"][0]=$attributes["contact_email"]; } 861*76ce1169SAndreas Gohr 862*76ce1169SAndreas Gohr //echo ("<pre>"); print_r($mod); 863*76ce1169SAndreas Gohr /* 864*76ce1169SAndreas Gohr // modifying a name is a bit fiddly 865*76ce1169SAndreas Gohr if ($attributes["firstname"] && $attributes["surname"]){ 866*76ce1169SAndreas Gohr $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"]; 867*76ce1169SAndreas Gohr $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"]; 868*76ce1169SAndreas Gohr $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"]; 869*76ce1169SAndreas Gohr } 870*76ce1169SAndreas Gohr */ 871*76ce1169SAndreas Gohr 872*76ce1169SAndreas Gohr if (count($mod)==0){ return (false); } 873*76ce1169SAndreas Gohr return ($mod); 874*76ce1169SAndreas Gohr } 875*76ce1169SAndreas Gohr 876*76ce1169SAndreas Gohr /** 877*76ce1169SAndreas Gohr * Convert 8bit characters e.g. accented characters to UTF8 encoded characters 878*76ce1169SAndreas Gohr */ 879*76ce1169SAndreas Gohr protected function encode8Bit(&$item, $key) { 880*76ce1169SAndreas Gohr $encode = false; 881*76ce1169SAndreas Gohr if (is_string($item)) { 882*76ce1169SAndreas Gohr for ($i=0; $i<strlen($item); $i++) { 883*76ce1169SAndreas Gohr if (ord($item[$i]) >> 7) { 884*76ce1169SAndreas Gohr $encode = true; 885*76ce1169SAndreas Gohr } 886*76ce1169SAndreas Gohr } 887*76ce1169SAndreas Gohr } 888*76ce1169SAndreas Gohr if ($encode === true && $key != 'password') { 889*76ce1169SAndreas Gohr $item = utf8_encode($item); 890*76ce1169SAndreas Gohr } 891*76ce1169SAndreas Gohr } 892*76ce1169SAndreas Gohr 893*76ce1169SAndreas Gohr /** 894*76ce1169SAndreas Gohr * Select a random domain controller from your domain controller array 895*76ce1169SAndreas Gohr * 896*76ce1169SAndreas Gohr * @return string 897*76ce1169SAndreas Gohr */ 898*76ce1169SAndreas Gohr protected function randomController() 899*76ce1169SAndreas Gohr { 900*76ce1169SAndreas Gohr mt_srand(doubleval(microtime()) * 100000000); // For older PHP versions 901*76ce1169SAndreas Gohr /*if (sizeof($this->domainControllers) > 1) { 902*76ce1169SAndreas Gohr $adController = $this->domainControllers[array_rand($this->domainControllers)]; 903*76ce1169SAndreas Gohr // Test if the controller is responding to pings 904*76ce1169SAndreas Gohr $ping = $this->pingController($adController); 905*76ce1169SAndreas Gohr if ($ping === false) { 906*76ce1169SAndreas Gohr // Find the current key in the domain controllers array 907*76ce1169SAndreas Gohr $key = array_search($adController, $this->domainControllers); 908*76ce1169SAndreas Gohr // Remove it so that we don't end up in a recursive loop 909*76ce1169SAndreas Gohr unset($this->domainControllers[$key]); 910*76ce1169SAndreas Gohr // Select a new controller 911*76ce1169SAndreas Gohr return $this->randomController(); 912*76ce1169SAndreas Gohr } 913*76ce1169SAndreas Gohr else { 914*76ce1169SAndreas Gohr return ($adController); 915*76ce1169SAndreas Gohr } 916*76ce1169SAndreas Gohr } */ 917*76ce1169SAndreas Gohr return $this->domainControllers[array_rand($this->domainControllers)]; 918*76ce1169SAndreas Gohr } 919*76ce1169SAndreas Gohr 920*76ce1169SAndreas Gohr /** 921*76ce1169SAndreas Gohr * Test basic connectivity to controller 922*76ce1169SAndreas Gohr * 923*76ce1169SAndreas Gohr * @return bool 924*76ce1169SAndreas Gohr */ 925*76ce1169SAndreas Gohr protected function pingController($host) { 926*76ce1169SAndreas Gohr $port = $this->adPort; 927*76ce1169SAndreas Gohr fsockopen($host, $port, $errno, $errstr, 10); 928*76ce1169SAndreas Gohr if ($errno > 0) { 929*76ce1169SAndreas Gohr return false; 930*76ce1169SAndreas Gohr } 931*76ce1169SAndreas Gohr return true; 932*76ce1169SAndreas Gohr } 933*76ce1169SAndreas Gohr 934*76ce1169SAndreas Gohr} 935*76ce1169SAndreas Gohr 936*76ce1169SAndreas Gohr/** 937*76ce1169SAndreas Gohr* adLDAP Exception Handler 938*76ce1169SAndreas Gohr* 939*76ce1169SAndreas Gohr* Exceptions of this type are thrown on bind failure or when SSL is required but not configured 940*76ce1169SAndreas Gohr* Example: 941*76ce1169SAndreas Gohr* try { 942*76ce1169SAndreas Gohr* $adldap = new adLDAP(); 943*76ce1169SAndreas Gohr* } 944*76ce1169SAndreas Gohr* catch (adLDAPException $e) { 945*76ce1169SAndreas Gohr* echo $e; 946*76ce1169SAndreas Gohr* exit(); 947*76ce1169SAndreas Gohr* } 948*76ce1169SAndreas Gohr*/ 949*76ce1169SAndreas Gohrclass adLDAPException extends Exception {} 950*76ce1169SAndreas Gohr 951*76ce1169SAndreas Gohr?>