adLDAPUsers.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. <?php
  2. /**
  3. * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
  4. * Version 4.0.4
  5. *
  6. * PHP Version 5 with SSL and LDAP support
  7. *
  8. * Written by Scott Barnett, Richard Hyland
  9. * email: scott@wiggumworld.com, adldap@richardhyland.com
  10. * http://adldap.sourceforge.net/
  11. *
  12. * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
  13. *
  14. * We'd appreciate any improvements or additions to be submitted back
  15. * to benefit the entire community :)
  16. *
  17. * This library is free software; you can redistribute it and/or
  18. * modify it under the terms of the GNU Lesser General Public
  19. * License as published by the Free Software Foundation; either
  20. * version 2.1 of the License.
  21. *
  22. * This library is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  25. * Lesser General Public License for more details.
  26. *
  27. * @category ToolsAndUtilities
  28. * @package adLDAP
  29. * @subpackage User
  30. * @author Scott Barnett, Richard Hyland
  31. * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
  32. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
  33. * @revision $Revision: 97 $
  34. * @version 4.0.4
  35. * @link http://adldap.sourceforge.net/
  36. */
  37. require_once(dirname(__FILE__) . '/../adLDAP.php');
  38. require_once(dirname(__FILE__) . '/../collections/adLDAPUserCollection.php');
  39. use dokuwiki\Utf8\Sort;
  40. /**
  41. * USER FUNCTIONS
  42. */
  43. class adLDAPUsers {
  44. /**
  45. * The current adLDAP connection via dependency injection
  46. *
  47. * @var adLDAP
  48. */
  49. protected $adldap;
  50. public function __construct(adLDAP $adldap) {
  51. $this->adldap = $adldap;
  52. }
  53. /**
  54. * Validate a user's login credentials
  55. *
  56. * @param string $username A user's AD username
  57. * @param string $password A user's AD password
  58. * @param bool optional $prevent_rebind
  59. * @return bool
  60. */
  61. public function authenticate($username, $password, $preventRebind = false) {
  62. return $this->adldap->authenticate($username, $password, $preventRebind);
  63. }
  64. /**
  65. * Create a user
  66. *
  67. * If you specify a password here, this can only be performed over SSL
  68. *
  69. * @param array $attributes The attributes to set to the user account
  70. * @return bool
  71. */
  72. public function create($attributes)
  73. {
  74. // Check for compulsory fields
  75. if (!array_key_exists("username", $attributes)){ return "Missing compulsory field [username]"; }
  76. if (!array_key_exists("firstname", $attributes)){ return "Missing compulsory field [firstname]"; }
  77. if (!array_key_exists("surname", $attributes)){ return "Missing compulsory field [surname]"; }
  78. if (!array_key_exists("email", $attributes)){ return "Missing compulsory field [email]"; }
  79. if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
  80. if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
  81. if (array_key_exists("password",$attributes) && (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS())){
  82. throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
  83. }
  84. if (!array_key_exists("display_name", $attributes)) {
  85. $attributes["display_name"] = $attributes["firstname"] . " " . $attributes["surname"];
  86. }
  87. // Translate the schema
  88. $add = $this->adldap->adldap_schema($attributes);
  89. // Additional stuff only used for adding accounts
  90. $add["cn"][0] = $attributes["display_name"];
  91. $add["samaccountname"][0] = $attributes["username"];
  92. $add["objectclass"][0] = "top";
  93. $add["objectclass"][1] = "person";
  94. $add["objectclass"][2] = "organizationalPerson";
  95. $add["objectclass"][3] = "user"; //person?
  96. //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
  97. // Set the account control attribute
  98. $control_options = array("NORMAL_ACCOUNT");
  99. if (!$attributes["enabled"]) {
  100. $control_options[] = "ACCOUNTDISABLE";
  101. }
  102. $add["userAccountControl"][0] = $this->accountControl($control_options);
  103. // Determine the container
  104. $attributes["container"] = array_reverse($attributes["container"]);
  105. $container = "OU=" . implode(", OU=",$attributes["container"]);
  106. // Add the entry
  107. $result = @ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"][0] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
  108. if ($result != true) {
  109. return false;
  110. }
  111. return true;
  112. }
  113. /**
  114. * Account control options
  115. *
  116. * @param array $options The options to convert to int
  117. * @return int
  118. */
  119. protected function accountControl($options)
  120. {
  121. $val=0;
  122. if (is_array($options)) {
  123. if (in_array("SCRIPT",$options)){ $val=$val+1; }
  124. if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
  125. if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
  126. if (in_array("LOCKOUT",$options)){ $val=$val+16; }
  127. if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
  128. //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
  129. //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
  130. if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
  131. if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
  132. if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
  133. if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
  134. if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
  135. if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
  136. if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
  137. if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
  138. if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
  139. if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
  140. if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
  141. if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
  142. if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; }
  143. if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
  144. if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
  145. }
  146. return $val;
  147. }
  148. /**
  149. * Delete a user account
  150. *
  151. * @param string $username The username to delete (please be careful here!)
  152. * @param bool $isGUID Is the username a GUID or a samAccountName
  153. * @return array
  154. */
  155. public function delete($username, $isGUID = false)
  156. {
  157. $userinfo = $this->info($username, array("*"), $isGUID);
  158. $dn = $userinfo[0]['distinguishedname'][0];
  159. $result = $this->adldap->folder()->delete($dn);
  160. if ($result != true) {
  161. return false;
  162. }
  163. return true;
  164. }
  165. /**
  166. * Groups the user is a member of
  167. *
  168. * @param string $username The username to query
  169. * @param bool $recursive Recursive list of groups
  170. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  171. * @return array
  172. */
  173. public function groups($username, $recursive = NULL, $isGUID = false)
  174. {
  175. if ($username === NULL) { return false; }
  176. if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
  177. if (!$this->adldap->getLdapBind()) { return false; }
  178. // Search the directory for their information
  179. $info = @$this->info($username, array("memberof", "primarygroupid"), $isGUID);
  180. $groups = $this->adldap->utilities()->niceNames($info[0]["memberof"]); // Presuming the entry returned is our guy (unique usernames)
  181. if ($recursive === true){
  182. foreach ($groups as $id => $groupName){
  183. $extraGroups = $this->adldap->group()->recursiveGroups($groupName);
  184. $groups = array_merge($groups, $extraGroups);
  185. }
  186. }
  187. return $groups;
  188. }
  189. /**
  190. * Find information about the users. Returned in a raw array format from AD
  191. *
  192. * @param string $username The username to query
  193. * @param array $fields Array of parameters to query
  194. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  195. * @return array
  196. */
  197. public function info($username, $fields = NULL, $isGUID = false)
  198. {
  199. if ($username === NULL) { return false; }
  200. if (!$this->adldap->getLdapBind()) { return false; }
  201. if ($isGUID === true) {
  202. $username = $this->adldap->utilities()->strGuidToHex($username);
  203. $filter = "objectguid=" . $username;
  204. }
  205. else if (strstr($username, "@")) {
  206. $filter = "userPrincipalName=" . $username;
  207. }
  208. else {
  209. $filter = "samaccountname=" . $username;
  210. }
  211. $filter = "(&(objectCategory=person)({$filter}))";
  212. if ($fields === NULL) {
  213. $fields = array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid","objectsid");
  214. }
  215. if (!in_array("objectsid", $fields)) {
  216. $fields[] = "objectsid";
  217. }
  218. $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
  219. $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
  220. if (isset($entries[0])) {
  221. if ($entries[0]['count'] >= 1) {
  222. if (in_array("memberof", $fields)) {
  223. // AD does not return the primary group in the ldap query, we may need to fudge it
  224. if ($this->adldap->getRealPrimaryGroup() && isset($entries[0]["primarygroupid"][0]) && isset($entries[0]["objectsid"][0])){
  225. //$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
  226. $entries[0]["memberof"][] = $this->adldap->group()->getPrimaryGroup($entries[0]["primarygroupid"][0], $entries[0]["objectsid"][0]);
  227. } else {
  228. $entries[0]["memberof"][] = "CN=Domain Users,CN=Users," . $this->adldap->getBaseDn();
  229. }
  230. if (!isset($entries[0]["memberof"]["count"])) {
  231. $entries[0]["memberof"]["count"] = 0;
  232. }
  233. $entries[0]["memberof"]["count"]++;
  234. }
  235. }
  236. return $entries;
  237. }
  238. return false;
  239. }
  240. /**
  241. * Find information about the users. Returned in a raw array format from AD
  242. *
  243. * @param string $username The username to query
  244. * @param array $fields Array of parameters to query
  245. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  246. * @return mixed
  247. */
  248. public function infoCollection($username, $fields = NULL, $isGUID = false)
  249. {
  250. if ($username === NULL) { return false; }
  251. if (!$this->adldap->getLdapBind()) { return false; }
  252. $info = $this->info($username, $fields, $isGUID);
  253. if ($info !== false) {
  254. $collection = new adLDAPUserCollection($info, $this->adldap);
  255. return $collection;
  256. }
  257. return false;
  258. }
  259. /**
  260. * Determine if a user is in a specific group
  261. *
  262. * @param string $username The username to query
  263. * @param string $group The name of the group to check against
  264. * @param bool $recursive Check groups recursively
  265. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  266. * @return bool
  267. */
  268. public function inGroup($username, $group, $recursive = NULL, $isGUID = false)
  269. {
  270. if ($username === NULL) { return false; }
  271. if ($group === NULL) { return false; }
  272. if (!$this->adldap->getLdapBind()) { return false; }
  273. if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it
  274. // Get a list of the groups
  275. $groups = $this->groups($username, $recursive, $isGUID);
  276. // Return true if the specified group is in the group list
  277. if (in_array($group, $groups)) {
  278. return true;
  279. }
  280. return false;
  281. }
  282. /**
  283. * Determine a user's password expiry date
  284. *
  285. * @param string $username The username to query
  286. * @param book $isGUID Is the username passed a GUID or a samAccountName
  287. * @requires bcmath http://php.net/manual/en/book.bc.php
  288. * @return array
  289. */
  290. public function passwordExpiry($username, $isGUID = false)
  291. {
  292. if ($username === NULL) { return "Missing compulsory field [username]"; }
  293. if (!$this->adldap->getLdapBind()) { return false; }
  294. if (!function_exists('bcmod')) { throw new adLDAPException("Missing function support [bcmod] http://php.net/manual/en/book.bc.php"); };
  295. $userInfo = $this->info($username, array("pwdlastset", "useraccountcontrol"), $isGUID);
  296. $pwdLastSet = $userInfo[0]['pwdlastset'][0];
  297. $status = array();
  298. if ($userInfo[0]['useraccountcontrol'][0] == '66048') {
  299. // Password does not expire
  300. return "Does not expire";
  301. }
  302. if ($pwdLastSet === '0') {
  303. // Password has already expired
  304. return "Password has expired";
  305. }
  306. // Password expiry in AD can be calculated from TWO values:
  307. // - User's own pwdLastSet attribute: stores the last time the password was changed
  308. // - Domain's maxPwdAge attribute: how long passwords last in the domain
  309. //
  310. // Although Microsoft chose to use a different base and unit for time measurements.
  311. // This function will convert them to Unix timestamps
  312. $sr = ldap_read($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), 'objectclass=*', array('maxPwdAge'));
  313. if (!$sr) {
  314. return false;
  315. }
  316. $info = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
  317. $maxPwdAge = $info[0]['maxpwdage'][0];
  318. // See MSDN: http://msdn.microsoft.com/en-us/library/ms974598.aspx
  319. //
  320. // pwdLastSet contains the number of 100 nanosecond intervals since January 1, 1601 (UTC),
  321. // stored in a 64 bit integer.
  322. //
  323. // The number of seconds between this date and Unix epoch is 11644473600.
  324. //
  325. // maxPwdAge is stored as a large integer that represents the number of 100 nanosecond
  326. // intervals from the time the password was set before the password expires.
  327. //
  328. // We also need to scale this to seconds but also this value is a _negative_ quantity!
  329. //
  330. // If the low 32 bits of maxPwdAge are equal to 0 passwords do not expire
  331. //
  332. // Unfortunately the maths involved are too big for PHP integers, so I've had to require
  333. // BCMath functions to work with arbitrary precision numbers.
  334. if (bcmod($maxPwdAge, 4294967296) === '0') {
  335. return "Domain does not expire passwords";
  336. }
  337. // Add maxpwdage and pwdlastset and we get password expiration time in Microsoft's
  338. // time units. Because maxpwd age is negative we need to subtract it.
  339. $pwdExpire = bcsub($pwdLastSet, $maxPwdAge);
  340. // Convert MS's time to Unix time
  341. $status['expiryts'] = bcsub(bcdiv($pwdExpire, '10000000'), '11644473600');
  342. $status['expiryformat'] = date('Y-m-d H:i:s', bcsub(bcdiv($pwdExpire, '10000000'), '11644473600'));
  343. return $status;
  344. }
  345. /**
  346. * Modify a user
  347. *
  348. * @param string $username The username to query
  349. * @param array $attributes The attributes to modify. Note if you set the enabled attribute you must not specify any other attributes
  350. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  351. * @return bool
  352. */
  353. public function modify($username, $attributes, $isGUID = false)
  354. {
  355. if ($username === NULL) { return "Missing compulsory field [username]"; }
  356. if (array_key_exists("password", $attributes) && !$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) {
  357. throw new adLDAPException('SSL/TLS must be configured on your webserver and enabled in the class to set passwords.');
  358. }
  359. // Find the dn of the user
  360. $userDn = $this->dn($username, $isGUID);
  361. if ($userDn === false) {
  362. return false;
  363. }
  364. // Translate the update to the LDAP schema
  365. $mod = $this->adldap->adldap_schema($attributes);
  366. // Check to see if this is an enabled status update
  367. if (!$mod && !array_key_exists("enabled", $attributes)){
  368. return false;
  369. }
  370. // Set the account control attribute (only if specified)
  371. if (array_key_exists("enabled", $attributes)){
  372. if ($attributes["enabled"]){
  373. $controlOptions = array("NORMAL_ACCOUNT");
  374. }
  375. else {
  376. $controlOptions = array("NORMAL_ACCOUNT", "ACCOUNTDISABLE");
  377. }
  378. $mod["userAccountControl"][0] = $this->accountControl($controlOptions);
  379. }
  380. // Do the update
  381. $result = @ldap_modify($this->adldap->getLdapConnection(), $userDn, $mod);
  382. if ($result == false) {
  383. return false;
  384. }
  385. return true;
  386. }
  387. /**
  388. * Disable a user account
  389. *
  390. * @param string $username The username to disable
  391. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  392. * @return bool
  393. */
  394. public function disable($username, $isGUID = false)
  395. {
  396. if ($username === NULL) { return "Missing compulsory field [username]"; }
  397. $attributes = array("enabled" => 0);
  398. $result = $this->modify($username, $attributes, $isGUID);
  399. if ($result == false) { return false; }
  400. return true;
  401. }
  402. /**
  403. * Enable a user account
  404. *
  405. * @param string $username The username to enable
  406. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  407. * @return bool
  408. */
  409. public function enable($username, $isGUID = false)
  410. {
  411. if ($username === NULL) { return "Missing compulsory field [username]"; }
  412. $attributes = array("enabled" => 1);
  413. $result = $this->modify($username, $attributes, $isGUID);
  414. if ($result == false) { return false; }
  415. return true;
  416. }
  417. /**
  418. * Set the password of a user - This must be performed over SSL
  419. *
  420. * @param string $username The username to modify
  421. * @param string $password The new password
  422. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  423. * @return bool
  424. */
  425. public function password($username, $password, $isGUID = false)
  426. {
  427. if ($username === NULL) { return false; }
  428. if ($password === NULL) { return false; }
  429. if (!$this->adldap->getLdapBind()) { return false; }
  430. if (!$this->adldap->getUseSSL() && !$this->adldap->getUseTLS()) {
  431. throw new adLDAPException('SSL must be configured on your webserver and enabled in the class to set passwords.');
  432. }
  433. $userDn = $this->dn($username, $isGUID);
  434. if ($userDn === false) {
  435. return false;
  436. }
  437. $add=array();
  438. $add["unicodePwd"][0] = $this->encodePassword($password);
  439. $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $add);
  440. if ($result === false){
  441. $err = ldap_errno($this->adldap->getLdapConnection());
  442. if ($err) {
  443. $msg = 'Error ' . $err . ': ' . ldap_err2str($err) . '.';
  444. if($err == 53) {
  445. $msg .= ' Your password might not match the password policy.';
  446. }
  447. throw new adLDAPException($msg);
  448. }
  449. else {
  450. return false;
  451. }
  452. }
  453. return true;
  454. }
  455. /**
  456. * Encode a password for transmission over LDAP
  457. *
  458. * @param string $password The password to encode
  459. * @return string
  460. */
  461. public function encodePassword($password)
  462. {
  463. $password="\"".$password."\"";
  464. $encoded="";
  465. for ($i=0; $i <strlen($password); $i++){ $encoded.="{$password[$i]}\000"; }
  466. return $encoded;
  467. }
  468. /**
  469. * Obtain the user's distinguished name based on their userid
  470. *
  471. *
  472. * @param string $username The username
  473. * @param bool $isGUID Is the username passed a GUID or a samAccountName
  474. * @return string
  475. */
  476. public function dn($username, $isGUID=false)
  477. {
  478. $user = $this->info($username, array("cn"), $isGUID);
  479. if ($user[0]["dn"] === NULL) {
  480. return false;
  481. }
  482. $userDn = $user[0]["dn"];
  483. return $userDn;
  484. }
  485. /**
  486. * Return a list of all users in AD
  487. *
  488. * @param bool $includeDescription Return a description of the user
  489. * @param string $search Search parameter
  490. * @param bool $sorted Sort the user accounts
  491. * @return array
  492. */
  493. public function all($includeDescription = false, $search = "*", $sorted = true)
  494. {
  495. if (!$this->adldap->getLdapBind()) { return false; }
  496. // Perform the search and grab all their details
  497. $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=" . $search . "))";
  498. $fields = array("samaccountname","displayname");
  499. $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
  500. $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
  501. $usersArray = array();
  502. for ($i=0; $i<$entries["count"]; $i++){
  503. if ($includeDescription && strlen($entries[$i]["displayname"][0])>0){
  504. $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
  505. } elseif ($includeDescription){
  506. $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
  507. } else {
  508. array_push($usersArray, $entries[$i]["samaccountname"][0]);
  509. }
  510. }
  511. if ($sorted) {
  512. Sort::asort($usersArray);
  513. }
  514. return $usersArray;
  515. }
  516. /**
  517. * Converts a username (samAccountName) to a GUID
  518. *
  519. * @param string $username The username to query
  520. * @return string
  521. */
  522. public function usernameToGuid($username)
  523. {
  524. if (!$this->adldap->getLdapBind()){ return false; }
  525. if ($username === null){ return "Missing compulsory field [username]"; }
  526. $filter = "samaccountname=" . $username;
  527. $fields = array("objectGUID");
  528. $sr = @ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
  529. if (ldap_count_entries($this->adldap->getLdapConnection(), $sr) > 0) {
  530. $entry = @ldap_first_entry($this->adldap->getLdapConnection(), $sr);
  531. $guid = @ldap_get_values_len($this->adldap->getLdapConnection(), $entry, 'objectGUID');
  532. $strGUID = $this->adldap->utilities()->binaryToText($guid[0]);
  533. return $strGUID;
  534. }
  535. return false;
  536. }
  537. /**
  538. * Return a list of all users in AD that have a specific value in a field
  539. *
  540. * @param bool $includeDescription Return a description of the user
  541. * @param string $searchField Field to search search for
  542. * @param string $searchFilter Value to search for in the specified field
  543. * @param bool $sorted Sort the user accounts
  544. * @return array
  545. */
  546. public function find($includeDescription = false, $searchField = false, $searchFilter = false, $sorted = true){
  547. if (!$this->adldap->getLdapBind()){ return false; }
  548. // Perform the search and grab all their details
  549. $searchParams = "";
  550. if ($searchField) {
  551. $searchParams = "(" . $searchField . "=" . $searchFilter . ")";
  552. }
  553. $filter = "(&(objectClass=user)(samaccounttype=" . adLDAP::ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)" . $searchParams . ")";
  554. $fields = array("samaccountname","displayname");
  555. $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
  556. $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
  557. $usersArray = array();
  558. for ($i=0; $i < $entries["count"]; $i++) {
  559. if ($includeDescription && strlen($entries[$i]["displayname"][0]) > 0) {
  560. $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["displayname"][0];
  561. }
  562. else if ($includeDescription) {
  563. $usersArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
  564. }
  565. else {
  566. array_push($usersArray, $entries[$i]["samaccountname"][0]);
  567. }
  568. }
  569. if ($sorted){
  570. Sort::asort($usersArray);
  571. }
  572. return ($usersArray);
  573. }
  574. /**
  575. * Move a user account to a different OU
  576. *
  577. * @param string $username The username to move (please be careful here!)
  578. * @param array $container The container or containers to move the user to (please be careful here!).
  579. * accepts containers in 1. parent 2. child order
  580. * @return array
  581. */
  582. public function move($username, $container)
  583. {
  584. if (!$this->adldap->getLdapBind()) { return false; }
  585. if ($username === null) { return "Missing compulsory field [username]"; }
  586. if ($container === null) { return "Missing compulsory field [container]"; }
  587. if (!is_array($container)) { return "Container must be an array"; }
  588. $userInfo = $this->info($username, array("*"));
  589. $dn = $userInfo[0]['distinguishedname'][0];
  590. $newRDn = "cn=" . $username;
  591. $container = array_reverse($container);
  592. $newContainer = "ou=" . implode(",ou=",$container);
  593. $newBaseDn = strtolower($newContainer) . "," . $this->adldap->getBaseDn();
  594. $result = @ldap_rename($this->adldap->getLdapConnection(), $dn, $newRDn, $newBaseDn, true);
  595. if ($result !== true) {
  596. return false;
  597. }
  598. return true;
  599. }
  600. /**
  601. * Get the last logon time of any user as a Unix timestamp
  602. *
  603. * @param string $username
  604. * @return long $unixTimestamp
  605. */
  606. public function getLastLogon($username) {
  607. if (!$this->adldap->getLdapBind()) { return false; }
  608. if ($username === null) { return "Missing compulsory field [username]"; }
  609. $userInfo = $this->info($username, array("lastLogonTimestamp"));
  610. $lastLogon = adLDAPUtils::convertWindowsTimeToUnixTime($userInfo[0]['lastLogonTimestamp'][0]);
  611. return $lastLogon;
  612. }
  613. }
  614. ?>