PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Joomla/Client/LdapClient.php

https://github.com/dianaprajescu/joomla-framework
PHP | 659 lines | 346 code | 62 blank | 251 comment | 27 complexity | 1fb56e9f56979f4126a8f519565b2b3c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Part of the Joomla Framework Client Package
  4. *
  5. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  6. * @license GNU General Public License version 2 or later; see LICENSE
  7. */
  8. namespace Joomla\Client;
  9. /**
  10. * LDAP client class
  11. *
  12. * @since 1.0
  13. */
  14. class LdapClient
  15. {
  16. /**
  17. * @var string Hostname of LDAP server
  18. * @since 1.0
  19. */
  20. public $host = null;
  21. /**
  22. * @var bool Authorization Method to use
  23. * @since 1.0
  24. */
  25. public $auth_method = null;
  26. /**
  27. * @var int Port of LDAP server
  28. * @since 1.0
  29. */
  30. public $port = null;
  31. /**
  32. * @var string Base DN (e.g. o=MyDir)
  33. * @since 1.0
  34. */
  35. public $base_dn = null;
  36. /**
  37. * @var string User DN (e.g. cn=Users,o=MyDir)
  38. * @since 1.0
  39. */
  40. public $users_dn = null;
  41. /**
  42. * @var string Search String
  43. * @since 1.0
  44. */
  45. public $search_string = null;
  46. /**
  47. * @var boolean Use LDAP Version 3
  48. * @since 1.0
  49. */
  50. public $use_ldapV3 = null;
  51. /**
  52. * @var boolean No referrals (server transfers)
  53. * @since 1.0
  54. */
  55. public $no_referrals = null;
  56. /**
  57. * @var boolean Negotiate TLS (encrypted communications)
  58. * @since 1.0
  59. */
  60. public $negotiate_tls = null;
  61. /**
  62. * @var string Username to connect to server
  63. * @since 1.0
  64. */
  65. public $username = null;
  66. /**
  67. *
  68. * @var string Password to connect to server
  69. * @since 1.0
  70. */
  71. public $password = null;
  72. /**
  73. * @var mixed LDAP Resource Identifier
  74. * @since 1.0
  75. */
  76. private $resource = null;
  77. /**
  78. *
  79. * @var string Current DN
  80. * @since 1.0
  81. */
  82. private $dn = null;
  83. /**
  84. * Constructor
  85. *
  86. * @param object $configObj An object of configuration variables
  87. *
  88. * @since 1.0
  89. */
  90. public function __construct($configObj = null)
  91. {
  92. if (is_object($configObj))
  93. {
  94. $vars = get_class_vars(get_class($this));
  95. foreach (array_keys($vars) as $var)
  96. {
  97. if (substr($var, 0, 1) != '_')
  98. {
  99. $param = $configObj->get($var);
  100. if ($param)
  101. {
  102. $this->$var = $param;
  103. }
  104. }
  105. }
  106. }
  107. }
  108. /**
  109. * Connect to server
  110. *
  111. * @return boolean True if successful
  112. *
  113. * @since 1.0
  114. */
  115. public function connect()
  116. {
  117. if ($this->host == '')
  118. {
  119. return false;
  120. }
  121. $this->resource = @ ldap_connect($this->host, $this->port);
  122. if ($this->resource)
  123. {
  124. if ($this->use_ldapV3)
  125. {
  126. if (!@ldap_set_option($this->resource, LDAP_OPT_PROTOCOL_VERSION, 3))
  127. {
  128. return false;
  129. }
  130. }
  131. if (!@ldap_set_option($this->resource, LDAP_OPT_REFERRALS, (int) $this->no_referrals))
  132. {
  133. return false;
  134. }
  135. if ($this->negotiate_tls)
  136. {
  137. if (!@ldap_start_tls($this->resource))
  138. {
  139. return false;
  140. }
  141. }
  142. return true;
  143. }
  144. else
  145. {
  146. return false;
  147. }
  148. }
  149. /**
  150. * Close the connection
  151. *
  152. * @return void
  153. *
  154. * @since 1.0
  155. */
  156. public function close()
  157. {
  158. @ ldap_close($this->resource);
  159. }
  160. /**
  161. * Sets the DN with some template replacements
  162. *
  163. * @param string $username The username
  164. * @param string $nosub ...
  165. *
  166. * @return void
  167. *
  168. * @since 1.0
  169. */
  170. public function setDN($username, $nosub = 0)
  171. {
  172. if ($this->users_dn == '' || $nosub)
  173. {
  174. $this->dn = $username;
  175. }
  176. elseif (strlen($username))
  177. {
  178. $this->dn = str_replace('[username]', $username, $this->users_dn);
  179. }
  180. else
  181. {
  182. $this->dn = '';
  183. }
  184. }
  185. /**
  186. * Get the DN
  187. *
  188. * @return string The current dn
  189. *
  190. * @since 1.0
  191. */
  192. public function getDN()
  193. {
  194. return $this->dn;
  195. }
  196. /**
  197. * Anonymously binds to LDAP directory
  198. *
  199. * @return array
  200. *
  201. * @since 1.0
  202. */
  203. public function anonymous_bind()
  204. {
  205. $bindResult = @ldap_bind($this->resource);
  206. return $bindResult;
  207. }
  208. /**
  209. * Binds to the LDAP directory
  210. *
  211. * @param string $username The username
  212. * @param string $password The password
  213. * @param string $nosub ...
  214. *
  215. * @return boolean
  216. *
  217. * @since 1.0
  218. */
  219. public function bind($username = null, $password = null, $nosub = 0)
  220. {
  221. if (is_null($username))
  222. {
  223. $username = $this->username;
  224. }
  225. if (is_null($password))
  226. {
  227. $password = $this->password;
  228. }
  229. $this->setDN($username, $nosub);
  230. $bindResult = @ldap_bind($this->resource, $this->getDN(), $password);
  231. return $bindResult;
  232. }
  233. /**
  234. * Perform an LDAP search using comma separated search strings
  235. *
  236. * @param string $search search string of search values
  237. *
  238. * @return array Search results
  239. *
  240. * @since 1.0
  241. */
  242. public function simple_search($search)
  243. {
  244. $results = explode(';', $search);
  245. foreach ($results as $key => $result)
  246. {
  247. $results[$key] = '(' . $result . ')';
  248. }
  249. return $this->search($results);
  250. }
  251. /**
  252. * Performs an LDAP search
  253. *
  254. * @param array $filters Search Filters (array of strings)
  255. * @param string $dnoverride DN Override
  256. * @param array $attributes An array of attributes to return (if empty, all fields are returned).
  257. *
  258. * @return array Multidimensional array of results
  259. *
  260. * @since 1.0
  261. */
  262. public function search(array $filters, $dnoverride = null, array $attributes = array())
  263. {
  264. $result = array();
  265. if ($dnoverride)
  266. {
  267. $dn = $dnoverride;
  268. }
  269. else
  270. {
  271. $dn = $this->base_dn;
  272. }
  273. $resource = $this->resource;
  274. foreach ($filters as $search_filter)
  275. {
  276. $search_result = @ldap_search($resource, $dn, $search_filter, $attributes);
  277. if ($search_result && ($count = @ldap_count_entries($resource, $search_result)) > 0)
  278. {
  279. for ($i = 0; $i < $count; $i++)
  280. {
  281. $result[$i] = array();
  282. if (!$i)
  283. {
  284. $firstentry = @ldap_first_entry($resource, $search_result);
  285. }
  286. else
  287. {
  288. $firstentry = @ldap_next_entry($resource, $firstentry);
  289. }
  290. // Load user-specified attributes
  291. $result_array = @ldap_get_attributes($resource, $firstentry);
  292. // LDAP returns an array of arrays, fit this into attributes result array
  293. foreach ($result_array as $ki => $ai)
  294. {
  295. if (is_array($ai))
  296. {
  297. $subcount = $ai['count'];
  298. $result[$i][$ki] = array();
  299. for ($k = 0; $k < $subcount; $k++)
  300. {
  301. $result[$i][$ki][$k] = $ai[$k];
  302. }
  303. }
  304. }
  305. $result[$i]['dn'] = @ldap_get_dn($resource, $firstentry);
  306. }
  307. }
  308. }
  309. return $result;
  310. }
  311. /**
  312. * Replace an entry and return a true or false result
  313. *
  314. * @param string $dn The DN which contains the attribute you want to replace
  315. * @param string $attribute The attribute values you want to replace
  316. *
  317. * @return mixed result of comparison (true, false, -1 on error)
  318. *
  319. * @since 1.0
  320. */
  321. public function replace($dn, $attribute)
  322. {
  323. return @ldap_mod_replace($this->resource, $dn, $attribute);
  324. }
  325. /**
  326. * Modifies an entry and return a true or false result
  327. *
  328. * @param string $dn The DN which contains the attribute you want to modify
  329. * @param string $attribute The attribute values you want to modify
  330. *
  331. * @return mixed result of comparison (true, false, -1 on error)
  332. *
  333. * @since 1.0
  334. */
  335. public function modify($dn, $attribute)
  336. {
  337. return @ldap_modify($this->resource, $dn, $attribute);
  338. }
  339. /**
  340. * Removes attribute value from given dn and return a true or false result
  341. *
  342. * @param string $dn The DN which contains the attribute you want to remove
  343. * @param string $attribute The attribute values you want to remove
  344. *
  345. * @return mixed result of comparison (true, false, -1 on error)
  346. *
  347. * @since 1.0
  348. */
  349. public function remove($dn, $attribute)
  350. {
  351. $resource = $this->resource;
  352. return @ldap_mod_del($resource, $dn, $attribute);
  353. }
  354. /**
  355. * Compare an entry and return a true or false result
  356. *
  357. * @param string $dn The DN which contains the attribute you want to compare
  358. * @param string $attribute The attribute whose value you want to compare
  359. * @param string $value The value you want to check against the LDAP attribute
  360. *
  361. * @return mixed result of comparison (true, false, -1 on error)
  362. *
  363. * @since 1.0
  364. */
  365. public function compare($dn, $attribute, $value)
  366. {
  367. return @ldap_compare($this->resource, $dn, $attribute, $value);
  368. }
  369. /**
  370. * Read all or specified attributes of given dn
  371. *
  372. * @param string $dn The DN of the object you want to read
  373. *
  374. * @return mixed array of attributes or -1 on error
  375. *
  376. * @since 1.0
  377. */
  378. public function read($dn)
  379. {
  380. $base = substr($dn, strpos($dn, ',') + 1);
  381. $cn = substr($dn, 0, strpos($dn, ','));
  382. $result = @ldap_read($this->resource, $base, $cn);
  383. if ($result)
  384. {
  385. return @ldap_get_entries($this->resource, $result);
  386. }
  387. else
  388. {
  389. return $result;
  390. }
  391. }
  392. /**
  393. * Deletes a given DN from the tree
  394. *
  395. * @param string $dn The DN of the object you want to delete
  396. *
  397. * @return boolean Result of operation
  398. *
  399. * @since 1.0
  400. */
  401. public function delete($dn)
  402. {
  403. return @ldap_delete($this->resource, $dn);
  404. }
  405. /**
  406. * Create a new DN
  407. *
  408. * @param string $dn The DN where you want to put the object
  409. * @param array $entries An array of arrays describing the object to add
  410. *
  411. * @return boolean Result of operation
  412. *
  413. * @since 1.0
  414. */
  415. public function create($dn, array $entries)
  416. {
  417. return @ldap_add($this->resource, $dn, $entries);
  418. }
  419. /**
  420. * Add an attribute to the given DN
  421. * Note: DN has to exist already
  422. *
  423. * @param string $dn The DN of the entry to add the attribute
  424. * @param array $entry An array of arrays with attributes to add
  425. *
  426. * @return boolean Result of operation
  427. *
  428. * @since 1.0
  429. */
  430. public function add($dn, array $entry)
  431. {
  432. return @ldap_mod_add($this->resource, $dn, $entry);
  433. }
  434. /**
  435. * Rename the entry
  436. *
  437. * @param string $dn The DN of the entry at the moment
  438. * @param string $newdn The DN of the entry should be (only cn=newvalue)
  439. * @param string $newparent The full DN of the parent (null by default)
  440. * @param boolean $deleteolddn Delete the old values (default)
  441. *
  442. * @return boolean Result of operation
  443. *
  444. * @since 1.0
  445. */
  446. public function rename($dn, $newdn, $newparent, $deleteolddn)
  447. {
  448. return @ldap_rename($this->resource, $dn, $newdn, $newparent, $deleteolddn);
  449. }
  450. /**
  451. * Returns the error message
  452. *
  453. * @return string error message
  454. *
  455. * @since 1.0
  456. */
  457. public function getErrorMsg()
  458. {
  459. return @ldap_error($this->resource);
  460. }
  461. /**
  462. * Converts a dot notation IP address to net address (e.g. for Netware, etc)
  463. *
  464. * @param string $ip IP Address (e.g. xxx.xxx.xxx.xxx)
  465. *
  466. * @return string Net address
  467. *
  468. * @since 1.0
  469. */
  470. public static function ipToNetAddress($ip)
  471. {
  472. $parts = explode('.', $ip);
  473. $address = '1#';
  474. foreach ($parts as $int)
  475. {
  476. $tmp = dechex($int);
  477. if (strlen($tmp) != 2)
  478. {
  479. $tmp = '0' . $tmp;
  480. }
  481. $address .= '\\' . $tmp;
  482. }
  483. return $address;
  484. }
  485. /**
  486. * Extract readable network address from the LDAP encoded networkAddress attribute.
  487. *
  488. * Please keep this document block and author attribution in place.
  489. *
  490. * Novell Docs, see: http://developer.novell.com/ndk/doc/ndslib/schm_enu/data/sdk5624.html#sdk5624
  491. * for Address types: http://developer.novell.com/ndk/doc/ndslib/index.html?page=/ndk/doc/ndslib/schm_enu/data/sdk4170.html
  492. * LDAP Format, String:
  493. * taggedData = uint32String "#" octetstring
  494. * byte 0 = uint32String = Address Type: 0= IPX Address; 1 = IP Address
  495. * byte 1 = char = "#" - separator
  496. * byte 2+ = octetstring - the ordinal value of the address
  497. * Note: with eDirectory 8.6.2, the IP address (type 1) returns
  498. * correctly, however, an IPX address does not seem to. eDir 8.7 may correct this.
  499. * Enhancement made by Merijn van de Schoot:
  500. * If addresstype is 8 (UDP) or 9 (TCP) do some additional parsing like still returning the IP address
  501. *
  502. * @param string $networkaddress The network address
  503. *
  504. * @return array
  505. *
  506. * @author Jay Burrell, Systems & Networks, Mississippi State University
  507. * @since 1.0
  508. */
  509. public static function LDAPNetAddr($networkaddress)
  510. {
  511. $addr = "";
  512. $addrtype = (int) substr($networkaddress, 0, 1);
  513. // Throw away bytes 0 and 1 which should be the addrtype and the "#" separator
  514. $networkaddress = substr($networkaddress, 2);
  515. if (($addrtype == 8) || ($addrtype = 9))
  516. {
  517. // TODO 1.6: If UDP or TCP, (TODO fill addrport and) strip portnumber information from address
  518. $networkaddress = substr($networkaddress, (strlen($networkaddress) - 4));
  519. }
  520. $addrtypes = array(
  521. 'IPX',
  522. 'IP',
  523. 'SDLC',
  524. 'Token Ring',
  525. 'OSI',
  526. 'AppleTalk',
  527. 'NetBEUI',
  528. 'Socket',
  529. 'UDP',
  530. 'TCP',
  531. 'UDP6',
  532. 'TCP6',
  533. 'Reserved (12)',
  534. 'URL',
  535. 'Count');
  536. $len = strlen($networkaddress);
  537. if ($len > 0)
  538. {
  539. for ($i = 0; $i < $len; $i++)
  540. {
  541. $byte = substr($networkaddress, $i, 1);
  542. $addr .= ord($byte);
  543. if (($addrtype == 1) || ($addrtype == 8) || ($addrtype = 9))
  544. {
  545. // Dot separate IP addresses...
  546. $addr .= ".";
  547. }
  548. }
  549. if (($addrtype == 1) || ($addrtype == 8) || ($addrtype = 9))
  550. {
  551. // Strip last period from end of $addr
  552. $addr = substr($addr, 0, strlen($addr) - 1);
  553. }
  554. }
  555. else
  556. {
  557. $addr .= 'Address not available.';
  558. }
  559. return array('protocol' => $addrtypes[$addrtype], 'address' => $addr);
  560. }
  561. /**
  562. * Generates a LDAP compatible password
  563. *
  564. * @param string $password Clear text password to encrypt
  565. * @param string $type Type of password hash, either md5 or SHA
  566. *
  567. * @return string Encrypted password
  568. *
  569. * @since 1.0
  570. */
  571. public static function generatePassword($password, $type = 'md5')
  572. {
  573. switch (strtolower($type))
  574. {
  575. case 'sha':
  576. $userpassword = '{SHA}' . base64_encode(pack('H*', sha1($password)));
  577. break;
  578. case 'md5':
  579. default:
  580. $userpassword = '{MD5}' . base64_encode(pack('H*', md5($password)));
  581. break;
  582. }
  583. return $userpassword;
  584. }
  585. }