[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/authad/adLDAP/classes/ -> adLDAPGroups.php (source)

   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 Groups
  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/adLDAPGroupCollection.php');
  39  
  40  use dokuwiki\Utf8\Sort;
  41  
  42  /**
  43  * GROUP FUNCTIONS
  44  */
  45  class adLDAPGroups {
  46      /**
  47      * The current adLDAP connection via dependency injection
  48      * 
  49      * @var adLDAP
  50      */
  51      protected $adldap;
  52      
  53      public function __construct(adLDAP $adldap) {
  54          $this->adldap = $adldap;
  55      }
  56      
  57      /**
  58      * Add a group to a group
  59      * 
  60      * @param string $parent The parent group name
  61      * @param string $child The child group name
  62      * @return bool
  63      */
  64      public function addGroup($parent,$child){
  65  
  66          // Find the parent group's dn
  67          $parentGroup = $this->ginfo($parent, array("cn"));
  68          if ($parentGroup[0]["dn"] === NULL){
  69              return false; 
  70          }
  71          $parentDn = $parentGroup[0]["dn"];
  72          
  73          // Find the child group's dn
  74          $childGroup = $this->info($child, array("cn"));
  75          if ($childGroup[0]["dn"] === NULL){ 
  76              return false; 
  77          }
  78          $childDn = $childGroup[0]["dn"];
  79                  
  80          $add = array();
  81          $add["member"] = $childDn;
  82          
  83          $result = @ldap_mod_add($this->adldap->getLdapConnection(), $parentDn, $add);
  84          if ($result == false) { 
  85              return false; 
  86          }
  87          return true;
  88      }
  89      
  90      /**
  91      * Add a user to a group
  92      * 
  93      * @param string $group The group to add the user to
  94      * @param string $user The user to add to the group
  95      * @param bool $isGUID Is the username passed a GUID or a samAccountName
  96      * @return bool
  97      */
  98      public function addUser($group, $user, $isGUID = false)
  99      {
 100          // Adding a user is a bit fiddly, we need to get the full DN of the user
 101          // and add it using the full DN of the group
 102          
 103          // Find the user's dn
 104          $userDn = $this->adldap->user()->dn($user, $isGUID);
 105          if ($userDn === false) { 
 106              return false; 
 107          }
 108          
 109          // Find the group's dn
 110          $groupInfo = $this->info($group, array("cn"));
 111          if ($groupInfo[0]["dn"] === NULL) { 
 112              return false; 
 113          }
 114          $groupDn = $groupInfo[0]["dn"];
 115          
 116          $add = array();
 117          $add["member"] = $userDn;
 118          
 119          $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
 120          if ($result == false) { 
 121              return false; 
 122          }
 123          return true;
 124      }
 125      
 126      /**
 127      * Add a contact to a group
 128      * 
 129      * @param string $group The group to add the contact to
 130      * @param string $contactDn The DN of the contact to add
 131      * @return bool
 132      */
 133      public function addContact($group, $contactDn)
 134      {
 135          // To add a contact we take the contact's DN
 136          // and add it using the full DN of the group
 137          
 138          // Find the group's dn
 139          $groupInfo = $this->info($group, array("cn"));
 140          if ($groupInfo[0]["dn"] === NULL) { 
 141              return false; 
 142          }
 143          $groupDn = $groupInfo[0]["dn"];
 144          
 145          $add = array();
 146          $add["member"] = $contactDn;
 147          
 148          $result = @ldap_mod_add($this->adldap->getLdapConnection(), $groupDn, $add);
 149          if ($result == false) { 
 150              return false; 
 151          }
 152          return true;
 153      }
 154  
 155      /**
 156      * Create a group
 157      * 
 158      * @param array $attributes Default attributes of the group
 159      * @return bool
 160      */
 161      public function create($attributes)
 162      {
 163          if (!is_array($attributes)){ return "Attributes must be an array"; }
 164          if (!array_key_exists("group_name", $attributes)){ return "Missing compulsory field [group_name]"; }
 165          if (!array_key_exists("container", $attributes)){ return "Missing compulsory field [container]"; }
 166          if (!array_key_exists("description", $attributes)){ return "Missing compulsory field [description]"; }
 167          if (!is_array($attributes["container"])){ return "Container attribute must be an array."; }
 168          $attributes["container"] = array_reverse($attributes["container"]);
 169  
 170          //$member_array = array();
 171          //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
 172          //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
 173          
 174          $add = array();
 175          $add["cn"] = $attributes["group_name"];
 176          $add["samaccountname"] = $attributes["group_name"];
 177          $add["objectClass"] = "Group";
 178          $add["description"] = $attributes["description"];
 179          //$add["member"] = $member_array; UNTESTED
 180  
 181          $container = "OU=" . implode(",OU=", $attributes["container"]);
 182          $result = ldap_add($this->adldap->getLdapConnection(), "CN=" . $add["cn"] . ", " . $container . "," . $this->adldap->getBaseDn(), $add);
 183          if ($result != true) { 
 184              return false; 
 185          }
 186          return true;
 187      }
 188      
 189      /**
 190      * Delete a group account 
 191      * 
 192      * @param string $group The group to delete (please be careful here!) 
 193      * 
 194      * @return array 
 195      */
 196      public function delete($group) {
 197          if (!$this->adldap->getLdapBind()){ return false; }
 198          if ($group === null){ return "Missing compulsory field [group]"; }
 199          
 200          $groupInfo = $this->info($group, array("*"));
 201          $dn = $groupInfo[0]['distinguishedname'][0]; 
 202          $result = $this->adldap->folder()->delete($dn); 
 203          if ($result !== true) { 
 204              return false; 
 205          } return true;   
 206      }
 207  
 208      /**
 209      * Remove a group from a group
 210      * 
 211      * @param string $parent The parent group name
 212      * @param string $child The child group name
 213      * @return bool
 214      */
 215      public function removeGroup($parent , $child)
 216      {
 217      
 218          // Find the parent dn
 219          $parentGroup = $this->info($parent, array("cn"));
 220          if ($parentGroup[0]["dn"] === NULL) { 
 221              return false; 
 222          }
 223          $parentDn = $parentGroup[0]["dn"];
 224          
 225          // Find the child dn
 226          $childGroup = $this->info($child, array("cn"));
 227          if ($childGroup[0]["dn"] === NULL) { 
 228              return false; 
 229          }
 230          $childDn = $childGroup[0]["dn"];
 231          
 232          $del = array();
 233          $del["member"] = $childDn;
 234          
 235          $result = @ldap_mod_del($this->adldap->getLdapConnection(), $parentDn, $del);
 236          if ($result == false) { 
 237              return false; 
 238          }
 239          return true;
 240      }
 241      
 242      /**
 243      * Remove a user from a group
 244      * 
 245      * @param string $group The group to remove a user from
 246      * @param string $user The AD user to remove from the group
 247      * @param bool $isGUID Is the username passed a GUID or a samAccountName
 248      * @return bool
 249      */
 250      public function removeUser($group, $user, $isGUID = false)
 251      {
 252      
 253          // Find the parent dn
 254          $groupInfo = $this->info($group, array("cn"));
 255          if ($groupInfo[0]["dn"] === NULL){ 
 256              return false; 
 257          }
 258          $groupDn = $groupInfo[0]["dn"];
 259          
 260          // Find the users dn
 261          $userDn = $this->adldap->user()->dn($user, $isGUID);
 262          if ($userDn === false) {
 263              return false; 
 264          }
 265  
 266          $del = array();
 267          $del["member"] = $userDn;
 268          
 269          $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
 270          if ($result == false) {
 271              return false; 
 272          }
 273          return true;
 274      }
 275      
 276      /**
 277      * Remove a contact from a group
 278      * 
 279      * @param string $group The group to remove a user from
 280      * @param string $contactDn The DN of a contact to remove from the group
 281      * @return bool
 282      */
 283      public function removeContact($group, $contactDn)
 284      {
 285      
 286          // Find the parent dn
 287          $groupInfo = $this->info($group, array("cn"));
 288          if ($groupInfo[0]["dn"] === NULL) { 
 289              return false; 
 290          }
 291          $groupDn = $groupInfo[0]["dn"];
 292      
 293          $del = array();
 294          $del["member"] = $contactDn;
 295          
 296          $result = @ldap_mod_del($this->adldap->getLdapConnection(), $groupDn, $del);
 297          if ($result == false) { 
 298              return false; 
 299          }
 300          return true;
 301      }
 302      
 303      /**
 304      * Return a list of groups in a group
 305      * 
 306      * @param string $group The group to query
 307      * @param bool $recursive Recursively get groups
 308      * @return array
 309      */
 310      public function inGroup($group, $recursive = NULL)
 311      {
 312          if (!$this->adldap->getLdapBind()){ return false; }
 313          if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
 314          
 315          // Search the directory for the members of a group
 316          $info = $this->info($group, array("member","cn"));
 317          $groups = $info[0]["member"];
 318          if (!is_array($groups)) {
 319              return false;   
 320          }
 321   
 322          $groupArray = array();
 323  
 324          for ($i=0; $i<$groups["count"]; $i++){ 
 325               $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";
 326               $fields = array("samaccountname", "distinguishedname", "objectClass");
 327               $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 328               $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 329  
 330               // not a person, look for a group  
 331               if ($entries['count'] == 0 && $recursive == true) {  
 332                  $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($groups[$i]) . "))";  
 333                  $fields = array("distinguishedname");  
 334                  $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
 335                  $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
 336                  if (!isset($entries[0]['distinguishedname'][0])) {
 337                      continue;  
 338                  }
 339                  $subGroups = $this->inGroup($entries[0]['distinguishedname'][0], $recursive);  
 340                  if (is_array($subGroups)) {
 341                      $groupArray = array_merge($groupArray, $subGroups); 
 342                      $groupArray = array_unique($groupArray);  
 343                  }
 344                  continue;  
 345               } 
 346  
 347               $groupArray[] = $entries[0]['distinguishedname'][0];
 348          }
 349          return $groupArray;
 350      }
 351      
 352      /**
 353      * Return a list of members in a group
 354      * 
 355      * @param string $group The group to query
 356      * @param bool $recursive Recursively get group members
 357      * @return array
 358      */
 359      public function members($group, $recursive = NULL)
 360      {
 361          if (!$this->adldap->getLdapBind()){ return false; }
 362          if ($recursive === NULL){ $recursive = $this->adldap->getRecursiveGroups(); } // Use the default option if they haven't set it 
 363          // Search the directory for the members of a group
 364          $info = $this->info($group, array("member","cn"));
 365          $users = $info[0]["member"];
 366          if (!is_array($users)) {
 367              return false;   
 368          }
 369   
 370          $userArray = array();
 371  
 372          for ($i=0; $i<$users["count"]; $i++){ 
 373               $filter = "(&(objectCategory=person)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";
 374               $fields = array("samaccountname", "distinguishedname", "objectClass");
 375               $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 376               $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 377  
 378               // not a person, look for a group  
 379               if ($entries['count'] == 0 && $recursive == true) {  
 380                  $filter = "(&(objectCategory=group)(distinguishedName=" . $this->adldap->utilities()->ldapSlashes($users[$i]) . "))";  
 381                  $fields = array("samaccountname");  
 382                  $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);  
 383                  $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);  
 384                  if (!isset($entries[0]['samaccountname'][0])) {
 385                      continue;  
 386                  }
 387                  $subUsers = $this->members($entries[0]['samaccountname'][0], $recursive);  
 388                  if (is_array($subUsers)) {
 389                      $userArray = array_merge($userArray, $subUsers); 
 390                      $userArray = array_unique($userArray);  
 391                  }
 392                  continue;  
 393               } 
 394               else if ($entries['count'] == 0) {   
 395                  continue; 
 396               } 
 397  
 398               if ((!isset($entries[0]['samaccountname'][0]) || $entries[0]['samaccountname'][0] === NULL) && $entries[0]['distinguishedname'][0] !== NULL) {
 399                   $userArray[] = $entries[0]['distinguishedname'][0];
 400               }
 401               else if ($entries[0]['samaccountname'][0] !== NULL) {
 402                  $userArray[] = $entries[0]['samaccountname'][0];
 403               }
 404          }
 405          return $userArray;
 406      }
 407      
 408      /**
 409      * Group Information.  Returns an array of raw information about a group.
 410      * The group name is case sensitive
 411      * 
 412      * @param string $groupName The group name to retrieve info about
 413      * @param array $fields Fields to retrieve
 414      * @return array
 415      */
 416      public function info($groupName, $fields = NULL)
 417      {
 418          if ($groupName === NULL) { return false; }
 419          if (!$this->adldap->getLdapBind()) { return false; }
 420          
 421          if (stristr($groupName, '+')) {
 422              $groupName = stripslashes($groupName);   
 423          }
 424          
 425          $filter = "(&(objectCategory=group)(name=" . $this->adldap->utilities()->ldapSlashes($groupName) . "))";
 426          if ($fields === NULL) { 
 427              $fields = array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); 
 428          }
 429          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 430          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 431  
 432          return $entries;
 433      }
 434      
 435      /**
 436      * Group Information.  Returns an collection
 437      * The group name is case sensitive
 438      * 
 439      * @param string $groupName The group name to retrieve info about
 440      * @param array $fields Fields to retrieve
 441      * @return adLDAPGroupCollection
 442      */
 443      public function infoCollection($groupName, $fields = NULL)
 444      {
 445          if ($groupName === NULL) { return false; }
 446          if (!$this->adldap->getLdapBind()) { return false; }
 447          
 448          $info = $this->info($groupName, $fields);
 449          if ($info !== false) {
 450              $collection = new adLDAPGroupCollection($info, $this->adldap);
 451              return $collection;
 452          }
 453          return false;
 454      }
 455      
 456      /**
 457      * Return a complete list of "groups in groups"
 458      * 
 459      * @param string $group The group to get the list from
 460      * @return array
 461      */
 462      public function recursiveGroups($group)
 463      {
 464          if ($group === NULL) { return false; }
 465  
 466          $stack = array(); 
 467          $processed = array(); 
 468          $retGroups = array(); 
 469       
 470          array_push($stack, $group); // Initial Group to Start with 
 471          while (count($stack) > 0) {
 472              $parent = array_pop($stack);
 473              array_push($processed, $parent);
 474              
 475              $info = $this->info($parent, array("memberof"));
 476              
 477              if (isset($info[0]["memberof"]) && is_array($info[0]["memberof"])) {
 478                  $groups = $info[0]["memberof"]; 
 479                  if ($groups) {
 480                      $groupNames = $this->adldap->utilities()->niceNames($groups);  
 481                      $retGroups = array_merge($retGroups, $groupNames); //final groups to return
 482                      foreach ($groupNames as $id => $groupName) { 
 483                          if (!in_array($groupName, $processed)) {
 484                              array_push($stack, $groupName);
 485                          }
 486                      }
 487                  }
 488              }
 489          }
 490          
 491          return $retGroups;
 492      }
 493      
 494      /**
 495      * Returns a complete list of the groups in AD based on a SAM Account Type  
 496      * 
 497      * @param string $sAMAaccountType The account type to return
 498      * @param bool $includeDescription Whether to return a description
 499      * @param string $search Search parameters
 500      * @param bool $sorted Whether to sort the results
 501      * @return array
 502      */
 503      public function search($sAMAaccountType = adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription = false, $search = "*", $sorted = true) {
 504          if (!$this->adldap->getLdapBind()) { return false; }
 505          
 506          $filter = '(&(objectCategory=group)';
 507          if ($sAMAaccountType !== null) {
 508              $filter .= '(samaccounttype='. $sAMAaccountType .')';
 509          }
 510          $filter .= '(cn=' . $search . '))';
 511          // Perform the search and grab all their details
 512          $fields = array("samaccountname", "description");
 513          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 514          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 515  
 516          $groupsArray = array();        
 517          for ($i=0; $i<$entries["count"]; $i++){
 518              if ($includeDescription && strlen($entries[$i]["description"][0]) > 0 ) {
 519                  $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["description"][0];
 520              }
 521              else if ($includeDescription){
 522                  $groupsArray[$entries[$i]["samaccountname"][0]] = $entries[$i]["samaccountname"][0];
 523              }
 524              else {
 525                  array_push($groupsArray, $entries[$i]["samaccountname"][0]);
 526              }
 527          }
 528          if ($sorted) { 
 529              Sort::asort($groupsArray); 
 530          }
 531          return $groupsArray;
 532      }
 533      
 534      /**
 535      * Returns a complete list of all groups in AD
 536      * 
 537      * @param bool $includeDescription Whether to return a description
 538      * @param string $search Search parameters
 539      * @param bool $sorted Whether to sort the results
 540      * @return array
 541      */
 542      public function all($includeDescription = false, $search = "*", $sorted = true){
 543          $groupsArray = $this->search(null, $includeDescription, $search, $sorted);
 544          return $groupsArray;
 545      }
 546      
 547      /**
 548      * Returns a complete list of security groups in AD
 549      * 
 550      * @param bool $includeDescription Whether to return a description
 551      * @param string $search Search parameters
 552      * @param bool $sorted Whether to sort the results
 553      * @return array
 554      */
 555      public function allSecurity($includeDescription = false, $search = "*", $sorted = true){
 556          $groupsArray = $this->search(adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP, $includeDescription, $search, $sorted);
 557          return $groupsArray;
 558      }
 559      
 560      /**
 561      * Returns a complete list of distribution lists in AD
 562      * 
 563      * @param bool $includeDescription Whether to return a description
 564      * @param string $search Search parameters
 565      * @param bool $sorted Whether to sort the results
 566      * @return array
 567      */
 568      public function allDistribution($includeDescription = false, $search = "*", $sorted = true){
 569          $groupsArray = $this->search(adLDAP::ADLDAP_DISTRIBUTION_GROUP, $includeDescription, $search, $sorted);
 570          return $groupsArray;
 571      }
 572      
 573      /**
 574      * Coping with AD not returning the primary group
 575      * http://support.microsoft.com/?kbid=321360 
 576      * 
 577      * This is a re-write based on code submitted by Bruce which prevents the 
 578      * need to search each security group to find the true primary group
 579      * 
 580      * @param string $gid Group ID
 581      * @param string $usersid User's Object SID
 582      * @return mixed
 583      */
 584      public function getPrimaryGroup($gid, $usersid)
 585      {
 586          if ($gid === NULL || $usersid === NULL) { return false; }
 587          $sr = false;
 588  
 589          $gsid = substr_replace($usersid, pack('V',$gid), strlen($usersid)-4,4);
 590          $filter = '(objectsid=' . $this->adldap->utilities()->getTextSID($gsid).')';
 591          $fields = array("samaccountname","distinguishedname");
 592          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 593          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 594  
 595          if (isset($entries[0]['distinguishedname'][0])) {
 596              return $entries[0]['distinguishedname'][0];
 597          }
 598          return false;
 599       }
 600       
 601       /**
 602      * Coping with AD not returning the primary group
 603      * http://support.microsoft.com/?kbid=321360 
 604      * 
 605      * For some reason it's not possible to search on primarygrouptoken=XXX
 606      * If someone can show otherwise, I'd like to know about it :)
 607      * this way is resource intensive and generally a pain in the @#%^
 608      * 
 609      * @deprecated deprecated since version 3.1, see get get_primary_group
 610      * @param string $gid Group ID
 611      * @return string
 612      */
 613      public function cn($gid){    
 614          if ($gid === NULL) { return false; }
 615          $sr = false;
 616          $r = '';
 617          
 618          $filter = "(&(objectCategory=group)(samaccounttype=" . adLDAP::ADLDAP_SECURITY_GLOBAL_GROUP . "))";
 619          $fields = array("primarygrouptoken", "samaccountname", "distinguishedname");
 620          $sr = ldap_search($this->adldap->getLdapConnection(), $this->adldap->getBaseDn(), $filter, $fields);
 621          $entries = ldap_get_entries($this->adldap->getLdapConnection(), $sr);
 622          
 623          for ($i=0; $i<$entries["count"]; $i++){
 624              if ($entries[$i]["primarygrouptoken"][0] == $gid) {
 625                  $r = $entries[$i]["distinguishedname"][0];
 626                  $i = $entries["count"];
 627              }
 628          }
 629  
 630          return $r;
 631      }
 632  }
 633  ?>