Copyright 2003-2007 Tarjej Huse, Jan Wagner, Del Elson, Benedikt Hallinger Copyright 2009-2016 Horde LLC (http://www.horde.org/)
Автор: Tarjej Huse (tarjei@bergfald.no)
Автор: Jan Wagner (wagner@netsols.de)
Автор: Del (del@babel.com.au)
Автор: Benedikt Hallinger (beni@php.net)
Автор: Ben Klang (ben@alkaloid.net)
Автор: Chuck Hagenbuch (chuck@horde.org)
Автор: Jan Schneider (jan@horde.org)
Пример #1
0
 /**
  * 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);
 }
Пример #2
0
 /**
  * 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();
     }
 }
Пример #3
0
 /**
  * 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);
     }
 }
Пример #4
0
 /**
  * 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;
 }
Пример #5
0
 /**
  * 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;
 }
Пример #6
0
 /**
  * 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;
 }
Пример #7
0
 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;
 }
Пример #8
0
 /**
  * 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);
     }
 }
Пример #9
0
 /**
  * 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;
     }
 }
Пример #10
0
 /**
  * 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;
 }
Пример #11
0
 /**
  * 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;
 }
Пример #12
0
 /**
  * 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];
 }
Пример #13
0
 /**
  * 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);
 }
Пример #14
0
 /**
  * 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();
     }
 }
Пример #15
0
 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.')))));
 }