From 8290929aa6fcb1e62e79d7acf8bf310c8d6f94d7 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Sun, 29 Sep 2013 23:53:14 +0200 Subject: [PATCH] LDAP Wizard: autodetect base DN --- apps/user_ldap/ajax/wizard.php | 1 + apps/user_ldap/js/settings.js | 71 +++++++++++++++++++++----- apps/user_ldap/lib/helper.php | 21 ++++++++ apps/user_ldap/lib/ildapwrapper.php | 8 +++ apps/user_ldap/lib/ldap.php | 4 ++ apps/user_ldap/lib/wizard.php | 79 ++++++++++++++++++++++++++--- 6 files changed, 162 insertions(+), 22 deletions(-) diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 53c66c34f8..7df922f17a 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -45,6 +45,7 @@ $wizard = new \OCA\user_ldap\lib\Wizard($configuration, $ldapWrapper); switch($action) { case 'guessPortAndTLS': + case 'guessBaseDN': try { $result = $wizard->$action(); if($result !== false) { diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 97470b4da4..45b1a9239f 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -126,7 +126,7 @@ var LdapConfiguration = { var LdapWizard = { checkPortInfoShown: false, - changeIndicators: {}, + saveBlacklist: {}, ajax: function(param, fnOnSuccess, fnOnError) { $.post( @@ -144,10 +144,36 @@ var LdapWizard = { applyChanges: function (result) { for (id in result.changes) { + LdapWizard.saveBlacklist[id] = true; $('#'+id).val(result.changes[id]); } }, + checkBaseDN: function() { + host = $('#ldap_host').val(); + user = $('#ldap_dn').val(); + pass = $('#ldap_agent_password').val(); + + if(host && user && pass) { + param = 'action=guessBaseDN'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + LdapWizard.applyChanges(result); + if($('#ldap_base').val()) { + $('#ldap_base').removeClass('hidden'); + LdapWizard.hideInfoBox(); + } + }, + function (result) { + $('#ldap_base').removeClass('hidden'); + LdapWizard.showInfoBox('Please specify a port'); + } + ); + } + }, + checkPort: function() { host = $('#ldap_host').val(); user = $('#ldap_dn').val(); @@ -162,30 +188,45 @@ var LdapWizard = { LdapWizard.applyChanges(result); if($('#ldap_port').val()) { $('#ldap_port').removeClass('hidden'); - if(LdapWizard.checkPortInfoShown) { - $('#ldapWizard1 .ldapWizardInfo').addClass('hidden'); - LdapWizard.checkPortInfoShown = false; - } + LdapWizard.hideInfoBox(); } }, function (result) { $('#ldap_port').removeClass('hidden'); - $('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', - 'Please specify a port')); - $('#ldapWizard1 .ldapWizardInfo').removeClass('hidden'); - LdapWizard.checkPortInfoShown = true; + LdapWizard.showInfoBox('Please specify the BaseDN'); } ); } }, + hideInfoBox: function() { + if(LdapWizard.checkInfoShown) { + $('#ldapWizard1 .ldapWizardInfo').addClass('hidden'); + LdapWizard.checkInfoShown = false; + } + }, + init: function() { if($('#ldap_port').val()) { $('#ldap_port').removeClass('hidden'); } }, + processChanges: function(triggerObj) { + if(triggerObj.id == 'ldap_host' + || triggerObj.id == 'ldap_port' + || triggerObj.id == 'ldap_dn' + || triggerObj.id == 'ldap_agent_password') { + LdapWizard.checkPort(); + LdapWizard.checkBaseDN(); + } + }, + save: function(inputObj) { + if(LdapWizard.saveBlacklist.hasOwnProperty(inputObj.id)) { + delete LdapWizard.saveBlacklist[inputObj.id]; + return; + } param = 'cfgkey='+inputObj.id+ '&cfgval='+$(inputObj).val()+ '&action=save'+ @@ -196,16 +237,18 @@ var LdapWizard = { param, function(result) { if(result.status == 'success') { - if(inputObj.id == 'ldap_host' - || inputObj.id == 'ldap_dn' - || inputObj.id == 'ldap_agent_password') { - LdapWizard.checkPort(); - } + LdapWizard.processChanges(inputObj); } else { // alert('Oooooooooooh :('); } } ); + }, + + showInfoBox: function(text) { + $('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', text)); + $('#ldapWizard1 .ldapWizardInfo').removeClass('hidden'); + LdapWizard.checkInfoShown = true; } }; diff --git a/apps/user_ldap/lib/helper.php b/apps/user_ldap/lib/helper.php index 4c9dd07a12..09f646921e 100644 --- a/apps/user_ldap/lib/helper.php +++ b/apps/user_ldap/lib/helper.php @@ -161,4 +161,25 @@ class Helper { return true; } + + /** + * @brief extractsthe domain from a given URL + * @param $url the URL + * @return mixed, domain as string on success, false otherwise + */ + static public function getDomainFromURL($url) { + $uinfo = parse_url($url); + if(!is_array($uinfo)) { + return false; + } + + $domain = false; + if(isset($uinfo['host'])) { + $domain = $uinfo['host']; + } else if(isset($uinfo['path'])) { + $domain = $uinfo['path']; + } + + return $domain; + } } diff --git a/apps/user_ldap/lib/ildapwrapper.php b/apps/user_ldap/lib/ildapwrapper.php index 9e6bd56ef2..5e12c7c63b 100644 --- a/apps/user_ldap/lib/ildapwrapper.php +++ b/apps/user_ldap/lib/ildapwrapper.php @@ -67,6 +67,14 @@ interface ILDAPWrapper { */ public function controlPagedResultResponse($link, $result, &$cookie); + /** + * @brief Count the number of entries in a search + * @param $link LDAP link resource + * @param $result LDAP result resource + * @return mixed, number of results on success, false otherwise + */ + public function countEntries($link, $result); + /** * @brief Return the LDAP error number of the last LDAP command * @param $link LDAP link resource diff --git a/apps/user_ldap/lib/ldap.php b/apps/user_ldap/lib/ldap.php index b63e969912..13314462b8 100644 --- a/apps/user_ldap/lib/ldap.php +++ b/apps/user_ldap/lib/ldap.php @@ -49,6 +49,10 @@ class LDAP implements ILDAPWrapper { $isCritical, $cookie); } + public function countEntries($link, $result) { + return $this->invokeLDAPMethod('count_entries', $link, $result); + } + public function errno($link) { return $this->invokeLDAPMethod('errno', $link); } diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 04802205cd..ad71fd10f6 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -89,6 +89,10 @@ class Wizard extends LDAPUtility { return false; } + /** + * @brief tries to determine a base dn from User DN or LDAP Host + * @returns mixed WizardResult on success, false otherwise + */ public function guessBaseDN() { if(!$this->checkRequirements(array('ldapHost', 'ldapAgentName', @@ -97,10 +101,52 @@ class Wizard extends LDAPUtility { ))) { return false; } - $cr = $this->getConnection(); - if(!$cr) { + + //check whether a DN is given in the agent name (99.9% of all cases) + $base = null; + $i = stripos($this->configuration->ldapAgentName, 'dc='); + if($i !== false) { + $base = substr($this->configuration->ldapAgentName, $i); + + if($this->testBaseDN($base)) { + $this->applyFind('ldap_base', $base); + $this->applyFind('ldap_base_users', $base); + $this->applyFind('ldap_base_groups', $base); + return $this->result; + } + } + + //this did not help :( + //Let's see whether we can parse the Host URL and convert the domain to + //a base DN + $domain = Helper::getDomainFromURL($this->configuration->ldapHost); + if(!$domain) { return false; } + + $dparts = explode('.', $domain); + $base2 = implode('dc=', $dparts); + if($base !== $base2 && $this->testBaseDN($base2)) { + $this->applyFind('ldap_base', $base2); + $this->applyFind('ldap_base_users', $base2); + $this->applyFind('ldap_base_groups', $base2); + return $this->result; + } + + return false; + } + + /** + * @brief sets the found value for the configuration key in the WizardResult + * as well as in the Configuration instance + * @param $key the configuration key + * @param $value the (detected) value + * @return null + * + */ + private function applyFind($key, $value) { + $this->result->addChange($key, $value); + $this->configuration->setConfiguration(array($key => $value)); } /** @@ -116,15 +162,32 @@ class Wizard extends LDAPUtility { if(is_array($hostInfo) && isset($hostInfo['port'])) { $port = $hostInfo['port']; $host = str_replace(':'.$port, '', $host); - $config = array('ldapHost' => $host, - 'ldapPort' => $port, - ); - $this->result->addChange('ldap_host', $host); - $this->result->addChange('ldap_port', $port); - $this->configuration->setConfiguration($config); + $this->applyFind('ldap_host', $host); + $this->applyFind('ldap_port', $port); } } + /** + * @brief Checks whether for a given BaseDN results will be returned + * @param $base the BaseDN to test + * @return bool true on success, false otherwise + */ + private function testBaseDN($base) { + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + + //base is there, let's validate it. If we search for anything, we should + //get a result set > 0 on a proper base + $rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1); + if(!$this->ldap->isResource($rr)) { + return false; + } + $entries = $this->ldap->countEntries($cr, $rr); + return ($entries !== false) && ($entries > 0); + } + /** * Connects and Binds to an LDAP Server * @param $port the port to connect with