diff options
author | Arthur Schiwon <blizzz@owncloud.com> | 2013-10-04 16:33:37 +0200 |
---|---|---|
committer | Arthur Schiwon <blizzz@owncloud.com> | 2013-10-17 19:13:27 +0200 |
commit | 3b1822cf91407f243f18311b8abc273ad2eb1b11 (patch) | |
tree | dce41cedcf3916bd9ef4951b74fec029fb9636c7 /apps/user_ldap/lib | |
parent | 8290929aa6fcb1e62e79d7acf8bf310c8d6f94d7 (diff) | |
download | nextcloud-server-3b1822cf91407f243f18311b8abc273ad2eb1b11.tar.gz nextcloud-server-3b1822cf91407f243f18311b8abc273ad2eb1b11.zip |
LDAP Wizard: add detection, load and save of LDAP objectClasses for filter purposes
Diffstat (limited to 'apps/user_ldap/lib')
-rw-r--r-- | apps/user_ldap/lib/configuration.php | 20 | ||||
-rw-r--r-- | apps/user_ldap/lib/ildapwrapper.php | 16 | ||||
-rw-r--r-- | apps/user_ldap/lib/ldap.php | 8 | ||||
-rw-r--r-- | apps/user_ldap/lib/wizard.php | 150 | ||||
-rw-r--r-- | apps/user_ldap/lib/wizardresult.php | 11 |
5 files changed, 190 insertions, 15 deletions
diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index ed6f384da88..e67e0d8d00b 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -44,6 +44,7 @@ class Configuration { 'turnOffCertCheck' => null, 'ldapIgnoreNamingRules' => null, 'ldapUserDisplayName' => null, + 'ldapUserFilterObjectclass' => null, 'ldapUserFilter' => null, 'ldapGroupFilter' => null, 'ldapGroupDisplayName' => null, @@ -121,6 +122,7 @@ class Configuration { case 'ldapBaseGroups': case 'ldapAttributesForUserSearch': case 'ldapAttributesForGroupSearch': + case 'ldapUserFilterObjectclass': $setMethod = 'setMultiLine'; default: $this->$setMethod($key, $val); @@ -136,19 +138,18 @@ class Configuration { if(!$this->configRead && !is_null($this->configPrefix)) { $cta = array_flip($this->getConfigTranslationArray()); foreach($this->config as $key => $val) { -// if($this->configPrefix == 's04') var_dump($key); if(!isset($cta[$key])) { //some are determined continue; } $dbkey = $cta[$key]; -// if($this->configPrefix == 's04') var_dump($dbkey); switch($key) { case 'ldapBase': case 'ldapBaseUsers': case 'ldapBaseGroups': case 'ldapAttributesForUserSearch': case 'ldapAttributesForGroupSearch': + case 'ldapUserFilterObjectclass': $readMethod = 'getMultiLine'; break; case 'ldapIgnoreNamingRules': @@ -166,16 +167,10 @@ class Configuration { $readMethod = 'getValue'; break; } -// if($this->configPrefix == 's04') var_dump($readMethod); $this->config[$key] = $this->$readMethod($dbkey); } $this->configRead = true; } - if($this->configPrefix == 's03') { -// var_dump($this->config); - -// die; - } } /** @@ -193,6 +188,7 @@ class Configuration { case 'ldapBaseGroups': case 'ldapAttributesForUserSearch': case 'ldapAttributesForGroupSearch': + case 'ldapUserFilterObjectclass': if(is_array($value)) { $value = implode("\n", $value); } @@ -250,12 +246,6 @@ class Configuration { if(is_null($defaults)) { $defaults = $this->getDefaults(); } -// if($this->configPrefix == 's04') var_dump($this->configPrefix.$varname); -// if(0 == $this->configKeyToDBKey($varname)) { -// var_dump($varname); -// print("<pre>"); -// debug_print_backtrace(); die; -// } return \OCP\Config::getAppValue('user_ldap', $this->configPrefix.$varname, $defaults[$varname]); @@ -288,6 +278,7 @@ class Configuration { 'ldap_base_users' => '', 'ldap_base_groups' => '', 'ldap_userlist_filter' => 'objectClass=person', + 'ldap_userfilter_objectclass' => '', 'ldap_login_filter' => 'uid=%uid', 'ldap_group_filter' => 'objectClass=posixGroup', 'ldap_display_name' => 'cn', @@ -327,6 +318,7 @@ class Configuration { 'ldap_base' => 'ldapBase', 'ldap_base_users' => 'ldapBaseUsers', 'ldap_base_groups' => 'ldapBaseGroups', + 'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass', 'ldap_userlist_filter' => 'ldapUserFilter', 'ldap_login_filter' => 'ldapLoginFilter', 'ldap_group_filter' => 'ldapGroupFilter', diff --git a/apps/user_ldap/lib/ildapwrapper.php b/apps/user_ldap/lib/ildapwrapper.php index 5e12c7c63b9..20587cba7db 100644 --- a/apps/user_ldap/lib/ildapwrapper.php +++ b/apps/user_ldap/lib/ildapwrapper.php @@ -106,6 +106,14 @@ interface ILDAPWrapper { public function getAttributes($link, $result); /** + * @brief Get the DN of a result entry + * @param $link LDAP link resource + * @param $result LDAP result resource + * @return string containing the DN, false on error + */ + public function getDN($link, $result); + + /** * @brief Get all result entries * @param $link LDAP link resource * @param $result LDAP result resource @@ -114,6 +122,14 @@ interface ILDAPWrapper { public function getEntries($link, $result); /** + * @brief Return next result id + * @param $link LDAP link resource + * @param $result LDAP entry result resource + * @return an LDAP search result resource + * */ + public function nextEntry($link, $result); + + /** * @brief Read an entry * @param $link LDAP link resource * @param $baseDN The DN of the entry to read from diff --git a/apps/user_ldap/lib/ldap.php b/apps/user_ldap/lib/ldap.php index 13314462b8c..bc963191722 100644 --- a/apps/user_ldap/lib/ldap.php +++ b/apps/user_ldap/lib/ldap.php @@ -69,10 +69,18 @@ class LDAP implements ILDAPWrapper { return $this->invokeLDAPMethod('get_attributes', $link, $result); } + public function getDN($link, $result) { + return $this->invokeLDAPMethod('get_dn', $link, $result); + } + public function getEntries($link, $result) { return $this->invokeLDAPMethod('get_entries', $link, $result); } + public function nextEntry($link, $result) { + return $this->invokeLDAPMethod('next_entry', $link, $result); + } + public function read($link, $baseDN, $filter, $attr) { return $this->invokeLDAPMethod('read', $link, $baseDN, $filter, $attr); } diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index ad71fd10f63..170af44e118 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -28,6 +28,10 @@ class Wizard extends LDAPUtility { protected $configuration; protected $result; + const LRESULT_PROCESSED_OK = 0; + const LRESULT_PROCESSED_INVALID = 1; + const LRESULT_PROCESSED_SKIP = 2; + /** * @brief Constructor * @param $configuration an instance of Configuration @@ -48,6 +52,51 @@ class Wizard extends LDAPUtility { } } + public function determineObjectClasses() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + ))) { + return false; + } + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + + $p = 'objectclass='; + $obclasses = array($p.'inetOrgPerson', $p.'person', + $p.'organizationalPerson', $p.'user', + $p.'posixAccount', $p.'*'); + + $maxEntryObjC = ''; + $availableObjectClasses = + $this->cumulativeSearchOnAttribute($obclasses, 'objectclass', + true, $maxEntryObjC); + if(is_array($availableObjectClasses) + && count($availableObjectClasses) > 0) { + $this->result->addOptions('ldap_userfilter_objectclass', + $availableObjectClasses); + } else { + throw new \Exception(self::$l->t('Could not find any objectClass')); + } + $setOCs = $this->configuration->ldapUserFilterObjectclass; + file_put_contents('/tmp/set', print_r($setOCs, true)); + if(is_array($setOCs) && !empty($setOCs)) { + //something is already configured? pre-select it. + $this->result->addChange('ldap_userfilter_objectclass', $setOCs); + } else if(!empty($maxEntryObjC)) { + //new? pre-select something hopefully sane + $maxEntryObjC = str_replace($p, '', $maxEntryObjC); + $this->result->addChange('ldap_userfilter_objectclass', + $maxEntryObjC); + } + + return $this->result; + } + /** * Tries to determine the port, requires given Host, User DN and Password * @returns mixed WizardResult on success, false otherwise @@ -55,7 +104,8 @@ class Wizard extends LDAPUtility { public function guessPortAndTLS() { if(!$this->checkRequirements(array('ldapHost', 'ldapAgentName', - 'ldapAgentPassword'))) { + 'ldapAgentPassword' + ))) { return false; } $this->checkHost(); @@ -266,6 +316,104 @@ class Wizard extends LDAPUtility { return true; } + /** + * @brief does a cumulativeSearch on LDAP to get different values of a + * specified attribute + * @param $filters array, the filters that shall be used in the search + * @param $attr the attribute of which a list of values shall be returned + * @param $lfw bool, whether the last filter is a wildcard which shall not + * be processed if there were already findings, defaults to true + * @param $maxF string. if not null, this variable will have the filter that + * yields most result entries + * @return mixed, an array with the values on success, false otherwise + * + */ + private function cumulativeSearchOnAttribute($filters, $attr, $lfw = true, &$maxF = null) { + $dnRead = array(); + $foundItems = array(); + $maxEntries = 0; + if(!is_array($this->configuration->ldapBase) || !isset($this->configuration->ldapBase[0])) { + return false; + } + $base = $this->configuration->ldapBase[0]; + $cr = $this->getConnection(); + if(!is_resource($cr)) { + return false; + } + foreach($filters as $filter) { + if($lfw && count($foundItems) > 0) { + continue; + } + $rr = $this->ldap->search($cr, $base, $filter, array($attr)); + if(!$this->ldap->isResource($rr)) { + \OCP\Util::writeLog('user_ldap', 'Search failed, Base '.$base, \OCP\Util::DEBUG); + continue; + } + $entries = $this->ldap->countEntries($cr, $rr); + $getEntryFunc = 'firstEntry'; + if(($entries !== false) && ($entries > 0)) { + if(!is_null($maxF) && $entries > $maxEntries) { + $maxEntries = $entries; + $maxF = $filter; + } + do { + $entry = $this->ldap->$getEntryFunc($cr, $rr); + if(!$this->ldap->isResource($entry)) { + continue 2; + } + $attributes = $this->ldap->getAttributes($cr, $entry); + $dn = $this->ldap->getDN($cr, $entry); + if($dn === false || in_array($dn, $dnRead)) { + continue; + } + $state = $this->getAttributeValuesFromEntry($attributes, + $attr, + $foundItems); + $dnRead[] = $dn; + $getEntryFunc = 'nextEntry'; + $rr = $entry; //will be expected by nextEntry next round + } while($state === self::LRESULT_PROCESSED_SKIP + || $this->ldap->isResource($entry)); + } + } + + return $foundItems; + } + + /** + * @brief appends a list of values fr + * @param $result resource, the return value from ldap_get_attributes + * @param $attribute string, the attribute values to look for + * @param &$known array, new values will be appended here + * @return int, state on of the class constants LRESULT_PROCESSED_OK, + * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP + */ + private function getAttributeValuesFromEntry($result, $attribute, &$known) { + if(!is_array($result) + || !isset($result['count']) + || !$result['count'] > 0) { + return self::LRESULT_PROCESSED_INVALID; + } + + //strtolower on all keys for proper comparison + $result = \OCP\Util::mb_array_change_key_case($result); + $attribute = strtolower($attribute); + if(isset($result[$attribute])) { + foreach($result[$attribute] as $key => $val) { + if($key === 'count') { + continue; + } + if(!in_array($val, $known)) { + \OCP\Util::writeLog('user_ldap', 'Found objclass '.$val, \OCP\Util::DEBUG); + $known[] = $val; + } + } + return self::LRESULT_PROCESSED_OK; + } else { + return self::LRESULT_PROCESSED_SKIP; + } + } + private function getConnection() { $cr = $this->ldap->connect( $this->configuration->ldapHost.':'.$this->configuration->ldapPort, diff --git a/apps/user_ldap/lib/wizardresult.php b/apps/user_ldap/lib/wizardresult.php index 2140f654fd0..4c3b563c0c2 100644 --- a/apps/user_ldap/lib/wizardresult.php +++ b/apps/user_ldap/lib/wizardresult.php @@ -25,11 +25,19 @@ namespace OCA\user_ldap\lib; class WizardResult { protected $changes = array(); + protected $options = array(); public function addChange($key, $value) { $this->changes[$key] = $value; } + public function addOptions($key, $values) { + if(!is_array($values)) { + $values = array($values); + } + $this->options[$key] = $values; + } + public function hasChanges() { return count($this->changes) > 0; } @@ -37,6 +45,9 @@ class WizardResult { public function getResultArray() { $result = array(); $result['changes'] = $this->changes; + if(count($this->options) > 0) { + $result['options'] = $this->options; + } return $result; } }
\ No newline at end of file |