From 53db1fe5ac24f569918fa7cfb3dcd67054099836 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Fri, 27 Sep 2013 18:30:59 +0200 Subject: First stage of new Wizard, neither feature complete nor ready --- apps/user_ldap/js/settings.js | 88 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 20d6f76dcd6..97470b4da41 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -30,6 +30,7 @@ var LdapConfiguration = { // assign the value $('#'+configkey).val(configvalue); }); + LdapWizard.init(); } } ); @@ -91,6 +92,7 @@ var LdapConfiguration = { $('#ldap_serverconfig_chooser option:selected').removeAttr('selected'); var html = ''; $('#ldap_serverconfig_chooser option:last').before(html); + LdapWizard.init(); } else { OC.dialogs.alert( result.message, @@ -122,12 +124,98 @@ var LdapConfiguration = { } }; +var LdapWizard = { + checkPortInfoShown: false, + changeIndicators: {}, + + ajax: function(param, fnOnSuccess, fnOnError) { + $.post( + OC.filePath('user_ldap','ajax','wizard.php'), + param, + function(result) { + if(result.status == 'success') { + fnOnSuccess(result); + } else { + fnOnError(result); + } + } + ); + }, + + applyChanges: function (result) { + for (id in result.changes) { + $('#'+id).val(result.changes[id]); + } + }, + + checkPort: function() { + host = $('#ldap_host').val(); + user = $('#ldap_dn').val(); + pass = $('#ldap_agent_password').val(); + + if(host && user && pass) { + param = 'action=guessPortAndTLS'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + LdapWizard.applyChanges(result); + if($('#ldap_port').val()) { + $('#ldap_port').removeClass('hidden'); + if(LdapWizard.checkPortInfoShown) { + $('#ldapWizard1 .ldapWizardInfo').addClass('hidden'); + LdapWizard.checkPortInfoShown = false; + } + } + }, + function (result) { + $('#ldap_port').removeClass('hidden'); + $('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', + 'Please specify a port')); + $('#ldapWizard1 .ldapWizardInfo').removeClass('hidden'); + LdapWizard.checkPortInfoShown = true; + } + ); + } + }, + + init: function() { + if($('#ldap_port').val()) { + $('#ldap_port').removeClass('hidden'); + } + }, + + save: function(inputObj) { + param = 'cfgkey='+inputObj.id+ + '&cfgval='+$(inputObj).val()+ + '&action=save'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + $.post( + OC.filePath('user_ldap','ajax','wizard.php'), + param, + function(result) { + if(result.status == 'success') { + if(inputObj.id == 'ldap_host' + || inputObj.id == 'ldap_dn' + || inputObj.id == 'ldap_agent_password') { + LdapWizard.checkPort(); + } + } else { +// alert('Oooooooooooh :('); + } + } + ); + } +}; + $(document).ready(function() { $('#ldapAdvancedAccordion').accordion({ heightStyle: 'content', animate: 'easeInOutCirc'}); $('#ldapSettings').tabs(); $('#ldap_submit').button(); $('#ldap_action_test_connection').button(); $('#ldap_action_delete_configuration').button(); + $('.lwautosave').change(function() { LdapWizard.save(this); }); LdapConfiguration.refreshConfig(); $('#ldap_action_test_connection').click(function(event){ event.preventDefault(); -- cgit v1.2.3 From 8290929aa6fcb1e62e79d7acf8bf310c8d6f94d7 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Sun, 29 Sep 2013 23:53:14 +0200 Subject: 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(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 53c66c34f8e..7df922f17af 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 97470b4da41..45b1a9239f5 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 4c9dd07a12c..09f646921e3 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 9e6bd56ef2a..5e12c7c63b9 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 b63e969912a..13314462b8c 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 04802205cd4..ad71fd10f63 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,13 +162,30 @@ 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); } /** -- cgit v1.2.3 From 3b1822cf91407f243f18311b8abc273ad2eb1b11 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Fri, 4 Oct 2013 16:33:37 +0200 Subject: LDAP Wizard: add detection, load and save of LDAP objectClasses for filter purposes --- apps/user_ldap/ajax/wizard.php | 1 + apps/user_ldap/css/settings.css | 20 ++- apps/user_ldap/js/settings.js | 81 +++++++++-- apps/user_ldap/lib/configuration.php | 20 +-- apps/user_ldap/lib/ildapwrapper.php | 16 +++ apps/user_ldap/lib/ldap.php | 8 ++ apps/user_ldap/lib/wizard.php | 150 ++++++++++++++++++++- apps/user_ldap/lib/wizardresult.php | 11 ++ apps/user_ldap/settings.php | 12 +- apps/user_ldap/templates/part.wizard-server.php | 4 +- .../user_ldap/templates/part.wizard-userfilter.php | 51 +++++++ apps/user_ldap/templates/settings.php | 2 +- 12 files changed, 343 insertions(+), 33 deletions(-) create mode 100644 apps/user_ldap/templates/part.wizard-userfilter.php (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 7df922f17af..807f04ca696 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -46,6 +46,7 @@ $wizard = new \OCA\user_ldap\lib\Wizard($configuration, $ldapWrapper); switch($action) { case 'guessPortAndTLS': case 'guessBaseDN': + case 'determineObjectClasses': try { $result = $wizard->$action(); if($result !== false) { diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index aa6c4687cf9..f6c9f756339 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -1,5 +1,6 @@ .table { display: table; + width: 60%; } .tablecell { @@ -18,7 +19,7 @@ height: 15px; } -.hidden { +.hidden, .invisible { visibility: hidden; } @@ -55,6 +56,16 @@ width: 96.5% !important; } +.tableCellInput { + margin-left: -40%; + width: 100%; +} + +.tableCellLabel { + text-align: right; + padding-right: 25%; +} + .ldapIndent { margin-left: 50px; } @@ -81,4 +92,11 @@ #ldap fieldset p input[type=checkbox] { vertical-align: bottom; +} + +select[multiple=multiple] + button { + height: 28px; + padding-top: 6px !important; + min-width: 40%; + max-width: 40%; } \ No newline at end of file diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 45b1a9239f5..88f63e25ca2 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -144,7 +144,10 @@ var LdapWizard = { applyChanges: function (result) { for (id in result.changes) { - LdapWizard.saveBlacklist[id] = true; + if(!$.isArray(result.changes[id])) { + //no need to blacklist multiselect + LdapWizard.saveBlacklist[id] = true; + } $('#'+id).val(result.changes[id]); } }, @@ -162,12 +165,12 @@ var LdapWizard = { function(result) { LdapWizard.applyChanges(result); if($('#ldap_base').val()) { - $('#ldap_base').removeClass('hidden'); + $('#ldap_base').removeClass('invisible'); LdapWizard.hideInfoBox(); } }, function (result) { - $('#ldap_base').removeClass('hidden'); + $('#ldap_base').removeClass('invisible'); LdapWizard.showInfoBox('Please specify a port'); } ); @@ -187,28 +190,59 @@ var LdapWizard = { function(result) { LdapWizard.applyChanges(result); if($('#ldap_port').val()) { - $('#ldap_port').removeClass('hidden'); + $('#ldap_port').removeClass('invisible'); LdapWizard.hideInfoBox(); } }, function (result) { - $('#ldap_port').removeClass('hidden'); + $('#ldap_port').removeClass('invisible'); LdapWizard.showInfoBox('Please specify the BaseDN'); } ); } }, + findObjectClasses: function() { + param = 'action=determineObjectClasses'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + $('#ldap_userfilter_objectclass').find('option').remove(); + for (i in result.options['ldap_userfilter_objectclass']) { + //FIXME: move HTML into template + objc = result.options['ldap_userfilter_objectclass'][i]; + $('#ldap_userfilter_objectclass').append(""); + } + LdapWizard.applyChanges(result); + $('#ldap_userfilter_objectclass').multiselect('refresh'); + }, + function (result) { + //TODO: error handling + } + ); + }, + hideInfoBox: function() { if(LdapWizard.checkInfoShown) { - $('#ldapWizard1 .ldapWizardInfo').addClass('hidden'); + $('#ldapWizard1 .ldapWizardInfo').addClass('invisible'); LdapWizard.checkInfoShown = false; } }, init: function() { if($('#ldap_port').val()) { - $('#ldap_port').removeClass('hidden'); + $('#ldap_port').removeClass('invisible'); + } + }, + + initUserFilter: function() { + LdapWizard.findObjectClasses(); + }, + + onTabChange: function(event, ui) { + if(ui.newTab[0].id === '#ldapWizard2') { + LdapWizard.initUserFilter(); } }, @@ -227,8 +261,20 @@ var LdapWizard = { delete LdapWizard.saveBlacklist[inputObj.id]; return; } - param = 'cfgkey='+inputObj.id+ - '&cfgval='+$(inputObj).val()+ + LdapWizard._save(inputObj, $(inputObj).val()); + }, + + saveMultiSelect: function(originalObj, resultObj) { + values = ''; + for(i = 0; i < resultObj.length; i++) { + values = values + "\n" + resultObj[i].value; + } + LdapWizard._save($('#'+originalObj)[0], $.trim(values)); + }, + + _save: function(object, value) { + param = 'cfgkey='+object.id+ + '&cfgval='+value+ '&action=save'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -237,7 +283,7 @@ var LdapWizard = { param, function(result) { if(result.status == 'success') { - LdapWizard.processChanges(inputObj); + LdapWizard.processChanges(object); } else { // alert('Oooooooooooh :('); } @@ -247,17 +293,28 @@ var LdapWizard = { showInfoBox: function(text) { $('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', text)); - $('#ldapWizard1 .ldapWizardInfo').removeClass('hidden'); + $('#ldapWizard1 .ldapWizardInfo').removeClass('invisible'); LdapWizard.checkInfoShown = true; } }; $(document).ready(function() { $('#ldapAdvancedAccordion').accordion({ heightStyle: 'content', animate: 'easeInOutCirc'}); - $('#ldapSettings').tabs(); + $('#ldapSettings').tabs({ beforeActivate: LdapWizard.onTabChange }); $('#ldap_submit').button(); $('#ldap_action_test_connection').button(); $('#ldap_action_delete_configuration').button(); + $('#ldap_userfilter_groups').multiselect(); + $('#ldap_userfilter_objectclass').multiselect({ + header: false, + selectedList: 9, + noneSelectedText: t('user_ldap', 'Select object classes'), + click: function(event, ui) { + LdapWizard.saveMultiSelect('ldap_userfilter_objectclass', + $('#ldap_userfilter_objectclass').multiselect("getChecked") + ); + } + }); $('.lwautosave').change(function() { LdapWizard.save(this); }); LdapConfiguration.refreshConfig(); $('#ldap_action_test_connection').click(function(event){ 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("
");
-// 			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
@@ -105,6 +105,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
@@ -113,6 +121,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
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
diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php
index 8a418a65005..ebba1dbd3a6 100644
--- a/apps/user_ldap/settings.php
+++ b/apps/user_ldap/settings.php
@@ -25,8 +25,11 @@
 
 OC_Util::checkAdminUser();
 
-OCP\Util::addscript('user_ldap', 'settings');
-OCP\Util::addstyle('user_ldap', 'settings');
+OCP\Util::addScript('user_ldap', 'settings');
+OCP\Util::addScript('core', 'jquery.multiselect');
+OCP\Util::addStyle('user_ldap', 'settings');
+OCP\Util::addStyle('core', 'jquery.multiselect');
+OCP\Util::addStyle('core', 'jquery-ui-1.10.0.custom');
 
 // fill template
 $tmpl = new OCP\Template('user_ldap', 'settings');
@@ -49,6 +52,11 @@ $wizard1->assign('wizardControls', $wControls);
 $wizardHtml .= $wizard1->fetchPage();
 $toc['#ldapWizard1'] = 'Server';
 
+$wizard2 = new OCP\Template('user_ldap', 'part.wizard-userfilter');
+$wizard2->assign('wizardControls', $wControls);
+$wizardHtml .= $wizard2->fetchPage();
+$toc['#ldapWizard2'] = 'User Filter';
+
 $tmpl->assign('tabs', $wizardHtml);
 $tmpl->assign('toc', $toc);
 
diff --git a/apps/user_ldap/templates/part.wizard-server.php b/apps/user_ldap/templates/part.wizard-server.php
index ae0a7e650c9..c6900fd24e8 100644
--- a/apps/user_ldap/templates/part.wizard-server.php
+++ b/apps/user_ldap/templates/part.wizard-server.php
@@ -33,7 +33,7 @@
 							/>
 						
 							
 						
@@ -68,7 +68,7 @@
 			
 
 			
-
diff --git a/apps/user_ldap/templates/part.wizard-userfilter.php b/apps/user_ldap/templates/part.wizard-userfilter.php new file mode 100644 index 00000000000..b58784b680f --- /dev/null +++ b/apps/user_ldap/templates/part.wizard-userfilter.php @@ -0,0 +1,51 @@ +
+ +
+

+ t('Limit the access to ownCloud to users meetignthis criteria:'));?> +

+ +

+ + + +

+ +

+ + + +

+ +

+ +

+ + + +

+

+

+ +
+
\ No newline at end of file diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 9ca9673ada2..f63a4bdef1f 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -2,7 +2,7 @@
    $title) { ?> -
  • +
  • Expert
  • Advanced
  • -- cgit v1.2.3 From 3cafcc2d47377187cd687a3bcde6a261ca8969ea Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Fri, 4 Oct 2013 18:11:44 +0200 Subject: LDAP Wizard: add detection, load and save of LDAP groups for filter purposes --- apps/user_ldap/ajax/wizard.php | 1 + apps/user_ldap/js/settings.js | 51 ++++++++++++---- apps/user_ldap/lib/configuration.php | 6 ++ apps/user_ldap/lib/wizard.php | 68 ++++++++++++++++------ .../user_ldap/templates/part.wizard-userfilter.php | 5 +- 5 files changed, 99 insertions(+), 32 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 807f04ca696..497fe9dcf24 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -47,6 +47,7 @@ switch($action) { case 'guessPortAndTLS': case 'guessBaseDN': case 'determineObjectClasses': + case 'determineGroups': try { $result = $wizard->$action(); if($result !== false) { diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 88f63e25ca2..8949f5002ca 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -202,6 +202,27 @@ var LdapWizard = { } }, + findAvailableGroups: function() { + param = 'action=determineGroups'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + $('#ldap_userfilter_groups').find('option').remove(); + for (i in result.options['ldap_userfilter_groups']) { + //FIXME: move HTML into template + objc = result.options['ldap_userfilter_groups'][i]; + $('#ldap_userfilter_groups').append(""); + } + LdapWizard.applyChanges(result); + $('#ldap_userfilter_groups').multiselect('refresh'); + }, + function (result) { + //TODO: error handling + } + ); + }, + findObjectClasses: function() { param = 'action=determineObjectClasses'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -236,8 +257,21 @@ var LdapWizard = { } }, + initMultiSelect: function(object, id, caption) { + object.multiselect({ + header: false, + selectedList: 9, + noneSelectedText: caption, + click: function(event, ui) { + LdapWizard.saveMultiSelect(id, + $('#'+id).multiselect("getChecked")); + } + }); + }, + initUserFilter: function() { LdapWizard.findObjectClasses(); + LdapWizard.findAvailableGroups(); }, onTabChange: function(event, ui) { @@ -304,17 +338,12 @@ $(document).ready(function() { $('#ldap_submit').button(); $('#ldap_action_test_connection').button(); $('#ldap_action_delete_configuration').button(); - $('#ldap_userfilter_groups').multiselect(); - $('#ldap_userfilter_objectclass').multiselect({ - header: false, - selectedList: 9, - noneSelectedText: t('user_ldap', 'Select object classes'), - click: function(event, ui) { - LdapWizard.saveMultiSelect('ldap_userfilter_objectclass', - $('#ldap_userfilter_objectclass').multiselect("getChecked") - ); - } - }); + LdapWizard.initMultiSelect($('#ldap_userfilter_groups'), + 'ldap_userfilter_groups', + t('user_ldap', 'Select groups')); + LdapWizard.initMultiSelect($('#ldap_userfilter_objectclass'), + 'ldap_userfilter_objectclass', + t('user_ldap', 'Select object classes')); $('.lwautosave').change(function() { LdapWizard.save(this); }); LdapConfiguration.refreshConfig(); $('#ldap_action_test_connection').click(function(event){ diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index e67e0d8d00b..33771cf9388 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -45,6 +45,7 @@ class Configuration { 'ldapIgnoreNamingRules' => null, 'ldapUserDisplayName' => null, 'ldapUserFilterObjectclass' => null, + 'ldapUserFilterGroups' => null, 'ldapUserFilter' => null, 'ldapGroupFilter' => null, 'ldapGroupDisplayName' => null, @@ -123,6 +124,7 @@ class Configuration { case 'ldapAttributesForUserSearch': case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': + case 'ldapUserFilterGroups': $setMethod = 'setMultiLine'; default: $this->$setMethod($key, $val); @@ -150,6 +152,7 @@ class Configuration { case 'ldapAttributesForUserSearch': case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': + case 'ldapUserFilterGroups': $readMethod = 'getMultiLine'; break; case 'ldapIgnoreNamingRules': @@ -189,6 +192,7 @@ class Configuration { case 'ldapAttributesForUserSearch': case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': + case 'ldapUserFilterGroups': if(is_array($value)) { $value = implode("\n", $value); } @@ -279,6 +283,7 @@ class Configuration { 'ldap_base_groups' => '', 'ldap_userlist_filter' => 'objectClass=person', 'ldap_userfilter_objectclass' => '', + 'ldap_userfilter_groups' => '', 'ldap_login_filter' => 'uid=%uid', 'ldap_group_filter' => 'objectClass=posixGroup', 'ldap_display_name' => 'cn', @@ -319,6 +324,7 @@ class Configuration { 'ldap_base_users' => 'ldapBaseUsers', 'ldap_base_groups' => 'ldapBaseGroups', 'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass', + 'ldap_userfilter_groups' => 'ldapUserFilterGroups', 'ldap_userlist_filter' => 'ldapUserFilter', 'ldap_login_filter' => 'ldapLoginFilter', 'ldap_group_filter' => 'ldapGroupFilter', diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index f785042f874..c72e832fbcd 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -52,6 +52,27 @@ class Wizard extends LDAPUtility { } } + public function determineGroups() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + ))) { + return false; + } + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + + $obclasses = array('posixGroup', 'group', '*'); + return $this->determineFeature($obclasses, + 'cn', + 'ldap_userfilter_groups', + 'ldapUserFilterGroups'); + } + public function determineObjectClasses() { if(!$this->checkRequirements(array('ldapHost', 'ldapPort', @@ -66,31 +87,44 @@ class Wizard extends LDAPUtility { throw new \Excpetion('Could not connect to LDAP'); } - $p = 'objectclass='; - $obclasses = array($p.'inetOrgPerson', $p.'person', - $p.'organizationalPerson', $p.'user', - $p.'posixAccount', $p.'*'); + $obclasses = array('inetOrgPerson', 'person', 'organizationalPerson', + 'user', 'posixAccount', '*'); + return $this->determineFeature($obclasses, + 'objectclass', + 'ldap_userfilter_objectclass', + 'ldapUserFilterObjectclass'); + } + private function determineFeature($objectclasses, $attr, $dbkey, $confkey) { + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + $p = 'objectclass='; + foreach($objectclasses as $key => $value) { + $objectclasses[$key] = $p.$value; + } $maxEntryObjC = ''; - $availableObjectClasses = - $this->cumulativeSearchOnAttribute($obclasses, 'objectclass', - true, $maxEntryObjC); - if(is_array($availableObjectClasses) - && count($availableObjectClasses) > 0) { - $this->result->addOptions('ldap_userfilter_objectclass', - $availableObjectClasses); + $availableFeatures = + $this->cumulativeSearchOnAttribute($objectclasses, $attr, + true, $maxEntryObjC); + if(is_array($availableFeatures) + && count($availableFeatures) > 0) { + $this->result->addOptions($dbkey, $availableFeatures); } else { - throw new \Exception(self::$l->t('Could not find any objectClass')); + throw new \Exception(self::$l->t('Could not find the desired feature')); } - $setOCs = $this->configuration->ldapUserFilterObjectclass; - if(is_array($setOCs) && !empty($setOCs)) { + + $setFeatures = $this->configuration->$confkey; + if(is_array($setFeatures) && !empty($setFeatures)) { //something is already configured? pre-select it. - $this->result->addChange('ldap_userfilter_objectclass', $setOCs); + $this->result->addChange($dbkey, $setFeatures); } else if(!empty($maxEntryObjC)) { + //TODO / FIXME: this is great for objectclasses, but wrong for groups + //isolate it in another method and call it from this method's callee //new? pre-select something hopefully sane $maxEntryObjC = str_replace($p, '', $maxEntryObjC); - $this->result->addChange('ldap_userfilter_objectclass', - $maxEntryObjC); + $this->result->addChange($dbkey, $maxEntryObjC); } return $this->result; diff --git a/apps/user_ldap/templates/part.wizard-userfilter.php b/apps/user_ldap/templates/part.wizard-userfilter.php index b58784b680f..56dd16e8a61 100644 --- a/apps/user_ldap/templates/part.wizard-userfilter.php +++ b/apps/user_ldap/templates/part.wizard-userfilter.php @@ -13,7 +13,6 @@

    @@ -23,10 +22,8 @@

    -- cgit v1.2.3 From 162bfb231aa31d7aa8c22543edff8aa9ceade3bd Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 8 Oct 2013 01:19:37 +0200 Subject: Ldap Wizard: find out whether server supports memberOf in LDAP Filter and disable group chooser if not --- apps/user_ldap/js/settings.js | 3 +- apps/user_ldap/lib/wizard.php | 79 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 16 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 8949f5002ca..837b79e329c 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -216,9 +216,10 @@ var LdapWizard = { } LdapWizard.applyChanges(result); $('#ldap_userfilter_groups').multiselect('refresh'); + $('#ldap_userfilter_groups').multiselect('enable'); }, function (result) { - //TODO: error handling + $('#ldap_userfilter_groups').multiselect('disable'); } ); }, diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 69354c69229..0dbd8c92021 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -25,8 +25,10 @@ namespace OCA\user_ldap\lib; class Wizard extends LDAPUtility { static protected $l; + protected $cr; protected $configuration; protected $result; + protected $resultCache = array(); const LRESULT_PROCESSED_OK = 0; const LRESULT_PROCESSED_INVALID = 1; @@ -71,12 +73,51 @@ class Wizard extends LDAPUtility { } $obclasses = array('posixGroup', 'group', '*'); - return $this->determineFeature($obclasses, - 'cn', - 'ldap_userfilter_groups', - 'ldapUserFilterGroups'); + $groups = $this->determineFeature($obclasses, + 'cn', + 'ldap_userfilter_groups', + 'ldapUserFilterGroups'); - //TODO: Check, whether member-of-overlay is installed on the LDAP Server + $isMemberOfWorking = $this->testMemberOf($groups); + if(!$isMemberOfWorking) { + throw new \Exception('memberOf is not supported by the server'); + } + + return $this->result; + } + + private function testMemberOf($groups) { + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + if(!is_array($this->configuration->ldapBase) + || !isset($this->configuration->ldapBase[0])) { + return false; + } + $base = $this->configuration->ldapBase[0]; + $filterPrefix = '(&(objectclass=*)(memberOf='; + + foreach($this->resultCache as $dn => $properties) { + if(!isset($properties['cn'])) { + //assuming only groups have their cn cached :) + continue; + } + $filter = strtolower($filterPrefix . $dn.'))'); + $rr = $this->ldap->search($cr, $base, $filter, array('dn')); + if(!$this->ldap->isResource($rr)) { + continue; + } + $entries = $this->ldap->countEntries($cr, $rr); + //we do not know which groups are empty, so test any and return + //success on the first match that returns at least one user + if(($entries !== false) && ($entries > 0)) { + return true; + } + } + + + return false; } /** @@ -89,7 +130,6 @@ class Wizard extends LDAPUtility { 'ldapAgentName', 'ldapAgentPassword', 'ldapBase', - true ))) { return false; } @@ -100,10 +140,13 @@ class Wizard extends LDAPUtility { $obclasses = array('inetOrgPerson', 'person', 'organizationalPerson', 'user', 'posixAccount', '*'); - return $this->determineFeature($obclasses, - 'objectclass', - 'ldap_userfilter_objectclass', - 'ldapUserFilterObjectclass'); + $this->determineFeature($obclasses, + 'objectclass', + 'ldap_userfilter_objectclass', + 'ldapUserFilterObjectclass', + true); + + return $this->result; } /** @@ -375,9 +418,12 @@ class Wizard extends LDAPUtility { if($dn === false || in_array($dn, $dnRead)) { continue; } + $newItems = array(); $state = $this->getAttributeValuesFromEntry($attributes, $attr, - $foundItems); + $newItems); + $foundItems = array_merge($foundItems, $newItems); + $this->resultCache[$dn][$attr] = $newItems; $dnRead[] = $dn; $getEntryFunc = 'nextEntry'; $rr = $entry; //will be expected by nextEntry next round @@ -386,7 +432,7 @@ class Wizard extends LDAPUtility { } } - return $foundItems; + return array_unique($foundItems); } /** @@ -398,7 +444,7 @@ class Wizard extends LDAPUtility { * Configuration class * @param $po boolean, whether the objectClass with most result entries * shall be pre-selected via the result - * @returns the instance's WizardResult instance + * @returns array, list of found items. */ private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) { $cr = $this->getConnection(); @@ -430,7 +476,7 @@ class Wizard extends LDAPUtility { $this->result->addChange($dbkey, $maxEntryObjC); } - return $this->result; + return $availableFeatures; } /** @@ -457,7 +503,6 @@ class Wizard extends LDAPUtility { continue; } if(!in_array($val, $known)) { - \OCP\Util::writeLog('user_ldap', 'Found objclass '.$val, \OCP\Util::DEBUG); $known[] = $val; } } @@ -468,6 +513,9 @@ class Wizard extends LDAPUtility { } private function getConnection() { + if(!is_null($this->cr)) { + return $cr; + } $cr = $this->ldap->connect( $this->configuration->ldapHost.':'.$this->configuration->ldapPort, $this->configuration->ldapPort); @@ -482,6 +530,7 @@ class Wizard extends LDAPUtility { $this->configuration->ldapAgentName, $this->configuration->ldapAgentPassword); if($lo === true) { + $this->$cr = $cr; return $cr; } -- cgit v1.2.3 From e903db7887fe9ffc61791610d098dd623552da5d Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 8 Oct 2013 18:27:36 +0200 Subject: LDAP Wizard: create user list filter, show number of user that will have access to OC --- apps/user_ldap/ajax/wizard.php | 2 + apps/user_ldap/js/settings.js | 68 +++++++++++- apps/user_ldap/lib/configuration.php | 3 + apps/user_ldap/lib/wizard.php | 121 ++++++++++++++++++++- .../user_ldap/templates/part.wizard-userfilter.php | 14 ++- 5 files changed, 201 insertions(+), 7 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 497fe9dcf24..27359b908f6 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -48,6 +48,8 @@ switch($action) { case 'guessBaseDN': case 'determineObjectClasses': case 'determineGroups': + case 'getUserListFilter': + case 'countUsers': try { $result = $wizard->$action(); if($result !== false) { diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 837b79e329c..d3c7aeea4f7 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -127,6 +127,7 @@ var LdapConfiguration = { var LdapWizard = { checkPortInfoShown: false, saveBlacklist: {}, + userFilterGroupSelectState: 'enable', ajax: function(param, fnOnSuccess, fnOnError) { $.post( @@ -148,7 +149,11 @@ var LdapWizard = { //no need to blacklist multiselect LdapWizard.saveBlacklist[id] = true; } - $('#'+id).val(result.changes[id]); + if(id.indexOf('count') > 0) { + $('#'+id).text(result.changes[id]); + } else { + $('#'+id).val(result.changes[id]); + } } }, @@ -202,6 +207,40 @@ var LdapWizard = { } }, + composeFilter: function(type) { + if(type == 'user') { + action = 'getUserListFilter'; + } + + param = 'action='+action+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + LdapWizard.applyChanges(result); + LdapWizard.countUsers(); + }, + function (result) { + // error handling + } + ); + }, + + countUsers: function() { + param = 'action=countUsers'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + LdapWizard.applyChanges(result); +// alert(result.changes['ldap_user_count']); + }, + function (result) { + // error handling + } + ); + }, + findAvailableGroups: function() { param = 'action=determineGroups'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -273,6 +312,7 @@ var LdapWizard = { initUserFilter: function() { LdapWizard.findObjectClasses(); LdapWizard.findAvailableGroups(); + LdapWizard.countUsers(); }, onTabChange: function(event, ui) { @@ -289,6 +329,10 @@ var LdapWizard = { LdapWizard.checkPort(); LdapWizard.checkBaseDN(); } + + if(triggerObj.id == 'ldap_userlist_filter') { + LdapWizard.countUsers(); + } }, save: function(inputObj) { @@ -305,6 +349,10 @@ var LdapWizard = { values = values + "\n" + resultObj[i].value; } LdapWizard._save($('#'+originalObj)[0], $.trim(values)); + if(originalObj == 'ldap_userfilter_objectclass' + || originalObj == 'ldap_userfilter_groups') { + LdapWizard.composeFilter('user'); + } }, _save: function(object, value) { @@ -330,6 +378,23 @@ var LdapWizard = { $('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', text)); $('#ldapWizard1 .ldapWizardInfo').removeClass('invisible'); LdapWizard.checkInfoShown = true; + }, + + toggleRawUserFilter: function() { + if($('#rawUserFilterContainer').hasClass('invisible')) { + $('#rawUserFilterContainer').removeClass('invisible'); + $('#ldap_userfilter_objectclass').multiselect('disable'); + if($('#ldap_userfilter_groups').multiselect().attr('disabled') == 'disabled') { + userFilterGroupSelectState = 'disable'; + } else { + userFilterGroupSelectState = 'enable'; + } + $('#ldap_userfilter_groups').multiselect('disable'); + } else { + $('#rawUserFilterContainer').addClass('invisible'); + $('#ldap_userfilter_group').multiselect(userFilterGroupSelectState); + $('#ldap_userfilter_objectclass').multiselect('enable'); + } } }; @@ -346,6 +411,7 @@ $(document).ready(function() { 'ldap_userfilter_objectclass', t('user_ldap', 'Select object classes')); $('.lwautosave').change(function() { LdapWizard.save(this); }); + $('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter); LdapConfiguration.refreshConfig(); $('#ldap_action_test_connection').click(function(event){ event.preventDefault(); diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index 33771cf9388..70c55458895 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -63,6 +63,7 @@ class Configuration { 'ldapAttributesForGroupSearch' => null, 'homeFolderNamingRule' => null, 'hasPagedResultSupport' => false, + 'hasMemberOfFilterSupport' => false, 'ldapExpertUsernameAttr' => null, 'ldapExpertUUIDAttr' => null, ); @@ -304,6 +305,7 @@ class Configuration { 'ldap_attributes_for_group_search' => '', 'ldap_expert_username_attr' => '', 'ldap_expert_uuid_attr' => '', + 'has_memberof_filter_support' => 0, ); } @@ -344,6 +346,7 @@ class Configuration { 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch', 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr', 'ldap_expert_uuid_attr' => 'ldapExpertUUIDAttr', + 'has_memberof_filter_support' => 'hasMemberOfFilterSupport', ); return $array; } diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 7e3dfa8610f..e85c7460748 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -34,6 +34,10 @@ class Wizard extends LDAPUtility { const LRESULT_PROCESSED_INVALID = 1; const LRESULT_PROCESSED_SKIP = 2; + const LFILTER_LOGIN = 0; + const LFILTER_USER_LIST = 1; + const LFILTER_GROUP_LIST = 2; + /** * @brief Constructor * @param $configuration an instance of Configuration @@ -54,6 +58,35 @@ class Wizard extends LDAPUtility { } } + public function countUsers() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + 'ldapUserFilter', + ))) { + return false; + } + + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + + $base = $this->configuration->ldapBase[0]; + $filter = $this->configuration->ldapUserFilter; + $rr = $this->ldap->search($cr, $base, $filter, array('dn')); + if(!$this->ldap->isResource($rr)) { + return false; + } + $entries = $this->ldap->countEntries($cr, $rr); + $entries = ($entries !== false) ? $entries : 0; + $this->result->addChange('ldap_user_count', $entries); + + return $this->result; + } + /** * @brief detects the available LDAP groups * @returns the instance's WizardResult instance @@ -78,7 +111,9 @@ class Wizard extends LDAPUtility { 'ldap_userfilter_groups', 'ldapUserFilterGroups'); - if(!$this->testMemberOf()) { + $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); + $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST); + if(!$this->configuration->hasMemberOfFilterSupport) { throw new \Exception('memberOf is not supported by the server'); } @@ -114,6 +149,24 @@ class Wizard extends LDAPUtility { return $this->result; } + public function getUserListFilter() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + ))) { + return false; + } + $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST); + if(!$filter) { + throw new \Exception('Cannot create filter'); + } + + $this->applyFind('ldap_userlist_filter', $filter); + return $this->result; + } + /** * Tries to determine the port, requires given Host, User DN and Password * @returns mixed WizardResult on success, false otherwise @@ -295,6 +348,72 @@ class Wizard extends LDAPUtility { return false; } + /** + * @brief creates an LDAP Filter from given configuration + * @param $filterType int, for which use case the filter shall be created + * can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or + * self::LFILTER_GROUP_LIST + * @return mixed, string with the filter on success, false otherwise + */ + private function composeLdapFilter($filterType) { + $filter = ''; + $parts = 0; + switch ($filterType) { + case self::LFILTER_USER_LIST: + $objcs = $this->configuration->ldapUserFilterObjectclass; + \OCP\Util::writeLog('user_ldap', 'Wiz: '.print_r($objcs, true), \OCP\Util::DEBUG); + //glue objectclasses + if(is_array($objcs) && count($objcs) > 0) { + \OCP\Util::writeLog('user_ldap', 'Wiz: Processing objectclasses', \OCP\Util::DEBUG); + $filter .= '(|'; + foreach($objcs as $objc) { + $filter .= '(objectclass=' . $objc . ')'; + } + $filter .= ')'; + $parts++; + } + \OCP\Util::writeLog('user_ldap', 'Wiz: Intermediate filter '.$filter, \OCP\Util::DEBUG); + //glue group memberships + if($this->configuration->hasMemberOfFilterSupport) { + $cns = $this->configuration->ldapUserFilterGroups; + \OCP\Util::writeLog('user_ldap', 'Wiz: '.print_r($cns, true), \OCP\Util::DEBUG); + if(is_array($cns) && count($cns) > 0) { + \OCP\Util::writeLog('user_ldap', 'Wiz: Processing groups', \OCP\Util::DEBUG); + $filter .= '(|'; + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + $base = $this->configuration->ldapBase[0]; + foreach($cns as $cn) { + $rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn')); + if(!$this->ldap->isResource($rr)) { + continue; + } + $er = $this->ldap->firstEntry($cr, $rr); + $dn = $this->ldap->getDN($cr, $er); + $filter .= '(memberof=' . $dn . ')'; + } + $filter .= ')'; + } + $parts++; + \OCP\Util::writeLog('user_ldap', 'Wiz: Intermediate filter '.$filter, \OCP\Util::DEBUG); + } + //wrap parts in AND condition + if($parts > 1) { + $filter = '(&' . $filter . ')'; + } + if(empty($filter)) { + $filter = 'objectclass=*'; + } + break; + } + + \OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG); + + return empty($filter) ? false : $filter; + } + /** * Connects and Binds to an LDAP Server * @param $port the port to connect with diff --git a/apps/user_ldap/templates/part.wizard-userfilter.php b/apps/user_ldap/templates/part.wizard-userfilter.php index 56dd16e8a61..879af95b2bc 100644 --- a/apps/user_ldap/templates/part.wizard-userfilter.php +++ b/apps/user_ldap/templates/part.wizard-userfilter.php @@ -2,7 +2,7 @@

    - t('Limit the access to ownCloud to users meetignthis criteria:'));?> + t('Limit the access to ownCloud to users meeting this criteria:'));?>

    @@ -28,13 +28,13 @@

    - +

    -

    + +

    + 0 t('user(s) found'));?> +

    \ No newline at end of file -- cgit v1.2.3 From 7c6a9c22562f03eefb6730fc53afeed360c0171e Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 8 Oct 2013 23:47:57 +0200 Subject: Ldap Wizard: Login filter UI, detection of username attribute, composing of login filter --- apps/user_ldap/ajax/wizard.php | 2 + apps/user_ldap/js/settings.js | 53 +++++++++++- apps/user_ldap/lib/configuration.php | 12 +++ apps/user_ldap/lib/wizard.php | 156 ++++++++++++++++++++++++++++++++--- apps/user_ldap/settings.php | 5 ++ 5 files changed, 214 insertions(+), 14 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 27359b908f6..7af879c99a5 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -48,7 +48,9 @@ switch($action) { case 'guessBaseDN': case 'determineObjectClasses': case 'determineGroups': + case 'determineAttributes': case 'getUserListFilter': + case 'getUserLoginFilter': case 'countUsers': try { $result = $wizard->$action(); diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index d3c7aeea4f7..ba000c200f5 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -210,6 +210,8 @@ var LdapWizard = { composeFilter: function(type) { if(type == 'user') { action = 'getUserListFilter'; + } else if(type == 'login') { + action = 'getUserLoginFilter'; } param = 'action='+action+ @@ -241,6 +243,32 @@ var LdapWizard = { ); }, + findAttributes: function() { + param = 'action=determineAttributes'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + $('#ldap_loginfilter_attributes').find('option').remove(); + for (i in result.options['ldap_loginfilter_attributes']) { + //FIXME: move HTML into template + attr = result.options['ldap_loginfilter_attributes'][i]; + $('#ldap_loginfilter_attributes').append( + ""); + } + LdapWizard.applyChanges(result); + $('#ldap_loginfilter_attributes').multiselect('refresh'); + $('#ldap_loginfilter_attributes').multiselect('enable'); + }, + function (result) { + //deactivate if no attributes found + $('#ldap_loginfilter_attributes').multiselect( + {noneSelectedText : 'No attributes found'}); + $('#ldap_loginfilter_attributes').multiselect('disable'); + } + ); + }, + findAvailableGroups: function() { param = 'action=determineGroups'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -297,6 +325,10 @@ var LdapWizard = { } }, + initLoginFilter: function() { + LdapWizard.findAttributes(); + }, + initMultiSelect: function(object, id, caption) { object.multiselect({ header: false, @@ -318,6 +350,8 @@ var LdapWizard = { onTabChange: function(event, ui) { if(ui.newTab[0].id === '#ldapWizard2') { LdapWizard.initUserFilter(); + } else if(ui.newTab[0].id === '#ldapWizard3') { + LdapWizard.initLoginFilter(); } }, @@ -333,6 +367,11 @@ var LdapWizard = { if(triggerObj.id == 'ldap_userlist_filter') { LdapWizard.countUsers(); } + + if(triggerObj.id == 'ldap_loginfilter_username' + || triggerObj.id == 'ldap_loginfilter_email') { + LdapWizard.composeFilter('login'); + } }, save: function(inputObj) { @@ -340,7 +379,13 @@ var LdapWizard = { delete LdapWizard.saveBlacklist[inputObj.id]; return; } - LdapWizard._save(inputObj, $(inputObj).val()); + if($(inputObj).is('input[type=checkbox]') + && !$(inputObj).is(':checked')) { + val = 0; + } else { + val = $(inputObj).val(); + } + LdapWizard._save(inputObj, val); }, saveMultiSelect: function(originalObj, resultObj) { @@ -352,7 +397,10 @@ var LdapWizard = { if(originalObj == 'ldap_userfilter_objectclass' || originalObj == 'ldap_userfilter_groups') { LdapWizard.composeFilter('user'); + } else if(originalObj == 'ldap_loginfilter_attributes') { + LdapWizard.composeFilter('login'); } + }, _save: function(object, value) { @@ -410,6 +458,9 @@ $(document).ready(function() { LdapWizard.initMultiSelect($('#ldap_userfilter_objectclass'), 'ldap_userfilter_objectclass', t('user_ldap', 'Select object classes')); + LdapWizard.initMultiSelect($('#ldap_loginfilter_attributes'), + 'ldap_loginfilter_attributes', + t('user_ldap', 'Select attributes')); $('.lwautosave').change(function() { LdapWizard.save(this); }); $('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter); LdapConfiguration.refreshConfig(); diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index 70c55458895..205f9b517a2 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -51,6 +51,9 @@ class Configuration { 'ldapGroupDisplayName' => null, 'ldapGroupMemberAssocAttr' => null, 'ldapLoginFilter' => null, + 'ldapLoginFilterEmail' => null, + 'ldapLoginFilterUsername' => null, + 'ldapLoginFilterAttributes' => null, 'ldapQuotaAttribute' => null, 'ldapQuotaDefault' => null, 'ldapEmailAttribute' => null, @@ -126,6 +129,7 @@ class Configuration { case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': case 'ldapUserFilterGroups': + case 'ldapLoginFilterAttributes': $setMethod = 'setMultiLine'; default: $this->$setMethod($key, $val); @@ -154,6 +158,7 @@ class Configuration { case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': case 'ldapUserFilterGroups': + case 'ldapLoginFilterAttributes': $readMethod = 'getMultiLine'; break; case 'ldapIgnoreNamingRules': @@ -194,6 +199,7 @@ class Configuration { case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': case 'ldapUserFilterGroups': + case 'ldapLoginFilterAttributes': if(is_array($value)) { $value = implode("\n", $value); } @@ -286,6 +292,9 @@ class Configuration { 'ldap_userfilter_objectclass' => '', 'ldap_userfilter_groups' => '', 'ldap_login_filter' => 'uid=%uid', + 'ldap_loginfilter_email' => 0, + 'ldap_loginfilter_username' => 1, + 'ldap_loginfilter_attributes' => '', 'ldap_group_filter' => 'objectClass=posixGroup', 'ldap_display_name' => 'cn', 'ldap_group_display_name' => 'cn', @@ -329,6 +338,9 @@ class Configuration { 'ldap_userfilter_groups' => 'ldapUserFilterGroups', 'ldap_userlist_filter' => 'ldapUserFilter', 'ldap_login_filter' => 'ldapLoginFilter', + 'ldap_loginfilter_email' => 'ldapLoginFilterEmail', + 'ldap_loginfilter_username' => 'ldapLoginFilterUsername', + 'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes', 'ldap_group_filter' => 'ldapGroupFilter', 'ldap_display_name' => 'ldapUserDisplayName', 'ldap_group_display_name' => 'ldapGroupDisplayName', diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index e85c7460748..3cbca172515 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -30,13 +30,13 @@ class Wizard extends LDAPUtility { protected $result; protected $resultCache = array(); - const LRESULT_PROCESSED_OK = 0; - const LRESULT_PROCESSED_INVALID = 1; - const LRESULT_PROCESSED_SKIP = 2; + const LRESULT_PROCESSED_OK = 2; + const LRESULT_PROCESSED_INVALID = 3; + const LRESULT_PROCESSED_SKIP = 4; - const LFILTER_LOGIN = 0; - const LFILTER_USER_LIST = 1; - const LFILTER_GROUP_LIST = 2; + const LFILTER_LOGIN = 2; + const LFILTER_USER_LIST = 3; + const LFILTER_GROUP_LIST = 4; /** * @brief Constructor @@ -87,6 +87,67 @@ class Wizard extends LDAPUtility { return $this->result; } + public function determineAttributes() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + 'ldapUserFilter', + ))) { + return false; + } + + $attributes = $this->getUserAttributes(); + + natcasesort($attributes); + $attributes = array_values($attributes); + + $this->result->addOptions('ldap_loginfilter_attributes', $attributes); + + $selected = $this->configuration->ldapLoginFilterAttributes; + if(is_array($selected) && !empty($selected)) { + $this->result->addChange('ldap_loginfilter_attributes', $selected); + } + + return $this->result; + } + + /** + * @brief detects the available LDAP attributes + * @returns the instance's WizardResult instance + */ + private function getUserAttributes() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + 'ldapUserFilter', + ))) { + return false; + } + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + + $base = $this->configuration->ldapBase[0]; + $filter = $this->configuration->ldapUserFilter; + $rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1); + if(!$this->ldap->isResource($rr)) { + return false; + } + $er = $this->ldap->firstEntry($cr, $rr); + $attributes = $this->ldap->getAttributes($cr, $er); + $pureAttributes = array(); + for($i = 0; $i < $attributes['count']; $i++) { + $pureAttributes[] = $attributes[$i]; + } + + return $pureAttributes; + } + /** * @brief detects the available LDAP groups * @returns the instance's WizardResult instance @@ -167,6 +228,25 @@ class Wizard extends LDAPUtility { return $this->result; } + public function getUserLoginFilter() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + 'ldapUserFilter', + ))) { + return false; + } + $filter = $this->composeLdapFilter(self::LFILTER_LOGIN); + if(!$filter) { + throw new \Exception('Cannot create filter'); + } + + $this->applyFind('ldap_login_filter', $filter); + return $this->result; + } + /** * Tries to determine the port, requires given Host, User DN and Password * @returns mixed WizardResult on success, false otherwise @@ -361,10 +441,8 @@ class Wizard extends LDAPUtility { switch ($filterType) { case self::LFILTER_USER_LIST: $objcs = $this->configuration->ldapUserFilterObjectclass; - \OCP\Util::writeLog('user_ldap', 'Wiz: '.print_r($objcs, true), \OCP\Util::DEBUG); //glue objectclasses if(is_array($objcs) && count($objcs) > 0) { - \OCP\Util::writeLog('user_ldap', 'Wiz: Processing objectclasses', \OCP\Util::DEBUG); $filter .= '(|'; foreach($objcs as $objc) { $filter .= '(objectclass=' . $objc . ')'; @@ -372,13 +450,10 @@ class Wizard extends LDAPUtility { $filter .= ')'; $parts++; } - \OCP\Util::writeLog('user_ldap', 'Wiz: Intermediate filter '.$filter, \OCP\Util::DEBUG); //glue group memberships if($this->configuration->hasMemberOfFilterSupport) { $cns = $this->configuration->ldapUserFilterGroups; - \OCP\Util::writeLog('user_ldap', 'Wiz: '.print_r($cns, true), \OCP\Util::DEBUG); if(is_array($cns) && count($cns) > 0) { - \OCP\Util::writeLog('user_ldap', 'Wiz: Processing groups', \OCP\Util::DEBUG); $filter .= '(|'; $cr = $this->getConnection(); if(!$cr) { @@ -397,15 +472,70 @@ class Wizard extends LDAPUtility { $filter .= ')'; } $parts++; - \OCP\Util::writeLog('user_ldap', 'Wiz: Intermediate filter '.$filter, \OCP\Util::DEBUG); } //wrap parts in AND condition if($parts > 1) { $filter = '(&' . $filter . ')'; } if(empty($filter)) { - $filter = 'objectclass=*'; + $filter = '(objectclass=*)'; + } + break; + + case self::LFILTER_LOGIN: + $ulf = $this->configuration->ldapUserFilter; + $loginpart = '=%uid'; + $filterUsername = ''; + $userAttributes = $this->getUserAttributes(); + $userAttributes = array_change_key_case(array_flip($userAttributes)); + $parts = 0; + + $x = $this->configuration->ldapLoginFilterUsername; + if($this->configuration->ldapLoginFilterUsername === '1') { + $attr = ''; + if(isset($userAttributes['uid'])) { + $attr = 'uid'; + } else if(isset($userAttributes['samaccountname'])) { + $attr = 'samaccountname'; + } else if(isset($userAttributes['cn'])) { + //fallback + $attr = 'cn'; + } + if(!empty($attr)) { + $filterUsername = '(' . $attr . $loginpart . ')'; + $parts++; + } } + + $filterEmail = ''; + if($this->configuration->ldapLoginFilterEmail === '1') { + $filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))'; + $parts++; + } + + $filterAttributes = ''; + $attrsToFilter = $this->configuration->ldapLoginFilterAttributes; + if(is_array($attrsToFilter) && count($attrsToFilter) > 0) { + $filterAttributes = '(|'; + foreach($attrsToFilter as $attribute) { + $filterAttributes .= '(' . $attribute . $loginpart . ')'; + } + $filterAttributes .= ')'; + $parts++; + } + + $filterLogin = ''; + if($parts > 1) { + $filterLogin = '(|'; + } + $filterLogin .= $filterUsername; + $filterLogin .= $filterEmail; + $filterLogin .= $filterAttributes; + if($parts > 1) { + $filterLogin .= ')'; + } + + $filter = '(&'.$ulf.$filterLogin.')'; break; } diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php index ebba1dbd3a6..299e98fe090 100644 --- a/apps/user_ldap/settings.php +++ b/apps/user_ldap/settings.php @@ -57,6 +57,11 @@ $wizard2->assign('wizardControls', $wControls); $wizardHtml .= $wizard2->fetchPage(); $toc['#ldapWizard2'] = 'User Filter'; +$wizard3 = new OCP\Template('user_ldap', 'part.wizard-loginfilter'); +$wizard3->assign('wizardControls', $wControls); +$wizardHtml .= $wizard3->fetchPage(); +$toc['#ldapWizard3'] = 'Login Filter'; + $tmpl->assign('tabs', $wizardHtml); $tmpl->assign('toc', $toc); -- cgit v1.2.3 From b2ccb712e26de6922e09d7500a01041814e6bd74 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 9 Oct 2013 22:00:36 +0200 Subject: Ldap Wizard: Group Filter configuration --- apps/user_ldap/ajax/wizard.php | 8 +- apps/user_ldap/js/settings.js | 122 ++++++++++++++++++++-------- apps/user_ldap/lib/configuration.php | 12 +++ apps/user_ldap/lib/wizard.php | 150 ++++++++++++++++++++++++++++++++--- apps/user_ldap/settings.php | 30 +++---- 5 files changed, 258 insertions(+), 64 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index 7af879c99a5..ebeedaee959 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -46,12 +46,16 @@ $wizard = new \OCA\user_ldap\lib\Wizard($configuration, $ldapWrapper); switch($action) { case 'guessPortAndTLS': case 'guessBaseDN': - case 'determineObjectClasses': - case 'determineGroups': + case 'determineUserObjectClasses': + case 'determineGroupObjectClasses': + case 'determineGroupsForUsers': + case 'determineGroupsForGroups': case 'determineAttributes': case 'getUserListFilter': case 'getUserLoginFilter': + case 'getGroupFilter': case 'countUsers': + case 'countGroups': try { $result = $wizard->$action(); if($result !== false) { diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index ba000c200f5..049df9b8b17 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -212,6 +212,8 @@ var LdapWizard = { action = 'getUserListFilter'; } else if(type == 'login') { action = 'getUserLoginFilter'; + } else if(type == 'group') { + action = 'getGroupFilter'; } param = 'action='+action+ @@ -220,7 +222,11 @@ var LdapWizard = { LdapWizard.ajax(param, function(result) { LdapWizard.applyChanges(result); - LdapWizard.countUsers(); + if(type == 'user') { + LdapWizard.countUsers(); + } else if(type == 'group') { + LdapWizard.countGroups(); + } }, function (result) { // error handling @@ -228,14 +234,13 @@ var LdapWizard = { ); }, - countUsers: function() { - param = 'action=countUsers'+ + _countThings: function(method) { + param = 'action='+method+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); LdapWizard.ajax(param, function(result) { LdapWizard.applyChanges(result); -// alert(result.changes['ldap_user_count']); }, function (result) { // error handling @@ -243,6 +248,14 @@ var LdapWizard = { ); }, + countGroups: function() { + LdapWizard._countThings('countGroups'); + }, + + countUsers: function() { + LdapWizard._countThings('countUsers'); + }, + findAttributes: function() { param = 'action=determineAttributes'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -269,42 +282,48 @@ var LdapWizard = { ); }, - findAvailableGroups: function() { - param = 'action=determineGroups'+ + findAvailableGroups: function(multisel, type) { + if(type != 'Users' && type != 'Groups') { + return false; + } + param = 'action=determineGroupsFor'+type+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); LdapWizard.ajax(param, function(result) { - $('#ldap_userfilter_groups').find('option').remove(); - for (i in result.options['ldap_userfilter_groups']) { + $('#'+multisel).find('option').remove(); + for (i in result.options[multisel]) { //FIXME: move HTML into template - objc = result.options['ldap_userfilter_groups'][i]; - $('#ldap_userfilter_groups').append(""); + objc = result.options[multisel][i]; + $('#'+multisel).append(""); } LdapWizard.applyChanges(result); - $('#ldap_userfilter_groups').multiselect('refresh'); - $('#ldap_userfilter_groups').multiselect('enable'); + $('#'+multisel).multiselect('refresh'); + $('#'+multisel).multiselect('enable'); }, function (result) { - $('#ldap_userfilter_groups').multiselect('disable'); + $('#'+multisel).multiselect('disable'); } ); }, - findObjectClasses: function() { - param = 'action=determineObjectClasses'+ + findObjectClasses: function(multisel, type) { + if(type != 'User' && type != 'Group') { + return false; + } + param = 'action=determine'+type+'ObjectClasses'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); LdapWizard.ajax(param, function(result) { - $('#ldap_userfilter_objectclass').find('option').remove(); - for (i in result.options['ldap_userfilter_objectclass']) { + $('#'+multisel).find('option').remove(); + for (i in result.options[multisel]) { //FIXME: move HTML into template - objc = result.options['ldap_userfilter_objectclass'][i]; - $('#ldap_userfilter_objectclass').append(""); + objc = result.options[multisel][i]; + $('#'+multisel).append(""); } LdapWizard.applyChanges(result); - $('#ldap_userfilter_objectclass').multiselect('refresh'); + $('#'+multisel).multiselect('refresh'); }, function (result) { //TODO: error handling @@ -325,6 +344,12 @@ var LdapWizard = { } }, + initGroupFilter: function() { + LdapWizard.findObjectClasses('ldap_groupfilter_objectclass', 'Group'); + LdapWizard.findAvailableGroups('ldap_groupfilter_groups', 'Groups'); + LdapWizard.countGroups(); + }, + initLoginFilter: function() { LdapWizard.findAttributes(); }, @@ -342,8 +367,8 @@ var LdapWizard = { }, initUserFilter: function() { - LdapWizard.findObjectClasses(); - LdapWizard.findAvailableGroups(); + LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User'); + LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users'); LdapWizard.countUsers(); }, @@ -352,6 +377,8 @@ var LdapWizard = { LdapWizard.initUserFilter(); } else if(ui.newTab[0].id === '#ldapWizard3') { LdapWizard.initLoginFilter(); + } else if(ui.newTab[0].id === '#ldapWizard4') { + LdapWizard.initGroupFilter(); } }, @@ -366,6 +393,8 @@ var LdapWizard = { if(triggerObj.id == 'ldap_userlist_filter') { LdapWizard.countUsers(); + } else if(triggerObj.id == 'ldap_group_filter') { + LdapWizard.countGroups(); } if(triggerObj.id == 'ldap_loginfilter_username' @@ -399,8 +428,10 @@ var LdapWizard = { LdapWizard.composeFilter('user'); } else if(originalObj == 'ldap_loginfilter_attributes') { LdapWizard.composeFilter('login'); + } else if(originalObj == 'ldap_groupfilter_objectclass' + || originalObj == 'ldap_groupfilter_groups') { + LdapWizard.composeFilter('group'); } - }, _save: function(object, value) { @@ -428,21 +459,37 @@ var LdapWizard = { LdapWizard.checkInfoShown = true; }, - toggleRawUserFilter: function() { - if($('#rawUserFilterContainer').hasClass('invisible')) { - $('#rawUserFilterContainer').removeClass('invisible'); - $('#ldap_userfilter_objectclass').multiselect('disable'); - if($('#ldap_userfilter_groups').multiselect().attr('disabled') == 'disabled') { - userFilterGroupSelectState = 'disable'; + toggleRawFilter: function(container, moc, mg, stateVar) { + if($(container).hasClass('invisible')) { + $(container).removeClass('invisible'); + $(moc).multiselect('disable'); + if($(mg).multiselect().attr('disabled') == 'disabled') { + LdapWizard[stateVar] = 'disable'; } else { - userFilterGroupSelectState = 'enable'; + LdapWizard[stateVar] = 'enable'; } - $('#ldap_userfilter_groups').multiselect('disable'); + $(mg).multiselect('disable'); } else { - $('#rawUserFilterContainer').addClass('invisible'); - $('#ldap_userfilter_group').multiselect(userFilterGroupSelectState); - $('#ldap_userfilter_objectclass').multiselect('enable'); + $(container).addClass('invisible'); + $(mg).multiselect(LdapWizard[stateVar]); + $(moc).multiselect('enable'); } + }, + + toggleRawGroupFilter: function() { + LdapWizard.toggleRawFilter('#rawGroupFilterContainer', + '#ldap_groupfilter_objectclass', + '#ldap_groupfilter_groups', + 'groupFilterGroupSelectState' + ); + }, + + toggleRawUserFilter: function() { + LdapWizard.toggleRawFilter('#rawUserFilterContainer', + '#ldap_userfilter_objectclass', + '#ldap_userfilter_groups', + 'userFilterGroupSelectState' + ); } }; @@ -461,8 +508,15 @@ $(document).ready(function() { LdapWizard.initMultiSelect($('#ldap_loginfilter_attributes'), 'ldap_loginfilter_attributes', t('user_ldap', 'Select attributes')); + LdapWizard.initMultiSelect($('#ldap_groupfilter_groups'), + 'ldap_groupfilter_groups', + t('user_ldap', 'Select groups')); + LdapWizard.initMultiSelect($('#ldap_groupfilter_objectclass'), + 'ldap_groupfilter_objectclass', + t('user_ldap', 'Select object classes')); $('.lwautosave').change(function() { LdapWizard.save(this); }); $('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter); + $('#toggleRawGroupFilter').click(LdapWizard.toggleRawGroupFilter); LdapConfiguration.refreshConfig(); $('#ldap_action_test_connection').click(function(event){ event.preventDefault(); diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index 205f9b517a2..14a14890bd1 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -48,6 +48,8 @@ class Configuration { 'ldapUserFilterGroups' => null, 'ldapUserFilter' => null, 'ldapGroupFilter' => null, + 'ldapGroupFilterObjectclass' => null, + 'ldapGroupFilterGroups' => null, 'ldapGroupDisplayName' => null, 'ldapGroupMemberAssocAttr' => null, 'ldapLoginFilter' => null, @@ -129,6 +131,8 @@ class Configuration { case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': case 'ldapUserFilterGroups': + case 'ldapGroupFilterObjectclass': + case 'ldapGroupFilterGroups': case 'ldapLoginFilterAttributes': $setMethod = 'setMultiLine'; default: @@ -158,6 +162,8 @@ class Configuration { case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': case 'ldapUserFilterGroups': + case 'ldapGroupFilterObjectclass': + case 'ldapGroupFilterGroups': case 'ldapLoginFilterAttributes': $readMethod = 'getMultiLine'; break; @@ -199,6 +205,8 @@ class Configuration { case 'ldapAttributesForGroupSearch': case 'ldapUserFilterObjectclass': case 'ldapUserFilterGroups': + case 'ldapGroupFilterObjectclass': + case 'ldapGroupFilterGroups': case 'ldapLoginFilterAttributes': if(is_array($value)) { $value = implode("\n", $value); @@ -296,6 +304,8 @@ class Configuration { 'ldap_loginfilter_username' => 1, 'ldap_loginfilter_attributes' => '', 'ldap_group_filter' => 'objectClass=posixGroup', + 'ldap_groupfilter_objectclass' => '', + 'ldap_groupfilter_groups' => '', 'ldap_display_name' => 'cn', 'ldap_group_display_name' => 'cn', 'ldap_tls' => 1, @@ -342,6 +352,8 @@ class Configuration { 'ldap_loginfilter_username' => 'ldapLoginFilterUsername', 'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes', 'ldap_group_filter' => 'ldapGroupFilter', + 'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass', + 'ldap_groupfilter_groups' => 'ldapGroupFilterGroups', 'ldap_display_name' => 'ldapUserDisplayName', 'ldap_group_display_name' => 'ldapGroupDisplayName', 'ldap_tls' => 'ldapTLS', diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 3cbca172515..86cf8d75af6 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -58,6 +58,38 @@ class Wizard extends LDAPUtility { } } + public function countGroups() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + ))) { + return false; + } + + $base = $this->configuration->ldapBase[0]; + $filter = $this->configuration->ldapGroupFilter; + \OCP\Util::writeLog('user_ldap', 'Wiz: g filter '. print_r($filter, true), \OCP\Util::DEBUG); + if(empty($filter)) { + $this->result->addChange('ldap_group_count', 0); + return $this->result; + } + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + $rr = $this->ldap->search($cr, $base, $filter, array('dn')); + if(!$this->ldap->isResource($rr)) { + return false; + } + $entries = $this->ldap->countEntries($cr, $rr); + $entries = ($entries !== false) ? $entries : 0; + $this->result->addChange('ldap_group_count', $entries); + + return $this->result; + } + public function countUsers() { if(!$this->checkRequirements(array('ldapHost', 'ldapPort', @@ -152,7 +184,26 @@ class Wizard extends LDAPUtility { * @brief detects the available LDAP groups * @returns the instance's WizardResult instance */ - public function determineGroups() { + public function determineGroupsForGroups() { + return $this->determineGroups('ldap_groupfilter_groups', + 'ldapGroupFilterGroups', + false); + } + + /** + * @brief detects the available LDAP groups + * @returns the instance's WizardResult instance + */ + public function determineGroupsForUsers() { + return $this->determineGroups('ldap_userfilter_groups', + 'ldapUserFilterGroups'); + } + + /** + * @brief detects the available LDAP groups + * @returns the instance's WizardResult instance + */ + private function determineGroups($dbkey, $confkey, $testMemberOf = true) { if(!$this->checkRequirements(array('ldapHost', 'ldapPort', 'ldapAgentName', @@ -167,15 +218,13 @@ class Wizard extends LDAPUtility { } $obclasses = array('posixGroup', 'group', '*'); - $this->determineFeature($obclasses, - 'cn', - 'ldap_userfilter_groups', - 'ldapUserFilterGroups'); + $this->determineFeature($obclasses, 'cn', $dbkey, $confkey); - $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); - $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST); - if(!$this->configuration->hasMemberOfFilterSupport) { - throw new \Exception('memberOf is not supported by the server'); + if($testMemberOf) { + $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); + if(!$this->configuration->hasMemberOfFilterSupport) { + throw new \Exception('memberOf is not supported by the server'); + } } return $this->result; @@ -185,7 +234,35 @@ class Wizard extends LDAPUtility { * @brief detects the available object classes * @returns the instance's WizardResult instance */ - public function determineObjectClasses() { + public function determineGroupObjectClasses() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + ))) { + return false; + } + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + + $obclasses = array('group', 'posixGroup', '*'); + $this->determineFeature($obclasses, + 'objectclass', + 'ldap_groupfilter_objectclass', + 'ldapGroupFilterObjectclass', + false); + + return $this->result; + } + + /** + * @brief detects the available object classes + * @returns the instance's WizardResult instance + */ + public function determineUserObjectClasses() { if(!$this->checkRequirements(array('ldapHost', 'ldapPort', 'ldapAgentName', @@ -201,12 +278,30 @@ class Wizard extends LDAPUtility { $obclasses = array('inetOrgPerson', 'person', 'organizationalPerson', 'user', 'posixAccount', '*'); + $filter = $this->configuration->ldapUserFilter; + //if filter is empty, it is probably the first time the wizard is called + //then, apply suggestions. $this->determineFeature($obclasses, 'objectclass', 'ldap_userfilter_objectclass', 'ldapUserFilterObjectclass', - true); + empty($filter)); + + return $this->result; + } + + public function getGroupFilter() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapBase', + ))) { + return false; + } + $filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST); + $this->applyFind('ldap_group_filter', $filter); return $this->result; } @@ -482,6 +577,34 @@ class Wizard extends LDAPUtility { } break; + case self::LFILTER_GROUP_LIST: + $objcs = $this->configuration->ldapGroupFilterObjectclass; + //glue objectclasses + if(is_array($objcs) && count($objcs) > 0) { + $filter .= '(|'; + foreach($objcs as $objc) { + $filter .= '(objectclass=' . $objc . ')'; + } + $filter .= ')'; + $parts++; + } + //glue group memberships + $cns = $this->configuration->ldapGroupFilterGroups; + if(is_array($cns) && count($cns) > 0) { + $filter .= '(|'; + $base = $this->configuration->ldapBase[0]; + foreach($cns as $cn) { + $filter .= '(cn=' . $cn . ')'; + } + $filter .= ')'; + } + $parts++; + //wrap parts in AND condition + if($parts > 1) { + $filter = '(&' . $filter . ')'; + } + break; + case self::LFILTER_LOGIN: $ulf = $this->configuration->ldapUserFilter; $loginpart = '=%uid'; @@ -541,7 +664,7 @@ class Wizard extends LDAPUtility { \OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG); - return empty($filter) ? false : $filter; + return $filter; } /** @@ -730,7 +853,8 @@ class Wizard extends LDAPUtility { } else if($po && !empty($maxEntryObjC)) { //pre-select objectclass with most result entries $maxEntryObjC = str_replace($p, '', $maxEntryObjC); - $this->result->addChange($dbkey, $maxEntryObjC); + $this->applyFind($dbkey, $maxEntryObjC); +// $this->result->addChange($dbkey, $maxEntryObjC); } return $availableFeatures; diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php index 299e98fe090..77bd26a52d9 100644 --- a/apps/user_ldap/settings.php +++ b/apps/user_ldap/settings.php @@ -45,22 +45,22 @@ $wControls = $wControls->fetchPage(); $sControls = new OCP\Template('user_ldap', 'part.settingcontrols'); $sControls = $sControls->fetchPage(); -$wizard1 = new OCP\Template('user_ldap', 'part.wizard-server'); -$wizard1->assign('serverConfigurationPrefixes', $prefixes); -$wizard1->assign('serverConfigurationHosts', $hosts); -$wizard1->assign('wizardControls', $wControls); -$wizardHtml .= $wizard1->fetchPage(); -$toc['#ldapWizard1'] = 'Server'; +$wizTabs = array(); +$wizTabs[] = array('tpl' => 'part.wizard-server', 'cap' => 'Server'); +$wizTabs[] = array('tpl' => 'part.wizard-userfilter', 'cap' => 'User Filter'); +$wizTabs[] = array('tpl' => 'part.wizard-loginfilter', 'cap' => 'Login Filter'); +$wizTabs[] = array('tpl' => 'part.wizard-groupfilter', 'cap' => 'Group Filter'); -$wizard2 = new OCP\Template('user_ldap', 'part.wizard-userfilter'); -$wizard2->assign('wizardControls', $wControls); -$wizardHtml .= $wizard2->fetchPage(); -$toc['#ldapWizard2'] = 'User Filter'; - -$wizard3 = new OCP\Template('user_ldap', 'part.wizard-loginfilter'); -$wizard3->assign('wizardControls', $wControls); -$wizardHtml .= $wizard3->fetchPage(); -$toc['#ldapWizard3'] = 'Login Filter'; +for($i = 0; $i < count($wizTabs); $i++) { + $tab = new OCP\Template('user_ldap', $wizTabs[$i]['tpl']); + if($i === 0) { + $tab->assign('serverConfigurationPrefixes', $prefixes); + $tab->assign('serverConfigurationHosts', $hosts); + } + $tab->assign('wizardControls', $wControls); + $wizardHtml .= $tab->fetchPage(); + $toc['#ldapWizard'.($i+1)] = $wizTabs[$i]['cap']; +} $tmpl->assign('tabs', $wizardHtml); $tmpl->assign('toc', $toc); -- cgit v1.2.3 From 109ddde944ae17621c4680d9c7172eb585b1626d Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Thu, 10 Oct 2013 01:21:05 +0200 Subject: Wizard: autodetection of group-member-assoc attribute --- apps/user_ldap/ajax/wizard.php | 1 + apps/user_ldap/js/settings.js | 16 ++++++++++ apps/user_ldap/lib/wizard.php | 61 +++++++++++++++++++++++++++++++++++++ apps/user_ldap/lib/wizardresult.php | 7 ++++- 4 files changed, 84 insertions(+), 1 deletion(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index ebeedaee959..c90efdf7e9e 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -46,6 +46,7 @@ $wizard = new \OCA\user_ldap\lib\Wizard($configuration, $ldapWrapper); switch($action) { case 'guessPortAndTLS': case 'guessBaseDN': + case 'determineGroupMemberAssoc': case 'determineUserObjectClasses': case 'determineGroupObjectClasses': case 'determineGroupsForUsers': diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 049df9b8b17..6b1f363bbaf 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -226,6 +226,7 @@ var LdapWizard = { LdapWizard.countUsers(); } else if(type == 'group') { LdapWizard.countGroups(); + LdapWizard.detectGroupMemberAssoc(); } }, function (result) { @@ -256,6 +257,20 @@ var LdapWizard = { LdapWizard._countThings('countUsers'); }, + detectGroupMemberAssoc: function() { + param = 'action=determineGroupMemberAssoc'+ + '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + + LdapWizard.ajax(param, + function(result) { + //pure background story + }, + function (result) { + // error handling + } + ); + }, + findAttributes: function() { param = 'action=determineAttributes'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -395,6 +410,7 @@ var LdapWizard = { LdapWizard.countUsers(); } else if(triggerObj.id == 'ldap_group_filter') { LdapWizard.countGroups(); + LdapWizard.detectGroupMemberAssoc(); } if(triggerObj.id == 'ldap_loginfilter_username' diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 86cf8d75af6..2538fe4a2c5 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -230,6 +230,26 @@ class Wizard extends LDAPUtility { return $this->result; } + public function determineGroupMemberAssoc() { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapAgentName', + 'ldapAgentPassword', + 'ldapGroupFilter', + ))) { + return false; + } + $attribute = $this->detectGroupMemberAssoc(); + if($attribute === false) { + return false; + } + $this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute)); + //so it will be saved on destruct + $this->result->markChange(); + + return $this->result; + } + /** * @brief detects the available object classes * @returns the instance's WizardResult instance @@ -462,6 +482,47 @@ class Wizard extends LDAPUtility { } } + /** + * @brief tries to detect the group member association attribute which is + * one of 'uniqueMember', 'memberUid', 'member' + * @return mixed, string with the attribute name, false on error + */ + private function detectGroupMemberAssoc() { + $possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'unfugasdfasdfdfa'); + $filter = $this->configuration->ldapGroupFilter; + if(empty($filter)) { + return false; + } + $cr = $this->getConnection(); + if(!$cr) { + throw new \Excpetion('Could not connect to LDAP'); + } + $base = $this->configuration->ldapBase[0]; + $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs); + if(!$this->ldap->isResource($rr)) { + return false; + } + $er = $this->ldap->firstEntry($cr, $rr); + while(is_resource($er)) { + $dn = $this->ldap->getDN($cr, $er); + $attrs = $this->ldap->getAttributes($cr, $er); + $result = array(); + for($i = 0; $i < count($possibleAttrs); $i++) { + if(isset($attrs[$possibleAttrs[$i]])) { + $result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count']; + } + } + if(!empty($result)) { + natsort($result); + return key($result); + } + + $er = $this->ldap->nextEntry($cr, $er); + } + + return false; + } + /** * @brief Checks whether for a given BaseDN results will be returned * @param $base the BaseDN to test diff --git a/apps/user_ldap/lib/wizardresult.php b/apps/user_ldap/lib/wizardresult.php index 4c3b563c0c2..542f106cad8 100644 --- a/apps/user_ldap/lib/wizardresult.php +++ b/apps/user_ldap/lib/wizardresult.php @@ -26,11 +26,16 @@ namespace OCA\user_ldap\lib; class WizardResult { protected $changes = array(); protected $options = array(); + protected $markedChange = false; public function addChange($key, $value) { $this->changes[$key] = $value; } + public function markChange() { + $this->markedChange = true; + } + public function addOptions($key, $values) { if(!is_array($values)) { $values = array($values); @@ -39,7 +44,7 @@ class WizardResult { } public function hasChanges() { - return count($this->changes) > 0; + return (count($this->changes) > 0 || $this->markedChange); } public function getResultArray() { -- cgit v1.2.3 From f64ae7510708e50a416448b4eccb6b0535f2faa6 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Thu, 10 Oct 2013 19:37:12 +0200 Subject: LDAP Wizard: fix couple more or less nasty bugs aka polishing --- apps/user_ldap/js/settings.js | 39 ++++++++++++++++++++++++++++++++++-- apps/user_ldap/lib/configuration.php | 8 ++++---- apps/user_ldap/lib/wizard.php | 22 +++++++++++--------- apps/user_ldap/settings.php | 1 + 4 files changed, 54 insertions(+), 16 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 6b1f363bbaf..df5de874601 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -155,14 +155,16 @@ var LdapWizard = { $('#'+id).val(result.changes[id]); } } + LdapWizard.functionalityCheck(); }, checkBaseDN: function() { host = $('#ldap_host').val(); + port = $('#ldap_port').val(); user = $('#ldap_dn').val(); pass = $('#ldap_agent_password').val(); - if(host && user && pass) { + if(host && port && user && pass) { param = 'action=guessBaseDN'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -195,6 +197,7 @@ var LdapWizard = { function(result) { LdapWizard.applyChanges(result); if($('#ldap_port').val()) { + LdapWizard.checkBaseDN(); $('#ldap_port').removeClass('invisible'); LdapWizard.hideInfoBox(); } @@ -346,6 +349,29 @@ var LdapWizard = { ); }, + functionalityCheck: function() { + //criterias to enable the connection: + // - host, port, user filter, login filter + host = $('#ldap_host').val(); + port = $('#ldap_port').val(); + userfilter = $('#ldap_dn').val(); + loginfilter = $('#ldap_agent_password').val(); + + //FIXME: activates a manually deactivated configuration. + if(host && port && userfilter && loginfilter) { + if($('#ldap_configuration_active').is(':checked')) { + return; + } + $('#ldap_configuration_active').prop('checked', true); + LdapWizard.save($('#ldap_configuration_active')[0]); + } else { + if($('#ldap_configuration_active').is(':checked')) { + $('#ldap_configuration_active').prop('checked', false); + LdapWizard.save($('#ldap_configuration_active')[0]); + } + } + }, + hideInfoBox: function() { if(LdapWizard.checkInfoShown) { $('#ldapWizard1 .ldapWizardInfo').addClass('invisible'); @@ -362,11 +388,13 @@ var LdapWizard = { initGroupFilter: function() { LdapWizard.findObjectClasses('ldap_groupfilter_objectclass', 'Group'); LdapWizard.findAvailableGroups('ldap_groupfilter_groups', 'Groups'); + LdapWizard.composeFilter('group'); LdapWizard.countGroups(); }, initLoginFilter: function() { LdapWizard.findAttributes(); + LdapWizard.composeFilter('login'); }, initMultiSelect: function(object, id, caption) { @@ -384,6 +412,7 @@ var LdapWizard = { initUserFilter: function() { LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User'); LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users'); + LdapWizard.composeFilter('user'); LdapWizard.countUsers(); }, @@ -403,7 +432,10 @@ var LdapWizard = { || triggerObj.id == 'ldap_dn' || triggerObj.id == 'ldap_agent_password') { LdapWizard.checkPort(); - LdapWizard.checkBaseDN(); + if($('#ldap_port').val()) { + //if Port is already set, check BaseDN + LdapWizard.checkBaseDN(); + } } if(triggerObj.id == 'ldap_userlist_filter') { @@ -442,6 +474,9 @@ var LdapWizard = { if(originalObj == 'ldap_userfilter_objectclass' || originalObj == 'ldap_userfilter_groups') { LdapWizard.composeFilter('user'); + //when user filter is changed afterwards, login filter needs to + //be adjusted, too + LdapWizard.composeFilter('login'); } else if(originalObj == 'ldap_loginfilter_attributes') { LdapWizard.composeFilter('login'); } else if(originalObj == 'ldap_groupfilter_objectclass' diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index e1e5d2b65d6..2fb566aec6f 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -287,7 +287,7 @@ class Configuration { public function getDefaults() { return array( 'ldap_host' => '', - 'ldap_port' => '389', + 'ldap_port' => '', 'ldap_backup_host' => '', 'ldap_backup_port' => '', 'ldap_override_main_server' => '', @@ -296,14 +296,14 @@ class Configuration { 'ldap_base' => '', 'ldap_base_users' => '', 'ldap_base_groups' => '', - 'ldap_userlist_filter' => 'objectClass=person', + 'ldap_userlist_filter' => '', 'ldap_userfilter_objectclass' => '', 'ldap_userfilter_groups' => '', 'ldap_login_filter' => 'uid=%uid', 'ldap_loginfilter_email' => 0, 'ldap_loginfilter_username' => 1, 'ldap_loginfilter_attributes' => '', - 'ldap_group_filter' => 'objectClass=posixGroup', + 'ldap_group_filter' => '', 'ldap_groupfilter_objectclass' => '', 'ldap_groupfilter_groups' => '', 'ldap_display_name' => 'displayName', @@ -319,7 +319,7 @@ class Configuration { 'ldap_override_uuid_attribute' => 0, 'home_folder_naming_rule' => '', 'ldap_turn_off_cert_check' => 0, - 'ldap_configuration_active' => 1, + 'ldap_configuration_active' => 0, 'ldap_attributes_for_user_search' => '', 'ldap_attributes_for_group_search' => '', 'ldap_expert_username_attr' => '', diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 2538fe4a2c5..a1d635faaea 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -38,6 +38,8 @@ class Wizard extends LDAPUtility { const LFILTER_USER_LIST = 3; const LFILTER_GROUP_LIST = 4; + const LDAP_NW_TIMEOUT = 4; + /** * @brief Constructor * @param $configuration an instance of Configuration @@ -222,6 +224,7 @@ class Wizard extends LDAPUtility { if($testMemberOf) { $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf(); + $this->result->markChange(); if(!$this->configuration->hasMemberOfFilterSupport) { throw new \Exception('memberOf is not supported by the server'); } @@ -375,7 +378,6 @@ class Wizard extends LDAPUtility { } $this->checkHost(); $portSettings = $this->getPortSettingsToTry(); - file_put_contents('/tmp/ps', print_r($portSettings, true).PHP_EOL, FILE_APPEND); if(!is_array($portSettings)) { throw new \Exception(print_r($portSettings, true)); @@ -763,10 +765,10 @@ class Wizard extends LDAPUtility { \OCP\Util::writeLog('user_ldap', 'Wiz: Setting LDAP Options ', \OCP\Util::DEBUG); //set LDAP options - if($this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3)) { - if($tls) { - $this->ldap->startTls($cr); - } + $a = $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); + $c = $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); + if($tls) { + $this->ldap->startTls($cr); } \OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG); @@ -915,7 +917,7 @@ class Wizard extends LDAPUtility { //pre-select objectclass with most result entries $maxEntryObjC = str_replace($p, '', $maxEntryObjC); $this->applyFind($dbkey, $maxEntryObjC); -// $this->result->addChange($dbkey, $maxEntryObjC); + $this->result->addChange($dbkey, $maxEntryObjC); } return $availableFeatures; @@ -962,10 +964,10 @@ class Wizard extends LDAPUtility { $this->configuration->ldapHost.':'.$this->configuration->ldapPort, $this->configuration->ldapPort); - if($this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3)) { - if($this->configuration->ldapTLS === 1) { - $this->ldap->startTls($cr); - } + $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3); + $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT); + if($this->configuration->ldapTLS === 1) { + $this->ldap->startTls($cr); } $lo = @$this->ldap->bind($cr, diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php index 5d3306246df..d077eafdde9 100644 --- a/apps/user_ldap/settings.php +++ b/apps/user_ldap/settings.php @@ -64,6 +64,7 @@ for($i = 0; $i < count($wizTabs); $i++) { $tmpl->assign('tabs', $wizardHtml); $tmpl->assign('toc', $toc); +$tmpl->assign('settingControls', $sControls); // assign default values $config = new \OCA\user_ldap\lib\Configuration('', false); -- cgit v1.2.3 From 63e9c56d48b257fd155de9fa6a978d2bfadffc1f Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Thu, 17 Oct 2013 13:05:14 +0200 Subject: LDAP Wizard: Use Ajax Spinner to indicate something is happening, especiall port detection --- apps/user_ldap/css/settings.css | 5 +++++ apps/user_ldap/js/settings.js | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index 2f12108b090..65bff3aadb7 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -5,6 +5,7 @@ .tablecell { display: table-cell !important; + white-space: nowrap; } .tablerow { @@ -75,6 +76,10 @@ color: #FF3B3B; } +.wizSpinner { + height: 15px; +} + #ldap fieldset p label { width: 20%; max-width: 200px; diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index df5de874601..0ccf7ecf425 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -128,6 +128,7 @@ var LdapWizard = { checkPortInfoShown: false, saveBlacklist: {}, userFilterGroupSelectState: 'enable', + spinner: '', ajax: function(param, fnOnSuccess, fnOnError) { $.post( @@ -168,15 +169,18 @@ var LdapWizard = { param = 'action=guessBaseDN'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + LdapWizard.showSpinner('#ldap_base'); LdapWizard.ajax(param, function(result) { LdapWizard.applyChanges(result); + LdapWizard.hideSpinner('#ldap_base'); if($('#ldap_base').val()) { $('#ldap_base').removeClass('invisible'); LdapWizard.hideInfoBox(); } }, function (result) { + LdapWizard.hideSpinner('#ldap_base'); $('#ldap_base').removeClass('invisible'); LdapWizard.showInfoBox('Please specify a port'); } @@ -193,9 +197,11 @@ var LdapWizard = { param = 'action=guessPortAndTLS'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + LdapWizard.showSpinner('#ldap_port'); LdapWizard.ajax(param, function(result) { LdapWizard.applyChanges(result); + LdapWizard.hideSpinner('#ldap_port'); if($('#ldap_port').val()) { LdapWizard.checkBaseDN(); $('#ldap_port').removeClass('invisible'); @@ -203,6 +209,7 @@ var LdapWizard = { } }, function (result) { + LdapWizard.hideSpinner('#ldap_port'); $('#ldap_port').removeClass('invisible'); LdapWizard.showInfoBox('Please specify the BaseDN'); } @@ -278,6 +285,7 @@ var LdapWizard = { param = 'action=determineAttributes'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + LdapWizard.showSpinner('#ldap_loginfilter_attributes'); LdapWizard.ajax(param, function(result) { $('#ldap_loginfilter_attributes').find('option').remove(); @@ -287,6 +295,7 @@ var LdapWizard = { $('#ldap_loginfilter_attributes').append( ""); } + LdapWizard.hideSpinner('#ldap_loginfilter_attributes'); LdapWizard.applyChanges(result); $('#ldap_loginfilter_attributes').multiselect('refresh'); $('#ldap_loginfilter_attributes').multiselect('enable'); @@ -296,6 +305,7 @@ var LdapWizard = { $('#ldap_loginfilter_attributes').multiselect( {noneSelectedText : 'No attributes found'}); $('#ldap_loginfilter_attributes').multiselect('disable'); + LdapWizard.hideSpinner('#ldap_loginfilter_attributes'); } ); }, @@ -307,6 +317,7 @@ var LdapWizard = { param = 'action=determineGroupsFor'+type+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + LdapWizard.showSpinner('#'+multisel); LdapWizard.ajax(param, function(result) { $('#'+multisel).find('option').remove(); @@ -315,11 +326,13 @@ var LdapWizard = { objc = result.options[multisel][i]; $('#'+multisel).append(""); } + LdapWizard.hideSpinner('#'+multisel); LdapWizard.applyChanges(result); $('#'+multisel).multiselect('refresh'); $('#'+multisel).multiselect('enable'); }, function (result) { + LdapWizard.hideSpinner('#'+multisel); $('#'+multisel).multiselect('disable'); } ); @@ -332,6 +345,7 @@ var LdapWizard = { param = 'action=determine'+type+'ObjectClasses'+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); + LdapWizard.showSpinner('#'+multisel); LdapWizard.ajax(param, function(result) { $('#'+multisel).find('option').remove(); @@ -340,10 +354,12 @@ var LdapWizard = { objc = result.options[multisel][i]; $('#'+multisel).append(""); } + LdapWizard.hideSpinner('#'+multisel); LdapWizard.applyChanges(result); $('#'+multisel).multiselect('refresh'); }, function (result) { + LdapWizard.hideSpinner('#'+multisel); //TODO: error handling } ); @@ -379,6 +395,11 @@ var LdapWizard = { } }, + hideSpinner: function(id) { + $(id+' + .wizSpinner').remove(); + $(id + " + button").css('display', 'inline'); + }, + init: function() { if($('#ldap_port').val()) { $('#ldap_port').removeClass('invisible'); @@ -510,6 +531,11 @@ var LdapWizard = { LdapWizard.checkInfoShown = true; }, + showSpinner: function(id) { + $(LdapWizard.spinner).insertAfter($(id)); + $(id + " + img + button").css('display', 'none'); + }, + toggleRawFilter: function(container, moc, mg, stateVar) { if($(container).hasClass('invisible')) { $(container).removeClass('invisible'); -- cgit v1.2.3 From 6b160d8507806f38eaeed2daea2f30621fb000b4 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Thu, 17 Oct 2013 18:33:58 +0200 Subject: LDAP Wizard: make Back and Continue work --- apps/user_ldap/js/settings.js | 58 ++++++++++++++++++++++++ apps/user_ldap/templates/part.wizardcontrols.php | 5 +- 2 files changed, 61 insertions(+), 2 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 0ccf7ecf425..7ce1014a85d 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -159,6 +159,22 @@ var LdapWizard = { LdapWizard.functionalityCheck(); }, + basicStatusCheck: function() { + //criterias to continue from the first tab + // - host, port, user filter, agent dn, password, base dn + host = $('#ldap_host').val(); + port = $('#ldap_port').val(); + agent = $('#ldap_dn').val(); + pwd = $('#ldap_agent_password').val(); + base = $('#ldap_base').val(); + + if(host && port && agent && pwd && base) { + $('.ldap_action_continue').removeAttr('disabled'); + } else { + $('.ldap_action_continue').attr('disabled', 'disabled'); + } + }, + checkBaseDN: function() { host = $('#ldap_host').val(); port = $('#ldap_port').val(); @@ -245,6 +261,35 @@ var LdapWizard = { ); }, + controlBack: function() { + curTabIndex = $('#ldapSettings').tabs('option', 'active'); + if(curTabIndex == 0) { + return; + } + if(curTabIndex == 1) { + $('.ldap_action_back').addClass('invisible'); + } + $('#ldapSettings').tabs('option', 'active', curTabIndex - 1); + if(curTabIndex == 3) { + $('.ldap_action_continue').removeClass('invisible'); + } + }, + + controlContinue: function() { + curTabIndex = $('#ldapSettings').tabs('option', 'active'); + if(curTabIndex == 3) { + return; + } + $('#ldapSettings').tabs('option', 'active', 1 + curTabIndex); + if(curTabIndex == 2) { + //now last tab + $('.ldap_action_continue').addClass('invisible'); + } + if(curTabIndex == 0) { + $('.ldap_action_back').removeClass('invisible'); + } + }, + _countThings: function(method) { param = 'action='+method+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); @@ -404,6 +449,7 @@ var LdapWizard = { if($('#ldap_port').val()) { $('#ldap_port').removeClass('invisible'); } + LdapWizard.basicStatusCheck(); }, initGroupFilter: function() { @@ -470,6 +516,10 @@ var LdapWizard = { || triggerObj.id == 'ldap_loginfilter_email') { LdapWizard.composeFilter('login'); } + + if($('#ldapSettings').tabs('option', 'active') == 0) { + LdapWizard.basicStatusCheck(); + } }, save: function(inputObj) { @@ -595,6 +645,14 @@ $(document).ready(function() { $('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter); $('#toggleRawGroupFilter').click(LdapWizard.toggleRawGroupFilter); LdapConfiguration.refreshConfig(); + $('.ldap_action_continue').click(function(event) { + event.preventDefault(); + LdapWizard.controlContinue(); + }); + $('.ldap_action_back').click(function(event) { + event.preventDefault(); + LdapWizard.controlBack(); + }); $('#ldap_action_test_connection').click(function(event){ event.preventDefault(); $.post( diff --git a/apps/user_ldap/templates/part.wizardcontrols.php b/apps/user_ldap/templates/part.wizardcontrols.php index 4d05586bdfb..db99145d514 100644 --- a/apps/user_ldap/templates/part.wizardcontrols.php +++ b/apps/user_ldap/templates/part.wizardcontrols.php @@ -1,8 +1,9 @@
    - - Date: Thu, 17 Oct 2013 18:55:02 +0200 Subject: Ldap Wizard: also disable tabs, if the first step is not complete --- apps/user_ldap/js/settings.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index 7ce1014a85d..efd9bade1ab 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -170,8 +170,10 @@ var LdapWizard = { if(host && port && agent && pwd && base) { $('.ldap_action_continue').removeAttr('disabled'); + $('#ldapSettings').tabs('option', 'disabled', []); } else { $('.ldap_action_continue').attr('disabled', 'disabled'); + $('#ldapSettings').tabs('option', 'disabled', [1, 2, 3, 4, 5]); } }, -- cgit v1.2.3 From 183dd813d34f870c11bea3a97c9a6b34bc46808b Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Thu, 17 Oct 2013 20:57:19 +0200 Subject: Fix Spinner issues with Base DN field --- apps/user_ldap/js/settings.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'apps/user_ldap/js/settings.js') diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js index efd9bade1ab..faef477420f 100644 --- a/apps/user_ldap/js/settings.js +++ b/apps/user_ldap/js/settings.js @@ -157,6 +157,10 @@ var LdapWizard = { } } LdapWizard.functionalityCheck(); + + if($('#ldapSettings').tabs('option', 'active') == 0) { + LdapWizard.basicStatusCheck(); + } }, basicStatusCheck: function() { @@ -451,6 +455,9 @@ var LdapWizard = { if($('#ldap_port').val()) { $('#ldap_port').removeClass('invisible'); } + if($('#ldap_base').val()) { + $('#ldap_base').removeClass('invisible'); + } LdapWizard.basicStatusCheck(); }, @@ -584,8 +591,10 @@ var LdapWizard = { }, showSpinner: function(id) { - $(LdapWizard.spinner).insertAfter($(id)); - $(id + " + img + button").css('display', 'none'); + if($(id + ' + .wizSpinner').length == 0) { + $(LdapWizard.spinner).insertAfter($(id)); + $(id + " + img + button").css('display', 'none'); + } }, toggleRawFilter: function(container, moc, mg, stateVar) { -- cgit v1.2.3