AD.class.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. <?php
  2. /**
  3. *
  4. * The Staple_AD class
  5. *
  6. * host - the hostname or IP of the Active Directory server to connect to.
  7. * username - Active Directory username to use to connect to the database with management privledges.
  8. * password - Active Directory password to use to connect to Active Directory.
  9. * LDAPSenabled - Determines if LDAPS is to be used to connect to Active Directory. See LDAPS notes below.
  10. * domain - FQDN of Active Directory
  11. * baseDN - Active Directory baseDN
  12. *
  13. * **LDAPS Notes**
  14. * LDAPS must be enable to perform any password management functions. In order to use LDAPS certificate services must
  15. * be running on your active directory server and the system running this script must accecpt the security certificate.
  16. *
  17. *
  18. * @author Hans Heeling
  19. * @copyright Copywrite (c) 2011, STAPLE CODE
  20. *
  21. * This file is part of the STAPLE Framework.
  22. *
  23. * The STAPLE Framework is free software: you can redistribute it and/or modify
  24. * it under the terms of the GNU General Public License as published by the
  25. * Free Software Foundation, either version 3 of the License, or (at your option)
  26. * any later version.
  27. *
  28. * The STAPLE Framework is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  30. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  31. * more details.
  32. *
  33. * You should have received a copy of the GNU General Public License
  34. * along with the STAPLE Framework. If not, see <http://www.gnu.org/licenses/>.
  35. */
  36. class Staple_AD
  37. {
  38. /**
  39. *
  40. * Holds the singleton instance for the object.
  41. * @var Staple_AD
  42. * @static
  43. */
  44. protected static $conn;
  45. /**
  46. *
  47. * Hostname for the AD server
  48. * @var string
  49. */
  50. protected $host;
  51. /**
  52. *
  53. * Username to access to the AD server
  54. * @var string
  55. */
  56. protected $username;
  57. /**
  58. *
  59. * Password to connect to Active Directory
  60. * @var string
  61. */
  62. protected $password;
  63. /**
  64. *
  65. * Domain name
  66. * @var string
  67. */
  68. protected $domain;
  69. /**
  70. *
  71. * Domain base DN
  72. * @var string
  73. */
  74. protected $baseDN;
  75. /**
  76. *
  77. * True or False if connections are to use LDAPS
  78. * @var string
  79. */
  80. protected $LDAPSenabled;
  81. /**
  82. *
  83. * Holds the connection identifier to the Active Directory server
  84. * @var LDAPConn
  85. */
  86. protected $LDAPConn;
  87. /**
  88. * @return the $host
  89. */
  90. public function getHost()
  91. {
  92. return $this->host;
  93. }
  94. /**
  95. * @param string $host
  96. */
  97. public function setHost($host)
  98. {
  99. $this->host = $host;
  100. return $this;
  101. }
  102. /**
  103. * @return the $username
  104. */
  105. public function getUsername()
  106. {
  107. return $this->username;
  108. }
  109. /**
  110. * @param string $username
  111. */
  112. public function setUsername($username)
  113. {
  114. $this->username = $username;
  115. return $this;
  116. }
  117. /**
  118. * @return the $domain
  119. */
  120. public function getDomain()
  121. {
  122. return $this->domain;
  123. }
  124. /**
  125. * @return the $baseDN
  126. */
  127. public function getbaseDN()
  128. {
  129. return $this->baseDN;
  130. }
  131. public function setbaseDN($baseDN)
  132. {
  133. $this->baseDN = $baseDN;
  134. return $this;
  135. }
  136. /**
  137. * @return the $LDAPSenabled
  138. */
  139. public function getLDAPSenabled()
  140. {
  141. return $this->domain;
  142. }
  143. /**
  144. * @param string $LDAPSenabled
  145. */
  146. public function setLDAPSenabled($LDAPSenabled)
  147. {
  148. $this->LDAPSenabled = $LDAPSenabled;
  149. return $this;
  150. }
  151. /**
  152. * @param string $domain
  153. */
  154. public function setDomain($db)
  155. {
  156. $this->db = $db;
  157. return $this;
  158. }
  159. /**
  160. * Sets the database password parameter.
  161. * @param string $password
  162. */
  163. public function setPassword($password)
  164. {
  165. $this->password = $password;
  166. }
  167. /**
  168. *
  169. * Loads the AD configuration information and esablishes connection to Active Directory Server
  170. *
  171. * @throws Exception
  172. */
  173. protected function __construct()
  174. {
  175. $settings = Staple_Config::get('ActiveDirectory');
  176. $this->host = $settings['host'];
  177. $this->username = $settings['username'];
  178. $this->password = $settings['password'];
  179. $this->domain = $settings['domain'];
  180. $this->baseDN = $settings['baseDN'];
  181. $this->LDAPSenabled = $settings['LDAPSenabled'];
  182. if($this->LDAPSenabled == 1)
  183. {
  184. $LDAPServer = "ldaps://" . $this->host;
  185. $this->LDAPConn = ldap_connect($LDAPServer, 636);
  186. }
  187. else
  188. {
  189. $LDAPServer = "ldap://" . $this->host;
  190. $this->LDAPConn = ldap_connect($LDAPServer, 389);
  191. }
  192. ldap_set_option($this->LDAPConn, LDAP_OPT_PROTOCOL_VERSION, 3);
  193. ldap_set_option($this->LDAPConn, LDAP_OPT_REFERRALS, 0);
  194. $this->mgmtbind();
  195. }
  196. /**
  197. *
  198. * Closes connection to LDAP server to free up resources.
  199. */
  200. public function __destruct()
  201. {
  202. ldap_close($this->LDAPConn);
  203. }
  204. /**
  205. *
  206. * Maintains a single instance of the AD connection.
  207. */
  208. public function __clone()
  209. {
  210. trigger_error('Clone is not allowed.', E_USER_ERROR);
  211. }
  212. /**
  213. *
  214. * Creates a singlton instance of the Staple_AD object.
  215. * @return Staple_AD
  216. */
  217. public static function get()
  218. {
  219. if (!isset(self::$conn)) {
  220. $c = __CLASS__;
  221. self::$conn = new $c();
  222. }
  223. return self::$conn;
  224. }
  225. /**
  226. *
  227. * Returns the full user login name for the specified username
  228. * @returns $usrlogin
  229. * @static
  230. */
  231. public function usrlogin($username)
  232. {
  233. $usrlogin = $username . "@" . $this->domain;
  234. return $usrlogin;
  235. }
  236. /**
  237. *
  238. * Establishes bind to ldap server with management credentials
  239. */
  240. protected function mgmtbind()
  241. {
  242. try
  243. {
  244. if(ldap_bind($this->LDAPConn, $this->usrlogin($this->username), $this->password))
  245. {
  246. return TRUE;
  247. }
  248. else
  249. {
  250. throw new Exception("Active Directory Management Connection Error: Check Management Credentials");
  251. }
  252. }
  253. catch(Exception $e)
  254. {
  255. throw new Exception("Active Directory Management Connection Error: Check Management Credentials");
  256. }
  257. }
  258. /**
  259. *
  260. * Checks the configuration file to make sure that all required keys exist.
  261. * @param array $config
  262. * @throws Exception
  263. */
  264. protected function checkConfig(array $config)
  265. {
  266. $keys = array('host','domain','baseDN','LDAPSenabled','username','password');
  267. foreach($keys as $value)
  268. {
  269. if(!array_key_exists($value, $config))
  270. {
  271. throw new Exception('Staple_AD configuration error.',Staple_Error::DB_ERROR);
  272. }
  273. }
  274. return true;
  275. }
  276. /**
  277. *
  278. * Checks the supplied value for invalid chars, returns TRUE if string is valid
  279. * @param $value
  280. */
  281. public static function validchars($value)
  282. {
  283. if(preg_match('/[^A-Za-z0-9!@$%^&*]/', $value) == 0)
  284. {
  285. return TRUE;
  286. }
  287. return FALSE;
  288. }
  289. /**
  290. *
  291. * Unicodes the supplied password
  292. * @param $password
  293. */
  294. public static function unicodePwd($password)
  295. {
  296. $uniPword = "";
  297. $Pword = "\"$password\"";
  298. $Plength = strlen($Pword);
  299. for($i=0; $i<10; $i++)
  300. {
  301. $uniPword .= "{$Pword{$i}}\000";
  302. }
  303. return $uniPword;
  304. }
  305. /**
  306. *
  307. * Verifies user credentials based on username and password provided, then resestablishes
  308. * management user connection to Active Directory.
  309. * @param $uname
  310. * @param $pword
  311. */
  312. public function bind($uname, $pword)
  313. {
  314. try
  315. {
  316. if(ldap_bind($this->LDAPConn, Staple_AD::usrlogin($uname), $pword))
  317. {
  318. $this->mgmtbind();
  319. return TRUE;
  320. }
  321. else
  322. {
  323. $this->mgmtbind();
  324. return FALSE;
  325. }
  326. }
  327. catch(Exception $e)
  328. {
  329. $this->mgmtbind();
  330. return FALSE;
  331. }
  332. }
  333. /**
  334. *
  335. * Returns an array containing the first and last name for the given username
  336. * @param $username
  337. */
  338. public function firstlast($username)
  339. {
  340. $UserInfo = ldap_get_entries($this->LDAPConn, $this->search("(sAMAccountName=$username)", "sn"));
  341. if(@$UserInfo[0]["sn"][0] != "" && $UserInfo[0]["givenname"][0] != "")
  342. {
  343. $nameInfo = array();
  344. $nameInfo['lastname'] = $UserInfo[0]["sn"][0];
  345. $nameInfo['firstname'] = $UserInfo[0]["givenname"][0];
  346. return $nameInfo;
  347. }
  348. else
  349. {
  350. return FALSE;
  351. }
  352. }
  353. /**
  354. *
  355. * Escapes strings for LDAP Filters and entry.
  356. *
  357. * Caution: This filter is still basic, it is suggested that you create whitelist filters on all
  358. * user input.
  359. *
  360. * @param $value
  361. *
  362. */
  363. public function ldapescape($value)
  364. {
  365. $value = str_replace(array('\\', '*', '(', ')'), array('\5c', '\2a', '\28', '\29'), $value);
  366. foreach(array($value) as $val)
  367. {
  368. if(ord($val) < 32)
  369. {
  370. $hex = dechex(ord($val));
  371. if(strlen($hex) == 1)
  372. {
  373. $hex = '0' . $hex;
  374. $val = '\\' . $hex;
  375. }
  376. }
  377. }
  378. }
  379. /**
  380. *
  381. * This method will change the supplied users password to the provided password. Will return a TRUE for success or a FALSE for
  382. * failure to change the password.
  383. */
  384. public function ChgUsrPwd($username, $password)
  385. {
  386. $filter = "(sAMAccountName=" . $username . ")";
  387. $Result = $this->search($filter, "dn", array("DN"));
  388. $UDN = $Result[0]['dn'];
  389. $encodePWD = $this->unicodePwd($password);
  390. $AccInfo["unicodePwd"] = $encodePWD;
  391. try
  392. {
  393. if(ldap_mod_replace($this->LDAPConn, $UDN, $AccInfo))
  394. {
  395. return TRUE;
  396. }
  397. else
  398. {
  399. return FALSE;
  400. }
  401. }
  402. catch (Exception $e)
  403. {
  404. return FALSE;
  405. }
  406. }
  407. /**
  408. *
  409. * This method allows for the disabling of a user. Will return True if disabled and False if failes to disable
  410. */
  411. public function UsrDisable($username)
  412. {
  413. }
  414. /**
  415. *
  416. * This method allows for the re-enableing of a user account. Will return True is user account is enabled and False if it fails to enable.
  417. *
  418. */
  419. public function UserEnable($username)
  420. {
  421. }
  422. /**
  423. *
  424. * User creation **UNDER CONSTRUCTION**
  425. */
  426. public function UserCreate()
  427. {
  428. }
  429. /**
  430. *
  431. * Simple LDAP search function. Provide the serach term for which you want to serach the LDAP Directory
  432. * as well how you want the returned array sorted. Attributes can be only those items you want to search, and limit
  433. * is how many entries you want returned. returns multi-dimensional array
  434. *
  435. * @param $searchterm - Also known as filter
  436. * @param $sortby
  437. * @param $attributes - Entries to return
  438. * @param $limit
  439. */
  440. public function search($searchterm, $sortby, $attributes = array(), $location = null, $limit = 0)
  441. {
  442. if($location === null)
  443. {
  444. $result = ldap_search($this->LDAPConn, $this->baseDN, $searchterm, $attributes);
  445. }
  446. else
  447. {
  448. if(stripos($location, $this->baseDN) > 0)
  449. {
  450. $DetLocal = $location;
  451. }
  452. else
  453. {
  454. $DetLocal = $location . "," . $this->baseDN;
  455. }
  456. $result = ldap_search($this->LDAPConn, $DetLocal, $searchterm, $attributes);
  457. }
  458. ldap_sort($this->LDAPConn, $result, $sortby);
  459. $entries = ldap_get_entries($this->LDAPConn, $result);
  460. return $entries;
  461. }
  462. /**
  463. *
  464. * Provides a list of users for the given directory DN location when added to the already supplied BaseDN. Will return a multi-dimensional array
  465. * of the returned values.
  466. *
  467. * @param $sortby - can be sorted by sn, givenName, samAccountName
  468. * @param $location - Detail DN excluding BaseDN
  469. */
  470. public function listusers($sortby, $location = null)
  471. {
  472. $filter = "(objectClass=user)";
  473. $attributes = array("sn","givenName","samAccountName");
  474. $entries = $this->search($filter, $sortby, $attributes, $location);
  475. return $entries;
  476. }
  477. public function listous($location = null)
  478. {
  479. $results = array();
  480. $filter = "(objectClass=organizationalUnit)";
  481. $attributes = array("dn");
  482. $entries = $this->search($filter, "dn", $attributes, $location);
  483. for($i=0; $i<$entries['count']; $i++)
  484. {
  485. $results[$i]['cn'] = substr($entries[$i]['dn'], 3, strpos($entries[$i]['dn'], ",")-3);
  486. $results[$i]['dn'] = $entries[$i]['dn'];
  487. }
  488. $count = $entries['count'];
  489. $results['count'] = $count;
  490. return $results;
  491. }
  492. /**
  493. *
  494. * Verifies the existance of the provided user in Active Directory
  495. *
  496. * @param $username
  497. *
  498. */
  499. public function userexit($username)
  500. {
  501. $usersam = "(sAMAccountName=" . $username . ")";
  502. try
  503. {
  504. if($this->search($usersam, "dn", array("DN")))
  505. {
  506. return TRUE;
  507. }
  508. else
  509. {
  510. return FALSE;
  511. }
  512. }
  513. catch (Exception $e)
  514. {
  515. return FALSE;
  516. }
  517. }
  518. /**
  519. *
  520. * Returns the user DN for the given username.
  521. * @param $username
  522. */
  523. public function userDN($username)
  524. {
  525. $UserInfo = $this->search("(sAMAccountName=$username)", "sn", array('dn'));
  526. return $UserInfo[0]['dn'];
  527. }
  528. }