/** * Update the entry on the directory server * * This will evaluate all changes made so far and send them * to the directory server. * Please note, that if you make changes to objectclasses wich * have mandatory attributes set, update() will currently fail. * Remove the entry from the server and readd it as new in such cases. * This also will deal with problems with setting structural object classes. * * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance * * @access public * @return true|Net_LDAP2_Error * @todo Entry rename with a DN containing special characters needs testing! */ public function update($ldap = null) { if ($ldap) { $msg = $this->setLDAP($ldap); if (Net_LDAP2::isError($msg)) { return PEAR::raiseError('You passed an invalid $ldap variable to update()'); } } // ensure we have a valid LDAP object $ldap =& $this->getLDAP(); if (!$ldap instanceof Net_LDAP2) { return PEAR::raiseError("The entries LDAP object is not valid"); } // Get and check link $link = $ldap->getLink(); if (!is_resource($link)) { return PEAR::raiseError("Could not update entry: internal LDAP link is invalid"); } /* * Delete the entry */ if (true === $this->_delete) { return $ldap->delete($this); } /* * New entry */ if (true === $this->_new) { $msg = $ldap->add($this); if (Net_LDAP2::isError($msg)) { return $msg; } $this->_new = false; $this->_changes['add'] = array(); $this->_changes['delete'] = array(); $this->_changes['replace'] = array(); $this->_original = $this->_attributes; $return = true; return $return; } /* * Rename/move entry */ if (false == is_null($this->_newdn)) { if ($ldap->getLDAPVersion() !== 3) { return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3"); } // make dn relative to parent (needed for ldap rename) $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (Net_LDAP2::isError($parent)) { return $parent; } $child = array_shift($parent); // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $child-RDN is an array! if (is_array($child)) { $child = Net_LDAP2_Util::canonical_dn($child); } $parent = Net_LDAP2_Util::canonical_dn($parent); // rename/move if (false == @ldap_rename($link, $this->_dn, $child, $parent, true)) { return PEAR::raiseError("Entry not renamed: " . @ldap_error($link), @ldap_errno($link)); } // reflect changes to local copy $this->_dn = $this->_newdn; $this->_newdn = null; } /* * Carry out modifications to the entry */ // ADD foreach ($this->_changes["add"] as $attr => $value) { // if attribute exists, add new values if ($this->exists($attr)) { if (false === @ldap_mod_add($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not add new values to attribute {$attr}: " . @ldap_error($link), @ldap_errno($link)); } } else { // new attribute if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not add new attribute {$attr}: " . @ldap_error($link), @ldap_errno($link)); } } // all went well here, I guess unset($this->_changes["add"][$attr]); } // DELETE foreach ($this->_changes["delete"] as $attr => $value) { // In LDAPv3 you need to specify the old values for deleting if (is_null($value) && $ldap->getLDAPVersion() === 3) { $value = $this->_original[$attr]; } if (false === @ldap_mod_del($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not delete attribute {$attr}: " . @ldap_error($link), @ldap_errno($link)); } unset($this->_changes["delete"][$attr]); } // REPLACE foreach ($this->_changes["replace"] as $attr => $value) { if (false === @ldap_modify($link, $this->dn(), array($attr => $value))) { return PEAR::raiseError("Could not replace attribute {$attr} values: " . @ldap_error($link), @ldap_errno($link)); } unset($this->_changes["replace"][$attr]); } // all went well, so _original (server) becomes _attributes (local copy) $this->_original = $this->_attributes; $return = true; return $return; }
/** * Writes a DN to the filehandle * * @param string $dn DN to write * * @access protected * @return void */ protected function writeDN($dn) { // prepare DN if ($this->_options['encode'] == 'base64') { $dn = $this->convertDN($dn) . PHP_EOL; } elseif ($this->_options['encode'] == 'canonical') { $dn = Net_LDAP2_Util::canonical_dn($dn, array('casefold' => 'none')) . PHP_EOL; } else { $dn = $dn . PHP_EOL; } $this->writeLine($dn, 'Net_LDAP2_LDIF error: unable to write DN of entry ' . $this->_entrynum); }
/** * Tells if a DN does exist in the directory * * @param string|Net_LDAP2_Entry $dn The DN of the object to test * * @return boolean|Net_LDAP2_Error */ public function dnExists($dn) { if (PEAR::isError($dn)) { return $dn; } if ($dn instanceof Net_LDAP2_Entry) { $dn = $dn->dn(); } if (false === is_string($dn)) { return PEAR::raiseError('Parameter $dn is not a string nor an entry object!'); } // make dn relative to parent $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (self::isError($base)) { return $base; } $entry_rdn = array_shift($base); if (is_array($entry_rdn)) { // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $entry_rdn is an array! $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn); } $base = Net_LDAP2_Util::canonical_dn($base); $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1); if (@ldap_count_entries($this->_link, $result)) { return true; } if (ldap_errno($this->_link) == 32) { return false; } if (ldap_errno($this->_link) != 0) { return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); } return false; }
/** * Retrieve this leaf-filters attribute, match and value component. * * For leaf filters, this returns array(attr, match, value). * Match is be the logical operator, not the text representation, * eg "=" instead of "equals". Note that some operators are really * a combination of operator+value with wildcard, like * "begins": That will return "=" with the value "value*"! * * For non-leaf filters this will drop an error. * * @todo $this->_match is not always available and thus not usable here; it would be great if it would set in the factory methods and constructor. * @return array|Net_LDAP2_Error */ function getComponents() { if ($this->isLeaf()) { $raw_filter = preg_replace('/^\\(|\\)$/', '', $this->_filter); $parts = Net_LDAP2_Util::split_attribute_string($raw_filter, true, true); if (count($parts) != 3) { return PEAR::raiseError("Net_LDAP2_Filter getComponents() error: invalid filter syntax - unknown matching rule used"); } else { return $parts; } } else { return PEAR::raiseError('Net_LDAP2_Filter getComponents() call is invalid for non-leaf filters!'); } }
/** * This can be used to escape a string to provide a valid LDAP-Filter. * * LDAP will only recognise certain characters as the * character istself if they are properly escaped. This is * what this method does. * The method can be called statically, so you can use it outside * for your own purposes (eg for escaping only parts of strings) * * In fact, this is just a shorthand to {@link Net_LDAP2_Util::escape_filter_value()}. * For upward compatibiliy reasons you are strongly encouraged to use the escape * methods provided by the Net_LDAP2_Util class. * * @param string $value Any string who should be escaped * * @static * @return string The string $string, but escaped * @deprecated Do not use this method anymore, instead use Net_LDAP2_Util::escape_filter_value() directly */ public static function escape($value) { $return = Net_LDAP2_Util::escape_filter_value(array($value)); return $return[0]; }
/** * Update the entry on the directory server * * This will evaluate all changes made so far and send them * to the directory server. * Please note, that if you make changes to objectclasses wich * have mandatory attributes set, update() will currently fail. * Remove the entry from the server and readd it as new in such cases. * This also will deal with problems with setting structural object classes. * * @param Net_LDAP2 $ldap If passed, a call to setLDAP() is issued prior update, thus switching the LDAP-server. This is for perl-ldap interface compliance * * @access public * @return true|Net_LDAP2_Error * @todo Entry rename with a DN containing special characters needs testing! */ public function update($ldap = null) { if ($ldap) { $msg = $this->setLDAP($ldap); if (Net_LDAP2::isError($msg)) { return PEAR::raiseError('You passed an invalid $ldap variable to update()'); } } // ensure we have a valid LDAP object $ldap = $this->getLDAP(); if (!$ldap instanceof Net_LDAP2) { return PEAR::raiseError("The entries LDAP object is not valid"); } // Get and check link $link = $ldap->getLink(); if (!is_resource($link)) { return PEAR::raiseError("Could not update entry: internal LDAP link is invalid"); } /* * Delete the entry */ if (true === $this->_delete) { return $ldap->delete($this); } /* * New entry */ if (true === $this->_new) { $msg = $ldap->add($this); if (Net_LDAP2::isError($msg)) { return $msg; } $this->_new = false; $this->_changes['add'] = array(); $this->_changes['delete'] = array(); $this->_changes['replace'] = array(); $this->_original = $this->_attributes; // In case the "new" entry was moved after creation, we must // adjust the internal DNs as the entry was already created // with the most current DN. if (false == is_null($this->_newdn)) { $this->_dn = $this->_newdn; $this->_newdn = null; } $return = true; return $return; } /* * Rename/move entry */ if (false == is_null($this->_newdn)) { if ($ldap->getLDAPVersion() !== 3) { return PEAR::raiseError("Renaming/Moving an entry is only supported in LDAPv3"); } // make dn relative to parent (needed for ldap rename) $parent = Net_LDAP2_Util::ldap_explode_dn($this->_newdn, array('casefolding' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (Net_LDAP2::isError($parent)) { return $parent; } $child = array_shift($parent); // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $child-RDN is an array! if (is_array($child)) { $child = Net_LDAP2_Util::canonical_dn($child); } $parent = Net_LDAP2_Util::canonical_dn($parent); // rename/move if (false == @ldap_rename($link, $this->_dn, $child, $parent, false)) { return PEAR::raiseError("Entry not renamed: " . @ldap_error($link), @ldap_errno($link)); } // reflect changes to local copy $this->_dn = $this->_newdn; $this->_newdn = null; } /* * Retrieve a entry that has all attributes we need so that the list of changes to build is created accurately */ $fullEntry = $ldap->getEntry($this->dn()); if (Net_LDAP2::isError($fullEntry)) { return PEAR::raiseError("Could not retrieve a full set of attributes to reconcile changes with"); } $modifications = array(); // ADD foreach ($this->_changes["add"] as $attr => $value) { // if attribute exists, we need to combine old and new values if ($fullEntry->exists($attr)) { $currentValue = $fullEntry->getValue($attr, "all"); $value = array_merge($currentValue, $value); } $modifications[$attr] = $value; } // DELETE foreach ($this->_changes["delete"] as $attr => $value) { // In LDAPv3 you need to specify the old values for deleting if (is_null($value) && $ldap->getLDAPVersion() === 3) { $value = $fullEntry->getValue($attr); } if (!is_array($value)) { $value = array($value); } // Find out what is missing from $value and exclude it $currentValue = isset($modifications[$attr]) ? $modifications[$attr] : $fullEntry->getValue($attr, "all"); $modifications[$attr] = array_values(array_diff($currentValue, $value)); } // REPLACE foreach ($this->_changes["replace"] as $attr => $value) { $modifications[$attr] = $value; } // COMMIT if (false === @ldap_modify($link, $this->dn(), $modifications)) { return PEAR::raiseError("Could not modify the entry: " . @ldap_error($link), @ldap_errno($link)); } // all went well, so _original (server) becomes _attributes (local copy), reset _changes too... $this->_changes['add'] = array(); $this->_changes['delete'] = array(); $this->_changes['replace'] = array(); $this->_original = $this->_attributes; $return = true; return $return; }
/** * Tell if a DN does exist in the directory * * @param string $dn The DN of the object to test * * @return boolean|Net_LDAP2_Error */ public function dnExists($dn) { if (!is_string($dn)) { return PEAR::raiseError('$dn is expected to be a string but is ' . gettype($dn) . ' ' . get_class($dn)); } // make dn relative to parent $base = Net_LDAP2_Util::ldap_explode_dn($dn, array('casefold' => 'none', 'reverse' => false, 'onlyvalues' => false)); if (self::isError($base)) { return $base; } $entry_rdn = array_shift($base); if (is_array($entry_rdn)) { // maybe the dn consist of a multivalued RDN, we must build the dn in this case // because the $entry_rdn is an array! $filter_dn = Net_LDAP2_Util::canonical_dn($entry_rdn); } $base = Net_LDAP2_Util::canonical_dn($base); $result = @ldap_list($this->_link, $base, $entry_rdn, array(), 1, 1); if (@ldap_count_entries($this->_link, $result)) { return true; } if (ldap_errno($this->_link) == 32) { return false; } if (ldap_errno($this->_link) != 0) { return PEAR::raiseError(ldap_error($this->_link), ldap_errno($this->_link)); } return false; }
/** * Test if split_attribute_string() works */ public function testSplitAttributeString() { // test default behavour $this->assertEquals(array('fooAttr', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr=barValue")); $this->assertEquals(array('fooAttr', '=barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr==barValue")); $this->assertEquals(array('fooAttr', 'bar=Value'), Net_LDAP2_Util::split_attribute_string("fooAttr=bar=Value")); $this->assertEquals(array('foo\\=Attr', 'barValue'), Net_LDAP2_Util::split_attribute_string("foo\\=Attr=barValue")); $this->assertEquals(array('fooAttr', 'bar\\=Value'), Net_LDAP2_Util::split_attribute_string("fooAttr=bar\\=Value")); // test default behaviour with delim $this->assertEquals(array('fooAttr', '=', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr=barValue", false, true)); $this->assertEquals(array('fooAttr', '=', '=barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr==barValue", false, true)); $this->assertEquals(array('fooAttr', '=', 'bar=Value'), Net_LDAP2_Util::split_attribute_string("fooAttr=bar=Value", false, true)); $this->assertEquals(array('foo\\=Attr', '=', 'barValue'), Net_LDAP2_Util::split_attribute_string("foo\\=Attr=barValue", false, true)); // test basic extended splitting and delimter return $test_delimeters = array('=', '~=', '>', '>=', '<', '<='); foreach ($test_delimeters as $td) { // default behavior with simple parameters $this->assertEquals(array('fooAttr', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr{$td}barValue", true), "AttrString='fooAttr{$td}barValue'; sep='{$td}'"); $this->assertEquals(array('fooAttr', 'barValue'), Net_LDAP2_Util::split_attribute_string("fooAttr{$td}barValue", true, false)); // test proper escaping $tde = addcslashes($td, '=~><'); $this->assertEquals(array("foo{$tde}Attr", 'barValue'), Net_LDAP2_Util::split_attribute_string("foo{$tde}Attr{$td}barValue", true)); } // negative test case: perform no split $this->assertEquals(array('fooAttr barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr barValue')); $this->assertEquals(array('fooAttr barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr barValue', true, true)); $this->assertEquals(array('fooAttr>barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr>barValue')); // extended splitting used, but not activated // negative testcase: wrong escaping used $this->assertEquals(array('fooAttr\\>', 'barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr\\>=barValue', false, false)); $this->assertEquals(array('fooAttr\\>', '=', 'barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr\\>=barValue', true, true)); $this->assertEquals(array('fooAttr', '>', '\\=barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr>\\=barValue', true, true)); $this->assertEquals(array('fooAttr\\>\\=barValue'), Net_LDAP2_Util::split_attribute_string('fooAttr\\>\\=barValue', true, true)); }
/** * Execute a LDAP query stement and fetch all results. * * @param mixed $query The SQL query as a string or an array. * @param string $configPath The config path; used for exception messages. * * @return array An array of records. * @throws XML_Query2XML_LDAP2Exception If Net_LDAP2::search() returns an error. * @see XML_Query2XML_Driver::getAllRecords() */ public function getAllRecords($query, $configPath) { $base = null; $filter = null; $options = array(); if (isset($query['base'])) { $base = $query['base']; } if (isset($query['filter'])) { $filter = $query['filter']; } if (isset($query['options'])) { $options = $query['options']; } if (isset($options['query2xml_placeholder'])) { $placeholder = $options['query2xml_placeholder']; } else { $placeholder = '?'; } unset($options['query2xml_placeholder']); if (isset($query['data']) && is_array($query['data'])) { $data = Net_LDAP2_Util::escape_filter_value($query['data']); $base = self::_replacePlaceholders($base, $data, $placeholder); if (is_string($filter)) { $filter = self::_replacePlaceholders($filter, $data, $placeholder); } } $search = $this->_ldap->search($base, $filter, $options); if (PEAR::isError($search)) { /* * unit test: getXML/throwLDAPException_queryError.phpt */ throw new XML_Query2XML_LDAP2Exception($configPath . ': Could not run LDAP search query: ' . $search->toString()); } $records = array(); $entries = $search->entries(); foreach ($entries as $key => $entry) { $records[] = $entry->getValues(); } $search->done(); $records = self::_processMultiValueAttributes($records); // set missing attriubtes to null if (isset($options['attributes']) && is_array($options['attributes'])) { foreach ($options['attributes'] as $attribute) { for ($i = 0; $i < count($records); $i++) { if (!array_key_exists($attribute, $records[$i])) { $records[$i][$attribute] = null; } } } } return $records; }
/** * Main Authentication method * Required for plugin interface * @param unknown $login User's username * @param unknown $password User's password * @return boolean */ function authenticate($login, $password) { if ($login && $password) { if (!function_exists('ldap_connect')) { trigger_error('auth_ldap requires PHP\'s PECL LDAP package installed.'); return FALSE; } if (!(require_once 'Net/LDAP2.php')) { trigger_error('auth_ldap requires the PEAR package Net::LDAP2'); return FALSE; } /** Loading configuration **/ $this->_debugMode = defined('LDAP_AUTH_DEBUG') ? LDAP_AUTH_DEBUG : FALSE; $this->_anonBeforeBind = defined('LDAP_AUTH_ANONYMOUSBEFOREBIND') ? LDAP_AUTH_ANONYMOUSBEFOREBIND : FALSE; $this->_serviceBindDN = defined('LDAP_AUTH_BINDDN') ? LDAP_AUTH_BINDDN : null; $this->_serviceBindPass = defined('LDAP_AUTH_BINDPW') ? LDAP_AUTH_BINDPW : null; $this->_baseDN = defined('LDAP_AUTH_BASEDN') ? LDAP_AUTH_BASEDN : null; if (!defined('LDAP_AUTH_BASEDN')) { $this->_log('LDAP_AUTH_BASEDN is required and not defined.', E_USER_ERROR); return FALSE; } else { $this->_baseDN = LDAP_AUTH_BASEDN; } $parsedURI = parse_url(LDAP_AUTH_SERVER_URI); if ($parsedURI === FALSE) { $this->_log('Could not parse LDAP_AUTH_SERVER_URI in config.php', E_USER_ERROR); return FALSE; } $this->_host = $parsedURI['host']; $this->_scheme = $parsedURI['scheme']; if (is_int($parsedURI['port'])) { $this->_port = $parsedURI['port']; } else { $this->_port = $this->_scheme === 'ldaps' ? 636 : 389; } $this->_useTLS = defined('LDAP_AUTH_USETLS') ? LDAP_AUTH_USETLS : FALSE; $this->_allowUntrustedCerts = defined('LDAP_AUTH_ALLOW_UNTRUSTED_CERT') ? LDAP_AUTH_ALLOW_UNTRUSTED_CERT : FALSE; $this->_schemaCacheEnable = defined('LDAP_AUTH_SCHEMA_CACHE_ENABLE') ? LDAP_AUTH_SCHEMA_CACHE_ENABLE : TRUE; $this->_schemaCacheTimeout = defined('LDAP_AUTH_SCHEMA_CACHE_TIMEOUT') ? LDAP_AUTH_SCHEMA_CACHE_TIMEOUT : 86400; $this->_logAttempts = defined('LDAP_AUTH_LOG_ATTEMPTS') ? LDAP_AUTH_LOG_ATTEMPTS : FALSE; $this->_ldapLoginAttrib = defined('LDAP_AUTH_LOGIN_ATTRIB') ? LDAP_AUTH_LOGIN_ATTRIB : null; /** Building LDAP connection **/ $ldapConnParams = array('host' => $this->_scheme . '://' . $this->_host, 'options' => array('LDAP_OPT_REFERRALS' => 0), 'basedn' => $this->_baseDN, 'port' => $this->_port, 'starttls' => $this->_useTLS); if (!$this->_anonBeforeBind) { $ldapConnParams['binddn'] = $this->_serviceBindDN; $ldapConnParams['bindpw'] = $this->_serviceBindPass; } if ($this->_allowUntrustedCerts) { putenv('LDAPTLS_REQCERT=never'); } if ($this->_debugMode) { $this->_log(print_r($ldapConnParams, TRUE), E_USER_NOTICE); } $ldapConn = Net_LDAP2::connect($ldapConnParams); if (get_class($ldapConn) !== 'Net_LDAP2') { $this->_log('Could not connect to LDAP Server: ' . $ldapConn->getMessage() . ' with ' . $this->_getBindDNWord(), E_USER_ERROR); return FALSE; } else { $this->ldapObj = $ldapConn; $this->_log('Connected to LDAP Server: ' . LDAP_AUTH_SERVER_URI . ' with ' . $this->_getBindDNWord()); } // Bind with service account if orignal connexion was anonymous if ($this->_anonBeforeBind && strlen($this->_bindDN > 0)) { $binding = $this->ldapObj->bind($this->_serviceBindDN, $this->_serviceBindPass); if (get_class($binding) !== 'Net_LDAP2') { $this->_log('Cound not bind service account: ' . $binding->getMessage(), E_USER_ERROR); return FALSE; } else { $this->_log('Bind with ' . $this->_serviceBindDN . ' successful.', E_USER_NOTICE); } } //Cache LDAP Schema if ($ldapSchemaCacheEnable) { $this->_getSchemaCache(); } //Validate BaseDN $baseDNObj = $this->ldapObj->getEntry($this->_baseDN); if (get_class($baseDNObj) !== 'Net_LDAP2_Entry') { $this->_log('Cound not get LDAP_AUTH_BASEDN. Please check config.php', E_USER_ERROR); //return FALSE; } //Searching for user $escapedUserName = Net_LDAP2_Util::escape_filter_value(array($login)); $completedSearchFilter = str_replace('???', $escapedUserName[0], LDAP_AUTH_SEARCHFILTER); $filterObj = Net_LDAP2_Filter::parse($completedSearchFilter); if (get_class($filterObj) !== 'Net_LDAP2_Filter') { $this->_log('Could not parse LDAP Search filter', E_USER_ERROR); return FALSE; } if ($this->_debugMode) { $this->_log("Seaching for user {$login} with this query " . $filterObj->asString() . ' within ' . $this->_baseDN); } $searchResults = $this->ldapObj->search($this->_baseDN, $filterObj); if (get_class($searchResults) !== 'Net_LDAP2_Search') { $this->_log('LDAP Search Failed: ' . $searchResults->getMessage(), E_USER_ERROR); return FALSE; } elseif ($searchResults->count() === 0) { $this->_log((string) $login, 'Unknown User', E_USER_NOTICE); return FALSE; } elseif ($searchResults->count() > 1) { $this->_log('Multiple DNs found for username ' . (string) $login, E_USER_WARNING); return FALSE; } //Getting user's DN from search $userEntry = $searchResults->shiftEntry(); $userDN = $userEntry->dn(); //Binding with user's DN. if ($this->_debugMode) { $this->_log('Try to bind with user\'s DN: ' . $userDN); } $loginAttempt = $this->ldapObj->bind($userDN, $password); if ($loginAttempt === TRUE) { $this->_log('User: '******' authentication successful'); if (strlen($this->_ldapLoginAttrib) > 0) { if ($this->_debugMode) { $this->_log('Looking up TT-RSS username attribute in ' . $this->_ldapLoginAttrib); } $ttrssUsername = $userEntry->getValue($this->_ldapLoginAttrib, 'single'); $this->ldapObj->disconnect(); if (!is_string($ttrssUsername)) { $this->_log('Could not find user name attribute ' . $this->_ldapLoginAttrib . ' in LDAP entry', E_USER_WARNING); return FALSE; } return $this->base->auto_create_user($ttrssUsername); } else { $this->ldapObj->disconnect(); return $this->base->auto_create_user($login); } } elseif ($loginAttempt->getCode() == 49) { $this->ldapObj->disconnect(); $this->_log('User: '******' authentication failed'); return FALSE; } else { $this->ldapObj->disconnect(); $this->_log('Unknown Error: Code: ' . $loginAttempt->getCode() . ' Message: ' . $loginAttempt->getMessage() . ' user(' . (string) $login . ')', E_USER_WARNING); return FALSE; } } return false; }