Last active
December 4, 2015 02:44
-
-
Save grom358/4ef0f1db6bf807144816 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class LDAP_Connection { | |
protected $ds; | |
protected $baseDN; | |
protected $hostname; | |
protected $port; | |
protected $binaryFields; | |
private $isConnected; | |
public function __construct($config = null) { | |
global $LDAP_DEFAULT_CONFIG; | |
if (!isset($config)) { | |
$config = $LDAP_DEFAULT_CONFIG; | |
} | |
$this->hostname = $config['hostname']; | |
if (strlen($this->hostname) > 8 && substr($this->hostname, 0, 8) == 'ldaps://') { | |
$defaultPort = 636; | |
} else { | |
$defaultPort = 389; | |
} | |
$this->port = isset($config['port']) ? $config['port'] : $defaultPort; | |
$this->ds = ldap_connect($this->hostname, $this->port); | |
if (!$this->ds) { | |
// Connections to fedora directory don't fail till binding | |
$this->ds = null; | |
throw new LDAP_Exception("Could not connect to " . $this->hostname . ':' . $this->port, -1); | |
} | |
$this->setOptions(); | |
// Bind as anonymous to test connection | |
if (!@ldap_bind($this->ds)) { | |
$this->ds = null; | |
throw new LDAP_Exception("Could not connect to " . $this->hostname . ':' . $this->port, -1); | |
} | |
$this->baseDN = $config['baseDN']; | |
$this->binaryFields = isset($config['binaryFields']) ? $config['binaryFields'] : array(); | |
$this->isConnected = true; | |
} | |
protected function setOptions() { | |
ldap_set_option($this->ds, LDAP_OPT_PROTOCOL_VERSION, 3); | |
} | |
public function __destruct() { | |
$this->disconnect(); | |
} | |
protected function checkForError() { | |
LDAP_Exception::checkForLdapError($this->ds); | |
} | |
public function bind($user, $password) { | |
$this->bindDN('uid=' . $user . ',' . $this->baseDN, $password); | |
} | |
public function bindAsDirectoryManager() { | |
$this->bindDN(LDAP_DIRECTORY_MANAGER_DN, LDAP_DIRECTORY_MANAGER_PASSWORD); | |
} | |
public function bindDN($bindDN, $password) { | |
if (!@ldap_bind($this->ds, $bindDN, $password)) { | |
$errorCode = ldap_errno($this->ds); | |
if ($errorCode == 32) { | |
throw new LDAP_Exception("Unable to bind as " . $bindDN, $errorCode); | |
} elseif ($errorCode == -1) { | |
// It appears a connection to fedora directory doesn't occur till you attempt to bind | |
throw new LDAP_Exception("Could not connect to " . $this->hostname . ':' . $this->port, $errorCode); | |
} else { | |
$this->checkForError(); | |
} | |
} | |
} | |
public function search($filter, $attributes = array(), $searchRDN = null) { | |
if ($filter instanceof LDAP_Filter) { | |
$filter = $filter->filter; | |
} | |
$searchDN = $this->baseDN; | |
if ($searchRDN) { | |
$searchDN = $searchRDN . ',' . $this->baseDN; | |
} | |
$sr = @ldap_search($this->ds, $searchDN, $filter, $attributes); | |
$this->checkForError(); | |
return new LDAP_SearchResults($this->ds, $this->baseDN, $sr, $this->binaryFields); | |
} | |
/** | |
* | |
* Returns null if there is no such record | |
*/ | |
public function read($rdn, $attributes = array()) { | |
$dn = $rdn . ',' . $this->baseDN; | |
$data = LDAP_Utils::getEntry($this->ds, $dn, $attributes, $this->binaryFields); | |
if ($data == null) { | |
return null; | |
} | |
if (array_key_exists('nsRole', $data)) { | |
$data['roles'] = LDAP_Utils::getRoles($this->ds, $data); | |
} | |
return new LDAP_Entry($this->ds, $rdn, $dn, $data); | |
} | |
public function add($rdn, $data) { | |
$dn = $rdn . ',' . $this->baseDN; | |
@ldap_add($this->ds, $dn, $data); | |
$this->checkForError(); | |
} | |
public function delete($rdn) { | |
$dn = $rdn . ',' . $this->baseDN; | |
@ldap_delete($this->ds, $dn); | |
$this->checkForError(); | |
} | |
public function rename($oldRDN, $newRDN, $newParent = null, $deleteOldDN = false) { | |
$oldDN = $oldRDN . ',' . $this->baseDN; | |
if ($newParent == null) { | |
$newParent = LDAP_Utils::getParent($oldDN); | |
} else { | |
$newParent .= ',' . $this->baseDN; | |
} | |
@ldap_rename($this->ds, $oldDN, $newRDN, $newParent, $deleteOldDN); | |
$this->checkForError(); | |
} | |
public function move($oldRDN, $newRDN) { | |
$oldDN = $oldRDN . ',' . $this->baseDN; | |
$newDN = $newRDN . ',' . $this->baseDN; | |
$parent = LDAP_Utils::getParent($oldDN); | |
$topRDN = LDAP_Utils::getRDN($newDN, $parent); | |
@ldap_rename($this->ds, $oldDN, $topRDN, $parent, false); | |
$this->checkForError(); | |
} | |
/** | |
* Shortcut for adding attributes | |
*/ | |
public function addAttributes($rdn, $data) { | |
$dn = $rdn . ',' . $this->baseDN; | |
@ldap_mod_add($this->ds, $dn, $data); | |
$this->checkForError(); | |
} | |
/** | |
* Shortcut for replacing attributes | |
*/ | |
public function replaceAttributes($rdn, $data) { | |
$dn = $rdn . ',' . $this->baseDN; | |
@ldap_mod_replace($this->ds, $dn, $data); | |
$this->checkForError(); | |
} | |
/** | |
* Shortcut for deleting attributes | |
*/ | |
public function deleteAttributes($rdn, $data) { | |
$dn = $rdn . ',' . $this->baseDN; | |
@ldap_mod_del($this->ds, $dn, $data); | |
$this->checkForError(); | |
} | |
public function disconnect() { | |
if ($this->isConnected) { | |
ldap_close($this->ds); | |
} | |
$this->isConnected = false; | |
} | |
} | |
class LDAP_Filter { | |
public $filter; | |
static public function create($filter = 'objectclass=*') { | |
$builder = new LDAP_Filter('(' . $filter . ')'); | |
return $builder; | |
} | |
private function __construct($filter) { | |
$this->filter = $filter; | |
} | |
public function and_($filter) { | |
if (is_a($filter, 'LDAP_Filter')) { | |
$this->filter = '(&' . $this->filter . $filter->filter . ')'; | |
} else { | |
$this->filter = '(&' . $this->filter . '(' . $filter . '))'; | |
} | |
return $this; | |
} | |
public function or_($filter) { | |
if (is_a($filter, 'LDAP_Filter')) { | |
$this->filter = '(|' . $this->filter . $filter->filter . ')'; | |
} else { | |
$this->filter = '(|' . $this->filter . '(' . $filter . '))'; | |
} | |
return $this; | |
} | |
static private function _not($filter) { | |
return '!(' . $filter . ')'; | |
} | |
static public function not($filter) { | |
return new LDAP_Filter('(' . self::_not($filter) . ')'); | |
} | |
public function andNot($filter) { | |
return $this->and_(self::_not($filter)); | |
} | |
public function orNot($filter) { | |
return $this->or_(self::_not($filter)); | |
} | |
} | |
class LDAP_SearchResults { | |
protected $ds; | |
protected $baseDN; | |
protected $sr; | |
protected $binaryFields; | |
protected $entryID = null; | |
public function __construct($ds, $baseDN, $sr, $binaryFields) { | |
$this->ds = $ds; | |
$this->baseDN = $baseDN; | |
$this->sr = $sr; | |
$this->binaryFields = $binaryFields; | |
} | |
public function next() { | |
if ($this->entryID === null) { | |
$this->entryID = ldap_first_entry($this->ds, $this->sr); | |
} else { | |
$this->entryID = ldap_next_entry($this->ds, $this->entryID); | |
} | |
if (!$this->entryID) { | |
return null; | |
} | |
$data = LDAP_Utils::readEntry($this->ds, $this->entryID, $this->binaryFields); | |
if (array_key_exists('nsRole', $data)) { | |
$data['roles'] = LDAP_Utils::getRoles($this->ds, $data); | |
} | |
$dn = ldap_get_dn($this->ds, $this->entryID); | |
$rdn = LDAP_Utils::getRDN($dn, $this->baseDN); | |
return new LDAP_Entry($this->ds, $rdn, $dn, $data); | |
} | |
public function count() { | |
return ldap_count_entries($this->ds, $this->sr); | |
} | |
public function sort($sortBy) { | |
if (is_array($sortBy)) { | |
$sortAttributes = array_reverse($sortBy); | |
foreach ($sortAttributes as $sortAttr) { | |
ldap_sort($this->ds, $this->sr, $sortAttr); | |
} | |
} else { | |
ldap_sort($this->ds, $this->sr, $sortBy); | |
} | |
} | |
public function getAll($dataOnly = false, $includeDN = true) { | |
$results = array(); | |
while ($entry = $this->next()) { | |
if ($dataOnly) { | |
if ($includeDN) { | |
$results[] = array_merge(array('rdn' => $entry->rdn, 'dn' => $entry->dn), $entry->data); | |
} else { | |
$results[] = $entry->data; | |
} | |
} else { | |
$results[] = $entry; | |
} | |
} | |
return $results; | |
} | |
public function getCol($columnName = null) { | |
$results = array(); | |
while ($entry = $this->next()) { | |
if ($columnName == null) { | |
$columnName = key($entry->data); | |
} | |
$results[] = $entry->data[$columnName]; | |
} | |
return $results; | |
} | |
public function getAssoc($idColumnName = null, $valueColumnName = null) { | |
$results = array(); | |
while ($entry = $this->next()) { | |
if ($idColumnName == null) { | |
$idColumnName = key($entry->data); | |
} | |
if ($valueColumnName == null) { | |
$keys = array_keys($entry->data); | |
$valueColumnName = $keys[1]; | |
} | |
$results[$entry->data[$idColumnName]] = $entry->data[$valueColumnName]; | |
} | |
return $results; | |
} | |
} | |
class LDAP_Entry { | |
protected $ds; | |
public $rdn; | |
public $dn; | |
public $dnAttribute; | |
public $data; | |
protected $oldData; | |
public function __construct($ds, $rdn, $dn, $data) { | |
$this->ds = $ds; | |
$this->rdn = $rdn; | |
$this->dn = $dn; | |
$this->data = $data; | |
$this->oldData = $data; | |
$exploded_dn = ldap_explode_dn($dn, 0); | |
$top_dn = explode('=', $exploded_dn[0]); | |
$this->dnAttribute = strtolower($top_dn[0]); | |
} | |
protected function checkForError() { | |
LDAP_Exception::checkForLdapError($this->ds); | |
} | |
public function deleteAttribute($attributeName) { | |
@ldap_mod_del($this->ds, $this->dn, array($attributeName => array())); | |
$this->checkForError(); | |
unset($this->oldData[$attributeName]); | |
unset($this->data[$attributeName]); | |
} | |
public function update() { | |
// Update LDAP entry | |
$add = array(); $replace = array(); $delete = array(); | |
$renameTo = null; | |
foreach ($this->data as $key => $val) { | |
if ($key == $this->dnAttribute && $val !== $this->oldData[$key]) { | |
$renameTo = $val; | |
} elseif (array_key_exists($key, $this->oldData)) { | |
if ($val == null) { | |
$delete[$key] = array(); | |
} elseif ($val !== $this->oldData[$key]) { | |
$replace[$key] = $val; | |
} | |
} elseif ($val != null) { | |
$add[$key] = $val; | |
} | |
} | |
if (count($add) > 0) { | |
@ldap_mod_add($this->ds, $this->dn, $add); | |
$this->checkForError(); | |
} | |
if (count($replace) > 0) { | |
@ldap_mod_replace($this->ds, $this->dn, $replace); | |
$this->checkForError(); | |
} | |
if (count($delete) > 0) { | |
@ldap_mod_del($this->ds, $this->dn, $delete); | |
$this->checkForError(); | |
} | |
if ($renameTo) { | |
$topRDN = $this->dnAttribute . '=' . $renameTo; | |
$parent = LDAP_Utils::getParent($this->dn); | |
@ldap_rename($this->ds, $this->dn, $topRDN, $parent, true); | |
$this->checkForError(); | |
$this->rdn = $topRDN . ',' . LDAP_Utils::getParent($this->rdn); | |
$this->dn = $topRDN . ',' . $parent; | |
} | |
} | |
} | |
class LDAP_Utils { | |
/** | |
* Take an LDAP entry and make an associative array from it. | |
* | |
* This function takes an LDAP entry in the ldap_get_entries() style and | |
* converts it to an associative array like ldap_add() needs. | |
* | |
* @param array $entry is the entry that should be converted. | |
* | |
* @return array is the converted entry. | |
*/ | |
static public function cleanUpEntry( &$entry ) { | |
$retEntry = array(); | |
for ( $i = 0; $i < $entry['count']; $i++ ) { | |
$attribute = $entry[$i]; | |
if ( $entry[$attribute]['count'] == 1 ) { | |
$retEntry[$attribute] = $entry[$attribute][0]; | |
} else { | |
for ( $j = 0; $j < $entry[$attribute]['count']; $j++ ) { | |
$retEntry[$attribute][] = $entry[$attribute][$j]; | |
} | |
} | |
} | |
return $retEntry; | |
} | |
static public function readEntry($ds, $entryId, $binaryFields = array()) { | |
$data = array(); | |
for ($attribute = ldap_first_attribute($ds, $entryId, $attributeId); $attribute !== false; $attribute = ldap_next_attribute($ds, $entryId, $attributeId)) { | |
$fieldValues = ldap_get_values($ds, $entryId, $attribute); | |
if (in_array($attribute, $binaryFields)) { | |
$fieldValues = ldap_get_values_len($ds, $entryId, $attribute); | |
} | |
if ($fieldValues['count'] == 1) { | |
$data[$attribute] = $fieldValues[0]; | |
} else { | |
for ($i = 0; $i < $fieldValues['count']; $i++) { | |
$data[$attribute][$i] = $fieldValues[$i]; | |
} | |
} | |
} | |
return $data; | |
} | |
static public function getEntry($ds, $dn, $attributes = array(), $binaryFields = array()) { | |
$sr = @ldap_read($ds, $dn, '(objectclass=*)', $attributes); | |
if (!$sr) { | |
return null; | |
} | |
$entryID = ldap_first_entry($ds, $sr); | |
$entry = self::readEntry($ds, $entryID, $binaryFields); | |
return $entry; | |
} | |
static public function getParent($dn) { | |
$exploded_dn = ldap_explode_dn($dn, 0); | |
$path = array(); | |
for ($i = 1; $i < $exploded_dn['count']; $i++) { | |
$path[] = $exploded_dn[$i]; | |
} | |
return implode(',', $path); | |
} | |
/** | |
* Test wether object class exists in objectclass attribute | |
*/ | |
static public function hasClass($class, $ldapClasses) { | |
if (in_array($class, $ldapClasses) || in_array(strtolower($class), $ldapClasses)) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Extract out the roles from LDAP entry | |
*/ | |
static public function getRoles( &$ds, &$ldap_entry ) { | |
$roles = array(); | |
if (!$ldap_entry['nsRole'] ) { | |
return $roles; | |
} | |
if (!is_array($ldap_entry['nsRole'])) { | |
$ldap_entry['nsRole'] = array($ldap_entry['nsRole']); | |
} | |
foreach ($ldap_entry['nsRole'] as $dn) { | |
$sr = ldap_read($ds, $dn, '(objectClass=*)', array('cn')); | |
$entryId = ldap_first_entry($ds, $sr); | |
$entry = self::cleanUpEntry(ldap_get_attributes($ds, $entryId)); | |
$roles[] = $entry['cn']; | |
} | |
return $roles; | |
} | |
static public function getRDN($dn, $baseDN) { | |
return substr($dn, 0, strlen($dn) - strlen($baseDN) - 1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment