/** * Constructor. * * Fetches the Schema from an LDAP connection. * * @param Horde_Ldap $ldap LDAP connection. * @param string $dn Subschema entry DN. * * @throws Horde_Ldap_Exception */ public function __construct(Horde_Ldap $ldap, $dn = null) { if (is_null($dn)) { // Get the subschema entry via rootDSE. $dse = $ldap->rootDSE(array('subschemaSubentry')); $base = $dse->getValue('subschemaSubentry', 'single'); $dn = $base; } // Support for buggy LDAP servers (e.g. Siemens DirX 6.x) that // incorrectly call this entry subSchemaSubentry instead of // subschemaSubentry. Note the correct case/spelling as per RFC 2251. if (is_null($dn)) { // Get the subschema entry via rootDSE. $dse = $ldap->rootDSE(array('subSchemaSubentry')); $base = $dse->getValue('subSchemaSubentry', 'single'); $dn = $base; } // Final fallback in case there is no subschemaSubentry attribute in // the root DSE (this is a bug for an LDAPv3 server so report this to // your LDAP vendor if you get this far). if (is_null($dn)) { $dn = 'cn=Subschema'; } // Fetch the subschema entry. $result = $ldap->search($dn, '(objectClass=*)', array('attributes' => array_values($this->types), 'scope' => 'base')); $entry = $result->shiftEntry(); if (!$entry instanceof Horde_Ldap_Entry) { throw new Horde_Ldap_Exception('Could not fetch Subschema entry'); } $this->parse($entry); }
/** * Rebinds to the LDAP server. * * @param boolean $write Whether to rebind for write access. Use false * after finishing write actions. * * @throws Horde_Ldap_Exception */ protected function _rebind($write) { if ($write) { $this->_ldap->bind($this->_params['writedn'], $this->_params['writepw']); } else { $this->_ldap->bind(); } }
/** * Constructor. * * @param Horde_Kolab_Server_Connection $connection The LDAP connection. * @param string $base_dn The LDAP server base DN. * @param string $filter A global filter to add * to all queries. */ public function __construct(Horde_Kolab_Server_Connection_Interface $connection, $base_dn) { $this->_conn = $connection; $this->_base_dn = $base_dn; try { Horde_Ldap::checkLDAPExtension(); } catch (Horde_Ldap_Exception $e) { throw new Horde_Kolab_Server_Exception($e->getMessage(), Horde_Kolab_Server_Exception::MISSING_LDAP_EXTENSION, $e); } }
/** * Returns entries sorted as objects. * * This returns a array with sorted Horde_Ldap_Entry objects. The sorting * is actually done with {@link sortedAsArray()}. * * Please note that attribute names are case sensitive! * * Also note that it is (depending on server capabilities) possible to let * the server sort your results. This happens through search controls and * is described in detail at {@link http://www.ietf.org/rfc/rfc2891.txt} * * Usage example: * <code> * // To sort entries first by location, then by surname, but descending: * $entries = $search->sorted(array('locality', 'sn'), SORT_DESC); * </code> * * @todo Entry object construction could be faster. Maybe we could use one * of the factories instead of fetching the entry again. * * @param array $attrs Attribute names as sort criteria. * @param integer $order Ordering direction, either constant SORT_ASC or * SORT_DESC * * @return array Sorted entries. * @throws Horde_Ldap_Exception */ public function sorted($attrs = array('cn'), $order = SORT_ASC) { $return = array(); $sorted = $this->sortedAsArray($attrs, $order); foreach ($sorted as $row) { $entry = $this->_ldap->getEntry($row['dn'], $this->searchedAttributes()); $return[] = $entry; } return $return; }
/** * Returns the user account from the LDAP source. * * @return Horde_Ldap_Entry An entry with complete account details. * * @throws Horde_Exception if user not found. * @throws Horde_Ldap_Exception on LDAP errors. */ protected function _getAccount() { if (!isset($this->_information)) { $search = $this->_ldap->search($this->_params['basedn'], $this->_params['attr'] . '=' . $this->_params['user']); if (!$search->count()) { throw new Horde_Exception(_("User account not found")); } $this->_information = $search->shiftEntry(); } return $this->_information; }
/** * Sets the internal attributes array. * * This method fetches the values for the attributes from the server. The * attribute syntax will be checked so binary attributes will be returned * as binary values. * * Attributes may be passed directly via the $attributes parameter to setup * this entry manually. This overrides attribute fetching from the server. * * @param array $attributes Attributes to set for this entry. */ protected function _loadAttributes(array $attributes = null) { /* Fetch attributes from the server. */ if (is_null($attributes) && is_resource($this->_entry) && is_resource($this->_link)) { /* Fetch schema. */ if ($this->_ldap instanceof Horde_Ldap) { try { $schema = $this->_ldap->schema(); } catch (Horde_Ldap_Exception $e) { $schema = null; } } /* Fetch attributes. */ $attributes = array(); for ($attr = @ldap_first_attribute($this->_link, $this->_entry); $attr; $attr = @ldap_next_attribute($this->_link, $this->_entry)) { /* Standard function to fetch value. */ $func = 'ldap_get_values'; /* Try to get binary values as binary data. */ if ($schema instanceof Horde_Ldap_Schema && $schema->isBinary($attr)) { $func = 'ldap_get_values_len'; } /* Fetch attribute value (needs error checking?) . */ $attributes[$attr] = $func($this->_link, $this->_entry, $attr); } } /* Set attribute data directly, if passed. */ if (is_array($attributes) && count($attributes) > 0) { if (isset($attributes['count']) && is_numeric($attributes['count'])) { unset($attributes['count']); } foreach ($attributes as $k => $v) { /* Attribute names should not be numeric. */ if (is_numeric($k)) { continue; } /* Map generic attribute name to real one. */ $this->_map[Horde_String::lower($k)] = $k; /* Attribute values should be in an array. */ if (false == is_array($v)) { $v = array($v); } /* Remove the value count (comes from LDAP server). */ if (isset($v['count'])) { unset($v['count']); } $this->_attributes[$k] = $v; } } /* Save a copy for later use. */ $this->_original = $this->_attributes; }
public function setUp() { // Check extension. try { Horde_Ldap::checkLDAPExtension(); } catch (Horde_Ldap_Exception $e) { $this->markTestSkipped($e->getMessage()); } $config = $this->getConfig('LDAP_TEST_CONFIG'); if (!$config) { $this->markTestSkipped('No configuration for LDAP tests.'); } self::$ldapcfg = $config; }
/** * Stores user preferences in the backend. * * @param boolean $defaults Whether to store the global defaults instead * of user options. Unused. * * @throws Sam_Exception */ public function store($defaults = false) { $entry = array(); foreach ($this->_options as $a => $v) { $sa = $this->_mapAttributeToOption($a); if (is_array($v)) { foreach ($v as $av) { $entry[] = $sa . ' ' . $av; } } else { $entry[] = $sa . ' ' . $v; } } $userdn = sprintf('%s=%s,%s', $this->_params['uid'], $this->_user, $this->_params['basedn']); try { $this->_ldap->modify($userdn, array('replace' => array($this->_params['attribute'] => $entry))); } catch (Horde_Ldap_Exception $e) { throw new Sam_Exception($e); } }
/** * Checks if $userId exists in the LDAP backend system. * * @author Marco Ferrante, University of Genova (I) * * @param string $userId User ID for which to check * * @return boolean Whether or not $userId already exists. */ public function exists($userId) { $params = array('scope' => $this->_params['scope']); try { $uidfilter = Horde_Ldap_Filter::create($this->_params['uid'], 'equals', $userId); $classfilter = Horde_Ldap_Filter::build(array('filter' => $this->_params['filter'])); $search = $this->_ldap->search($this->_params['basedn'], Horde_Ldap_Filter::combine('and', array($uidfilter, $classfilter)), $params); if ($search->count() < 1) { return false; } if ($search->count() > 1 && $this->_logger) { $this->_logger->log('Multiple LDAP entries with user identifier ' . $userId, 'WARN'); } return true; } catch (Horde_Ldap_Exception $e) { if ($this->_logger) { $this->_logger->log('Error searching LDAP user: '******'ERR'); } return false; } }
/** * Lists all available scopes. * * @return array The list of scopes stored in the backend. */ public function listScopes() { $scopes = array(); try { $prefs = $this->_ldap->search($this->_prefsDN, Horde_Ldap_Filter::create('objectclass', 'equals', 'hordePerson'), array('attributes' => array('@hordePerson'), 'scope' => 'base', 'attrsonly' => true)); } catch (Horde_Ldap_Exception $e) { throw new Horde_Prefs_Exception($e); } if (!$prefs) { return $scopes; } foreach ($prefs->shiftEntry()->attributes() as $attr) { // Trim off prefs from attribute name to get scope (e.g. hordePrefs // -> horde). $scope = str_ireplace("prefs", "", $attr); // Skip non-prefs attributes like objectclass (no replacement // occurred above). if ($attr != $scope) { $scopes[] = $scope; } } return $scopes; }
/** * Constructor. * * Fetches a RootDSE object from an LDAP connection. * * @param Horde_Ldap $ldap Directory from which the RootDSE should be * fetched. * @param array $attrs Array of attributes to search for. * * @throws Horde_Ldap_Exception */ public function __construct(Horde_Ldap $ldap, $attrs = null) { if (is_array($attrs) && count($attrs)) { $attributes = $attrs; } else { $attributes = array('vendorName', 'vendorVersion', 'namingContexts', 'altServer', 'supportedExtension', 'supportedControl', 'supportedSASLMechanisms', 'supportedLDAPVersion', 'subschemaSubentry'); } $referral = $ldap->getOption('LDAP_OPT_REFERRALS'); $ldap->setOption('LDAP_OPT_REFERRALS', false); try { $result = $ldap->search('', '(objectClass=*)', array('attributes' => $attributes, 'scope' => 'base')); } catch (Horde_Ldap_Exception $e) { $ldap->setOption('LDAP_OPT_REFERRALS', $referral); throw $e; } $ldap->setOption('LDAP_OPT_REFERRALS', $referral); $entry = $result->shiftEntry(); if (!$entry) { throw new Horde_Ldap_Exception('Could not fetch RootDSE entry'); } $this->_entry = $entry; }
/** * Returns the syntax of an attribute, if necessary recursively. * * @param string $att Attribute name. * * @return string Attribute syntax. * @throws Turba_Exception */ protected function _getSyntax($att) { $ldap = new Horde_Ldap($this->_convertParameters($this->_params)); $schema = $ldap->schema(); if (!isset($this->_syntaxCache[$att])) { $attv = $schema->get('attribute', $att); $this->_syntaxCache[$att] = isset($attv['syntax']) ? $attv['syntax'] : $this->_getSyntax($attv['sup'][0]); } return $this->_syntaxCache[$att]; }
/** * Renames or moves an entry. * * This method will instantly carry out an update() after the * move, so the entry is moved instantly. * * You can pass an optional Horde_Ldap object. In this case, a * cross directory move will be performed which deletes the entry * in the source (THIS) directory and adds it in the directory * $target_ldap. * * A cross directory move will switch the entry's internal LDAP * reference so updates to the entry will go to the new directory. * * If you want to do a cross directory move, you need to pass an * Horde_Ldap_Entry object, otherwise the attributes will be * empty. * * @param string|Horde_Ldap_Entry $entry An LDAP entry. * @param string $newdn The new location. * @param Horde_Ldap $target_ldap Target directory for cross * server move. * * @throws Horde_Ldap_Exception */ public function move($entry, $newdn, $target_ldap = null) { if (is_string($entry)) { if ($target_ldap && $target_ldap !== $this) { throw new Horde_Ldap_Exception('Unable to perform cross directory move: operation requires a Horde_Ldap_Entry object'); } $entry = $this->getEntry($entry); } if (!$entry instanceof Horde_Ldap_Entry) { throw new Horde_Ldap_Exception('Parameter $entry is expected to be a Horde_Ldap_Entry object! (If DN was passed, conversion failed)'); } if ($target_ldap && !$target_ldap instanceof Horde_Ldap) { throw new Horde_Ldap_Exception('Parameter $target_ldap is expected to be a Horde_Ldap object!'); } if (!$target_ldap || $target_ldap === $this) { /* Local move. */ $entry->dn($newdn); $entry->setLDAP($this); $entry->update(); return; } /* Cross directory move. */ if ($target_ldap->exists($newdn)) { throw new Horde_Ldap_Exception('Unable to perform cross directory move: entry does exist in target directory'); } $entry->dn($newdn); try { $target_ldap->add($entry); } catch (Exception $e) { throw new Horde_Ldap_Exception('Unable to perform cross directory move: ' . $e->getMessage() . ' in target directory'); } try { $this->delete($entry->currentDN()); } catch (Exception $e) { try { $add_error_string = ''; /* Undo add. */ $target_ldap->delete($entry); } catch (Exception $e) { $add_error_string = ' Additionally, the deletion (undo add) of $entry in target directory failed.'; } throw new Horde_Ldap_Exception('Unable to perform cross directory move: ' . $e->getMessage() . ' in source directory.' . $add_error_string); } $entry->setLDAP($target_ldap); }
/** * Tests SPL iterator. */ public function testSPLIterator() { $ldap = new Horde_Ldap(self::$ldapcfg['server']); // Some testdata, so we have some entries to search for. $base = self::$ldapcfg['server']['basedn']; $ou1 = Horde_Ldap_Entry::createFresh('ou=Horde_Ldap_Test_search1,' . $base, array('objectClass' => array('top', 'organizationalUnit'), 'ou' => 'Horde_Ldap_Test_search1')); $ou2 = Horde_Ldap_Entry::createFresh('ou=Horde_Ldap_Test_search2,' . $base, array('objectClass' => array('top', 'organizationalUnit'), 'ou' => 'Horde_Ldap_Test_search2')); $ldap->add($ou1); $this->assertTrue($ldap->exists($ou1->dn())); $ldap->add($ou2); $this->assertTrue($ldap->exists($ou2->dn())); /* Search and test each method. */ $search = $ldap->search(null, '(ou=Horde_Ldap*)'); $this->assertInstanceOf('Horde_Ldap_Search', $search); $this->assertEquals(2, $search->count()); // current() is supposed to return first valid element. $e1 = $search->current(); $this->assertInstanceOf('Horde_Ldap_Entry', $e1); $this->assertEquals($e1->dn(), $search->key()); $this->assertTrue($search->valid()); // Shift to next entry. $search->next(); $e2 = $search->current(); $this->assertInstanceOf('Horde_Ldap_Entry', $e2); $this->assertEquals($e2->dn(), $search->key()); $this->assertTrue($search->valid()); // Shift to non existent third entry. $search->next(); $this->assertFalse($search->current()); $this->assertFalse($search->key()); $this->assertFalse($search->valid()); // Rewind and test, which should return the first entry a second time. $search->rewind(); $e1_1 = $search->current(); $this->assertInstanceOf('Horde_Ldap_Entry', $e1_1); $this->assertEquals($e1_1->dn(), $search->key()); $this->assertTrue($search->valid()); $this->assertEquals($e1->dn(), $e1_1->dn()); // Don't rewind but call current, should return first entry again. $e1_2 = $search->current(); $this->assertInstanceOf('Horde_Ldap_Entry', $e1_2); $this->assertEquals($e1_2->dn(), $search->key()); $this->assertTrue($search->valid()); $this->assertEquals($e1->dn(), $e1_2->dn()); // Rewind again and test, which should return the first entry a third // time. $search->rewind(); $e1_3 = $search->current(); $this->assertInstanceOf('Horde_Ldap_Entry', $e1_3); $this->assertEquals($e1_3->dn(), $search->key()); $this->assertTrue($search->valid()); $this->assertEquals($e1->dn(), $e1_3->dn()); /* Try methods on empty search result. */ $search = $ldap->search(null, '(ou=Horde_LdapTest_NotExistentEntry)'); $this->assertInstanceOf('Horde_Ldap_Search', $search); $this->assertEquals(0, $search->count()); $this->assertFalse($search->current()); $this->assertFalse($search->key()); $this->assertFalse($search->valid()); $search->next(); $this->assertFalse($search->current()); $this->assertFalse($search->key()); $this->assertFalse($search->valid()); /* Search and simple iterate through the test entries. Then, rewind * and do it again several times. */ $search2 = $ldap->search(null, '(ou=Horde_Ldap*)'); $this->assertInstanceOf('Horde_Ldap_Search', $search2); $this->assertEquals(2, $search2->count()); for ($i = 0; $i <= 5; $i++) { $counter = 0; foreach ($search2 as $dn => $entry) { $counter++; // Check on type. $this->assertInstanceOf('Horde_Ldap_Entry', $entry); // Check on key. $this->assertThat(strlen($dn), $this->greaterThan(1)); $this->assertEquals($dn, $entry->dn()); } $this->assertEquals($search2->count(), $counter, "Failed at loop {$i}"); // Revert to start. $search2->rewind(); } }
public function testQuoteDN() { $this->assertEquals('cn=John Smith,dc=example,dc=com', Horde_Ldap::quoteDN(array(array('cn', 'John Smith'), array('dc', 'example'), array('dc', 'com')))); $this->assertEquals('cn=John+sn=Smith+o=Acme Inc.,dc=example,dc=com', Horde_Ldap::quoteDN(array(array(array('cn', 'John'), array('sn', 'Smith'), array('o', 'Acme Inc.')), array('dc', 'example'), array('dc', 'com')))); $this->assertEquals('cn=John+sn=Smith+o=Acme Inc.', Horde_Ldap::quoteDN(array(array(array('cn', 'John'), array('sn', 'Smith'), array('o', 'Acme Inc.'))))); }