diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php
new file mode 100644
index 00000000000..e580c097867
--- /dev/null
+++ b/apps/user_ldap/ajax/wizard.php
@@ -0,0 +1,96 @@
+.
+ *
+ */
+
+// Check user and app status
+OCP\JSON::checkAdminUser();
+OCP\JSON::checkAppEnabled('user_ldap');
+OCP\JSON::callCheck();
+
+$l=OC_L10N::get('user_ldap');
+
+if(!isset($_POST['action'])) {
+ \OCP\JSON::error(array('message' => $l->t('No action specified')));
+}
+$action = $_POST['action'];
+
+
+if(!isset($_POST['ldap_serverconfig_chooser'])) {
+ \OCP\JSON::error(array('message' => $l->t('No configuration specified')));
+}
+$prefix = $_POST['ldap_serverconfig_chooser'];
+
+$ldapWrapper = new OCA\user_ldap\lib\LDAP();
+$configuration = new \OCA\user_ldap\lib\Configuration($prefix);
+$wizard = new \OCA\user_ldap\lib\Wizard($configuration, $ldapWrapper);
+
+switch($action) {
+ case 'guessPortAndTLS':
+ case 'guessBaseDN':
+ case 'determineGroupMemberAssoc':
+ 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) {
+ OCP\JSON::success($result->getResultArray());
+ exit;
+ }
+ } catch (\Exception $e) {
+ \OCP\JSON::error(array('message' => $e->getMessage()));
+ exit;
+ }
+ \OCP\JSON::error();
+ exit;
+ break;
+
+ case 'save':
+ $key = isset($_POST['cfgkey']) ? $_POST['cfgkey'] : false;
+ $val = isset($_POST['cfgval']) ? $_POST['cfgval'] : null;
+ if($key === false || is_null($val)) {
+ \OCP\JSON::error(array('message' => $l->t('No data specified')));
+ exit;
+ }
+ $cfg = array($key => $val);
+ $setParameters = array();
+ $configuration->setConfiguration($cfg, $setParameters);
+ if(!in_array($key, $setParameters)) {
+ \OCP\JSON::error(array('message' => $l->t($key.
+ ' Could not set configuration %s', $setParameters[0])));
+ exit;
+ }
+ $configuration->saveConfiguration();
+ OCP\JSON::success();
+ break;
+ default:
+ //TODO: return 4xx error
+ break;
+}
+
diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 9d6327181af..c2cd295523e 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -30,7 +30,7 @@ if(count($configPrefixes) === 1) {
$ldapAccess = new OCA\user_ldap\lib\Access($connector, $ldapWrapper);
$userBackend = new OCA\user_ldap\USER_LDAP($ldapAccess);
$groupBackend = new OCA\user_ldap\GROUP_LDAP($ldapAccess);
-} else {
+} else if(count($configPrefixes) > 1) {
$userBackend = new OCA\user_ldap\User_Proxy($configPrefixes, $ldapWrapper);
$groupBackend = new OCA\user_ldap\Group_Proxy($configPrefixes, $ldapWrapper);
}
diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css
index 6086c7b74e6..65bff3aadb7 100644
--- a/apps/user_ldap/css/settings.css
+++ b/apps/user_ldap/css/settings.css
@@ -1,3 +1,85 @@
+.table {
+ display: table;
+ width: 60%;
+}
+
+.tablecell {
+ display: table-cell !important;
+ white-space: nowrap;
+}
+
+.tablerow {
+ display: table-row;
+}
+
+.tablerow input, .tablerow textarea {
+ width: 100% !important;
+}
+
+.tablerow textarea {
+ height: 15px;
+}
+
+.invisible {
+ visibility: hidden;
+}
+
+.ldapSettingsTabs {
+ float: right !important;
+}
+
+.ldapWizardControls {
+ width: 60%;
+ text-align: right;
+}
+
+.ldapWizardInfo {
+ width: 100% !important;
+ height: 50px;
+ background-color: lightyellow;
+ border-radius: 0.5em;
+ padding: 0.6em 0.5em 0.4em !important;
+ margin-bottom: 0.3em;
+}
+
+#ldapWizard1 .hostPortCombinator {
+ width: 60%;
+ display: table;
+}
+
+#ldapWizard1 .hostPortCombinator div span {
+ width: 7%;
+ display: table-cell;
+ text-align: right;
+}
+
+#ldapWizard1 .host {
+ width: 96.5% !important;
+}
+
+.tableCellInput {
+ margin-left: -40%;
+ width: 100%;
+}
+
+.tableCellLabel {
+ text-align: right;
+ padding-right: 25%;
+}
+
+.ldapIndent {
+ margin-left: 50px;
+}
+
+.ldapwarning {
+ margin-left: 1.4em;
+ color: #FF3B3B;
+}
+
+.wizSpinner {
+ height: 15px;
+}
+
#ldap fieldset p label {
width: 20%;
max-width: 200px;
@@ -9,7 +91,7 @@
}
#ldap fieldset input, #ldap fieldset textarea {
- width: 60%;
+ width: 60%;
display: inline-block;
}
@@ -17,11 +99,9 @@
vertical-align: bottom;
}
-.ldapIndent {
- margin-left: 50px;
-}
-
-.ldapwarning {
- margin-left: 1.4em;
- color: #FF3B3B;
-}
+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 20d6f76dcd6..faef477420f 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,13 +124,546 @@ var LdapConfiguration = {
}
};
+var LdapWizard = {
+ checkPortInfoShown: false,
+ saveBlacklist: {},
+ userFilterGroupSelectState: 'enable',
+ spinner: '',
+
+ 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) {
+ if(!$.isArray(result.changes[id])) {
+ //no need to blacklist multiselect
+ LdapWizard.saveBlacklist[id] = true;
+ }
+ if(id.indexOf('count') > 0) {
+ $('#'+id).text(result.changes[id]);
+ } else {
+ $('#'+id).val(result.changes[id]);
+ }
+ }
+ LdapWizard.functionalityCheck();
+
+ if($('#ldapSettings').tabs('option', 'active') == 0) {
+ LdapWizard.basicStatusCheck();
+ }
+ },
+
+ 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');
+ $('#ldapSettings').tabs('option', 'disabled', []);
+ } else {
+ $('.ldap_action_continue').attr('disabled', 'disabled');
+ $('#ldapSettings').tabs('option', 'disabled', [1, 2, 3, 4, 5]);
+ }
+ },
+
+ checkBaseDN: function() {
+ host = $('#ldap_host').val();
+ port = $('#ldap_port').val();
+ user = $('#ldap_dn').val();
+ pass = $('#ldap_agent_password').val();
+
+ if(host && port && user && pass) {
+ 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');
+ }
+ );
+ }
+ },
+
+ 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.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');
+ LdapWizard.hideInfoBox();
+ }
+ },
+ function (result) {
+ LdapWizard.hideSpinner('#ldap_port');
+ $('#ldap_port').removeClass('invisible');
+ LdapWizard.showInfoBox('Please specify the BaseDN');
+ }
+ );
+ }
+ },
+
+ composeFilter: function(type) {
+ if(type == 'user') {
+ action = 'getUserListFilter';
+ } else if(type == 'login') {
+ action = 'getUserLoginFilter';
+ } else if(type == 'group') {
+ action = 'getGroupFilter';
+ }
+
+ param = 'action='+action+
+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
+
+ LdapWizard.ajax(param,
+ function(result) {
+ LdapWizard.applyChanges(result);
+ if(type == 'user') {
+ LdapWizard.countUsers();
+ } else if(type == 'group') {
+ LdapWizard.countGroups();
+ LdapWizard.detectGroupMemberAssoc();
+ }
+ },
+ function (result) {
+ // error handling
+ }
+ );
+ },
+
+ 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();
+
+ LdapWizard.ajax(param,
+ function(result) {
+ LdapWizard.applyChanges(result);
+ },
+ function (result) {
+ // error handling
+ }
+ );
+ },
+
+ countGroups: function() {
+ LdapWizard._countThings('countGroups');
+ },
+
+ countUsers: function() {
+ 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();
+
+ LdapWizard.showSpinner('#ldap_loginfilter_attributes');
+ 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.hideSpinner('#ldap_loginfilter_attributes');
+ 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');
+ LdapWizard.hideSpinner('#ldap_loginfilter_attributes');
+ }
+ );
+ },
+
+ findAvailableGroups: function(multisel, type) {
+ if(type != 'Users' && type != 'Groups') {
+ return false;
+ }
+ param = 'action=determineGroupsFor'+type+
+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
+
+ LdapWizard.showSpinner('#'+multisel);
+ LdapWizard.ajax(param,
+ function(result) {
+ $('#'+multisel).find('option').remove();
+ for (i in result.options[multisel]) {
+ //FIXME: move HTML into template
+ 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');
+ }
+ );
+ },
+
+ findObjectClasses: function(multisel, type) {
+ if(type != 'User' && type != 'Group') {
+ return false;
+ }
+ param = 'action=determine'+type+'ObjectClasses'+
+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
+
+ LdapWizard.showSpinner('#'+multisel);
+ LdapWizard.ajax(param,
+ function(result) {
+ $('#'+multisel).find('option').remove();
+ for (i in result.options[multisel]) {
+ //FIXME: move HTML into template
+ objc = result.options[multisel][i];
+ $('#'+multisel).append("");
+ }
+ LdapWizard.hideSpinner('#'+multisel);
+ LdapWizard.applyChanges(result);
+ $('#'+multisel).multiselect('refresh');
+ },
+ function (result) {
+ LdapWizard.hideSpinner('#'+multisel);
+ //TODO: error handling
+ }
+ );
+ },
+
+ 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');
+ LdapWizard.checkInfoShown = false;
+ }
+ },
+
+ hideSpinner: function(id) {
+ $(id+' + .wizSpinner').remove();
+ $(id + " + button").css('display', 'inline');
+ },
+
+ init: function() {
+ if($('#ldap_port').val()) {
+ $('#ldap_port').removeClass('invisible');
+ }
+ if($('#ldap_base').val()) {
+ $('#ldap_base').removeClass('invisible');
+ }
+ LdapWizard.basicStatusCheck();
+ },
+
+ 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) {
+ object.multiselect({
+ header: false,
+ selectedList: 9,
+ noneSelectedText: caption,
+ click: function(event, ui) {
+ LdapWizard.saveMultiSelect(id,
+ $('#'+id).multiselect("getChecked"));
+ }
+ });
+ },
+
+ initUserFilter: function() {
+ LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User');
+ LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users');
+ LdapWizard.composeFilter('user');
+ LdapWizard.countUsers();
+ },
+
+ onTabChange: function(event, ui) {
+ if(ui.newTab[0].id === '#ldapWizard2') {
+ LdapWizard.initUserFilter();
+ } else if(ui.newTab[0].id === '#ldapWizard3') {
+ LdapWizard.initLoginFilter();
+ } else if(ui.newTab[0].id === '#ldapWizard4') {
+ LdapWizard.initGroupFilter();
+ }
+ },
+
+ processChanges: function(triggerObj) {
+ if(triggerObj.id == 'ldap_host'
+ || triggerObj.id == 'ldap_port'
+ || triggerObj.id == 'ldap_dn'
+ || triggerObj.id == 'ldap_agent_password') {
+ LdapWizard.checkPort();
+ if($('#ldap_port').val()) {
+ //if Port is already set, check BaseDN
+ LdapWizard.checkBaseDN();
+ }
+ }
+
+ if(triggerObj.id == 'ldap_userlist_filter') {
+ LdapWizard.countUsers();
+ } else if(triggerObj.id == 'ldap_group_filter') {
+ LdapWizard.countGroups();
+ LdapWizard.detectGroupMemberAssoc();
+ }
+
+ if(triggerObj.id == 'ldap_loginfilter_username'
+ || triggerObj.id == 'ldap_loginfilter_email') {
+ LdapWizard.composeFilter('login');
+ }
+
+ if($('#ldapSettings').tabs('option', 'active') == 0) {
+ LdapWizard.basicStatusCheck();
+ }
+ },
+
+ save: function(inputObj) {
+ if(LdapWizard.saveBlacklist.hasOwnProperty(inputObj.id)) {
+ delete LdapWizard.saveBlacklist[inputObj.id];
+ return;
+ }
+ if($(inputObj).is('input[type=checkbox]')
+ && !$(inputObj).is(':checked')) {
+ val = 0;
+ } else {
+ val = $(inputObj).val();
+ }
+ LdapWizard._save(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));
+ 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'
+ || originalObj == 'ldap_groupfilter_groups') {
+ LdapWizard.composeFilter('group');
+ }
+ },
+
+ _save: function(object, value) {
+ param = 'cfgkey='+object.id+
+ '&cfgval='+value+
+ '&action=save'+
+ '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
+
+ $.post(
+ OC.filePath('user_ldap','ajax','wizard.php'),
+ param,
+ function(result) {
+ if(result.status == 'success') {
+ LdapWizard.processChanges(object);
+ } else {
+// alert('Oooooooooooh :(');
+ }
+ }
+ );
+ },
+
+ showInfoBox: function(text) {
+ $('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', text));
+ $('#ldapWizard1 .ldapWizardInfo').removeClass('invisible');
+ LdapWizard.checkInfoShown = true;
+ },
+
+ showSpinner: function(id) {
+ if($(id + ' + .wizSpinner').length == 0) {
+ $(LdapWizard.spinner).insertAfter($(id));
+ $(id + " + img + button").css('display', 'none');
+ }
+ },
+
+ 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 {
+ LdapWizard[stateVar] = 'enable';
+ }
+ $(mg).multiselect('disable');
+ } else {
+ $(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'
+ );
+ }
+};
+
$(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();
+ 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'));
+ 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_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/lib/access.php b/apps/user_ldap/lib/access.php
index 0d6cc7cfd27..0d4b09bac7e 100644
--- a/apps/user_ldap/lib/access.php
+++ b/apps/user_ldap/lib/access.php
@@ -831,7 +831,7 @@ class Access extends LDAPUtility {
private function combineFilter($filters, $operator) {
$combinedFilter = '('.$operator;
foreach($filters as $filter) {
- if($filter[0] !== '(') {
+ if(!empty($filter) && $filter[0] !== '(') {
$filter = '('.$filter.')';
}
$combinedFilter.=$filter;
diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php
new file mode 100644
index 00000000000..c8bf1c09482
--- /dev/null
+++ b/apps/user_ldap/lib/configuration.php
@@ -0,0 +1,384 @@
+.
+ *
+ */
+
+namespace OCA\user_ldap\lib;
+
+class Configuration {
+
+ protected $configPrefix = null;
+ protected $configRead = false;
+
+ //settings
+ protected $config = array(
+ 'ldapHost' => null,
+ 'ldapPort' => null,
+ 'ldapBackupHost' => null,
+ 'ldapBackupPort' => null,
+ 'ldapBase' => null,
+ 'ldapBaseUsers' => null,
+ 'ldapBaseGroups' => null,
+ 'ldapAgentName' => null,
+ 'ldapAgentPassword' => null,
+ 'ldapTLS' => null,
+ 'ldapNoCase' => null,
+ 'turnOffCertCheck' => null,
+ 'ldapIgnoreNamingRules' => null,
+ 'ldapUserDisplayName' => null,
+ 'ldapUserFilterObjectclass' => null,
+ 'ldapUserFilterGroups' => null,
+ 'ldapUserFilter' => null,
+ 'ldapGroupFilter' => null,
+ 'ldapGroupFilterObjectclass' => null,
+ 'ldapGroupFilterGroups' => null,
+ 'ldapGroupDisplayName' => null,
+ 'ldapGroupMemberAssocAttr' => null,
+ 'ldapLoginFilter' => null,
+ 'ldapLoginFilterEmail' => null,
+ 'ldapLoginFilterUsername' => null,
+ 'ldapLoginFilterAttributes' => null,
+ 'ldapQuotaAttribute' => null,
+ 'ldapQuotaDefault' => null,
+ 'ldapEmailAttribute' => null,
+ 'ldapCacheTTL' => null,
+ 'ldapUuidUserAttribute' => 'auto',
+ 'ldapUuidGroupAttribute' => 'auto',
+ 'ldapOverrideMainServer' => false,
+ 'ldapConfigurationActive' => false,
+ 'ldapAttributesForUserSearch' => null,
+ 'ldapAttributesForGroupSearch' => null,
+ 'homeFolderNamingRule' => null,
+ 'hasPagedResultSupport' => false,
+ 'hasMemberOfFilterSupport' => false,
+ 'ldapExpertUsernameAttr' => null,
+ 'ldapExpertUUIDUserAttr' => null,
+ 'ldapExpertUUIDGroupAttr' => null,
+ );
+
+ public function __construct($configPrefix, $autoread = true) {
+ $this->configPrefix = $configPrefix;
+ if($autoread) {
+ $this->readConfiguration();
+ }
+ }
+
+ public function __get($name) {
+ if(isset($this->config[$name])) {
+ return $this->config[$name];
+ }
+ }
+
+ public function __set($name, $value) {
+ $this->setConfiguration(array($name => $value));
+ }
+
+ public function getConfiguration() {
+ return $this->config;
+ }
+
+ /**
+ * @brief set LDAP configuration with values delivered by an array, not read
+ * from configuration. It does not save the configuration! To do so, you
+ * must call saveConfiguration afterwards.
+ * @param $config array that holds the config parameters in an associated
+ * array
+ * @param &$applied optional; array where the set fields will be given to
+ * @return null
+ */
+ public function setConfiguration($config, &$applied = null) {
+ if(!is_array($config)) {
+ return false;
+ }
+
+ $cta = $this->getConfigTranslationArray();
+ foreach($config as $inputkey => $val) {
+ if(strpos($inputkey, '_') !== false && isset($cta[$inputkey])) {
+ $key = $cta[$inputkey];
+ } elseif(isset($this->config[$inputkey])) {
+ $key = $inputkey;
+ } else {
+ continue;
+ }
+
+ $setMethod = 'setValue';
+ switch($key) {
+ case 'homeFolderNamingRule':
+ if(!empty($val) && strpos($val, 'attr:') === false) {
+ $val = 'attr:'.$val;
+ }
+ case 'ldapBase':
+ case 'ldapBaseUsers':
+ case 'ldapBaseGroups':
+ case 'ldapAttributesForUserSearch':
+ case 'ldapAttributesForGroupSearch':
+ case 'ldapUserFilterObjectclass':
+ case 'ldapUserFilterGroups':
+ case 'ldapGroupFilterObjectclass':
+ case 'ldapGroupFilterGroups':
+ case 'ldapLoginFilterAttributes':
+ $setMethod = 'setMultiLine';
+ default:
+ $this->$setMethod($key, $val);
+ if(is_array($applied)) {
+ $applied[] = $inputkey;
+ }
+ }
+ }
+
+ }
+
+ public function readConfiguration() {
+ if(!$this->configRead && !is_null($this->configPrefix)) {
+ $cta = array_flip($this->getConfigTranslationArray());
+ foreach($this->config as $key => $val) {
+ if(!isset($cta[$key])) {
+ //some are determined
+ continue;
+ }
+ $dbkey = $cta[$key];
+ switch($key) {
+ case 'ldapBase':
+ case 'ldapBaseUsers':
+ case 'ldapBaseGroups':
+ case 'ldapAttributesForUserSearch':
+ case 'ldapAttributesForGroupSearch':
+ case 'ldapUserFilterObjectclass':
+ case 'ldapUserFilterGroups':
+ case 'ldapGroupFilterObjectclass':
+ case 'ldapGroupFilterGroups':
+ case 'ldapLoginFilterAttributes':
+ $readMethod = 'getMultiLine';
+ break;
+ case 'ldapIgnoreNamingRules':
+ $readMethod = 'getSystemValue';
+ $dbkey = $key;
+ break;
+ case 'ldapAgentPassword':
+ $readMethod = 'getPwd';
+ break;
+ case 'ldapUserDisplayName':
+ case 'ldapGroupDisplayName':
+ $readMethod = 'getLcValue';
+ break;
+ default:
+ $readMethod = 'getValue';
+ break;
+ }
+ $this->config[$key] = $this->$readMethod($dbkey);
+ }
+ $this->configRead = true;
+ }
+ }
+
+ /**
+ * @brief saves the current Configuration in the database
+ */
+ public function saveConfiguration() {
+ $cta = array_flip($this->getConfigTranslationArray());
+ foreach($this->config as $key => $value) {
+ switch ($key) {
+ case 'ldapAgentPassword':
+ $value = base64_encode($value);
+ break;
+ case 'ldapBase':
+ case 'ldapBaseUsers':
+ case 'ldapBaseGroups':
+ case 'ldapAttributesForUserSearch':
+ case 'ldapAttributesForGroupSearch':
+ case 'ldapUserFilterObjectclass':
+ case 'ldapUserFilterGroups':
+ case 'ldapGroupFilterObjectclass':
+ case 'ldapGroupFilterGroups':
+ case 'ldapLoginFilterAttributes':
+ if(is_array($value)) {
+ $value = implode("\n", $value);
+ }
+ break;
+ //following options are not stored but detected, skip them
+ case 'ldapIgnoreNamingRules':
+ case 'hasPagedResultSupport':
+ case 'ldapUuidUserAttribute':
+ case 'ldapUuidGroupAttribute':
+ continue 2;
+ }
+ if(is_null($value)) {
+ $value = '';
+ }
+ $this->saveValue($cta[$key], $value);
+ }
+ }
+
+ protected function getMultiLine($varname) {
+ $value = $this->getValue($varname);
+ if(empty($value)) {
+ $value = '';
+ } else {
+ $value = preg_split('/\r\n|\r|\n/', $value);
+ }
+
+ return $value;
+ }
+
+ protected function setMultiLine($varname, $value) {
+ if(empty($value)) {
+ $value = '';
+ } else {
+ $value = preg_split('/\r\n|\r|\n/', $value);
+ if($value === false) {
+ $value = '';
+ }
+ }
+
+ $this->setValue($varname, $value);
+ }
+
+ protected function getPwd($varname) {
+ return base64_decode($this->getValue($varname));
+ }
+
+ protected function getLcValue($varname) {
+ return mb_strtolower($this->getValue($varname), 'UTF-8');
+ }
+
+ protected function getSystemValue($varname) {
+ //FIXME: if another system value is added, softcode the default value
+ return \OCP\Config::getSystemValue($varname, false);
+ }
+
+ protected function getValue($varname) {
+ static $defaults;
+ if(is_null($defaults)) {
+ $defaults = $this->getDefaults();
+ }
+ return \OCP\Config::getAppValue('user_ldap',
+ $this->configPrefix.$varname,
+ $defaults[$varname]);
+ }
+
+ protected function setValue($varname, $value) {
+ $this->config[$varname] = $value;
+ }
+
+ protected function saveValue($varname, $value) {
+ return \OCP\Config::setAppValue('user_ldap',
+ $this->configPrefix.$varname,
+ $value);
+ }
+
+ /**
+ * @returns an associative array with the default values. Keys are correspond
+ * to config-value entries in the database table
+ */
+ public function getDefaults() {
+ return array(
+ 'ldap_host' => '',
+ 'ldap_port' => '',
+ 'ldap_backup_host' => '',
+ 'ldap_backup_port' => '',
+ 'ldap_override_main_server' => '',
+ 'ldap_dn' => '',
+ 'ldap_agent_password' => '',
+ 'ldap_base' => '',
+ 'ldap_base_users' => '',
+ 'ldap_base_groups' => '',
+ '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' => '',
+ 'ldap_groupfilter_objectclass' => '',
+ 'ldap_groupfilter_groups' => '',
+ 'ldap_display_name' => 'displayName',
+ 'ldap_group_display_name' => 'cn',
+ 'ldap_tls' => 1,
+ 'ldap_nocase' => 0,
+ 'ldap_quota_def' => '',
+ 'ldap_quota_attr' => '',
+ 'ldap_email_attr' => '',
+ 'ldap_group_member_assoc_attribute' => 'uniqueMember',
+ 'ldap_cache_ttl' => 600,
+ 'ldap_uuid_user_attribute' => 'auto',
+ 'ldap_uuid_group_attribute' => 'auto',
+ 'home_folder_naming_rule' => '',
+ 'ldap_turn_off_cert_check' => 0,
+ 'ldap_configuration_active' => 0,
+ 'ldap_attributes_for_user_search' => '',
+ 'ldap_attributes_for_group_search' => '',
+ 'ldap_expert_username_attr' => '',
+ 'ldap_expert_uuid_user_attr' => '',
+ 'ldap_expert_uuid_group_attr' => '',
+ 'has_memberof_filter_support' => 0,
+ );
+ }
+
+ /**
+ * @return returns an array that maps internal variable names to database fields
+ */
+ public function getConfigTranslationArray() {
+ //TODO: merge them into one representation
+ static $array = array(
+ 'ldap_host' => 'ldapHost',
+ 'ldap_port' => 'ldapPort',
+ 'ldap_backup_host' => 'ldapBackupHost',
+ 'ldap_backup_port' => 'ldapBackupPort',
+ 'ldap_override_main_server' => 'ldapOverrideMainServer',
+ 'ldap_dn' => 'ldapAgentName',
+ 'ldap_agent_password' => 'ldapAgentPassword',
+ 'ldap_base' => 'ldapBase',
+ '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_loginfilter_email' => 'ldapLoginFilterEmail',
+ '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',
+ 'ldap_nocase' => 'ldapNoCase',
+ 'ldap_quota_def' => 'ldapQuotaDefault',
+ 'ldap_quota_attr' => 'ldapQuotaAttribute',
+ 'ldap_email_attr' => 'ldapEmailAttribute',
+ 'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
+ 'ldap_cache_ttl' => 'ldapCacheTTL',
+ 'home_folder_naming_rule' => 'homeFolderNamingRule',
+ 'ldap_turn_off_cert_check' => 'turnOffCertCheck',
+ 'ldap_configuration_active' => 'ldapConfigurationActive',
+ 'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
+ 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
+ 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
+ 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIUserDAttr',
+ 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
+ 'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
+ );
+ return $array;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php
index 93efdb4c9cb..8d34fb2f418 100644
--- a/apps/user_ldap/lib/connection.php
+++ b/apps/user_ldap/lib/connection.php
@@ -1,7 +1,7 @@
null,
- 'ldapPort' => null,
- 'ldapBackupHost' => null,
- 'ldapBackupPort' => null,
- 'ldapBase' => null,
- 'ldapBaseUsers' => null,
- 'ldapBaseGroups' => null,
- 'ldapAgentName' => null,
- 'ldapAgentPassword' => null,
- 'ldapTLS' => null,
- 'ldapNoCase' => null,
- 'turnOffCertCheck' => null,
- 'ldapIgnoreNamingRules' => null,
- 'ldapUserDisplayName' => null,
- 'ldapUserFilter' => null,
- 'ldapGroupFilter' => null,
- 'ldapGroupDisplayName' => null,
- 'ldapGroupMemberAssocAttr' => null,
- 'ldapLoginFilter' => null,
- 'ldapQuotaAttribute' => null,
- 'ldapQuotaDefault' => null,
- 'ldapEmailAttribute' => null,
- 'ldapCacheTTL' => null,
- 'ldapUuidUserAttribute' => 'auto',
- 'ldapUuidGroupAttribute' => 'auto',
- 'ldapOverrideUuidAttribute' => null,
- 'ldapOverrideMainServer' => false,
- 'ldapConfigurationActive' => false,
- 'ldapAttributesForUserSearch' => null,
- 'ldapAttributesForGroupSearch' => null,
- 'homeFolderNamingRule' => null,
- 'hasPagedResultSupport' => false,
- 'ldapExpertUsernameAttr' => null,
- 'ldapExpertUUIDUserAttr' => null,
- 'ldapExpertUUIDGroupAttr' => null,
- );
+ //settings handler
+ protected $configuration;
/**
* @brief Constructor
@@ -83,13 +48,14 @@ class Connection extends LDAPUtility {
parent::__construct($ldap);
$this->configPrefix = $configPrefix;
$this->configID = $configID;
+ $this->configuration = new Configuration($configPrefix);
$memcache = new \OC\Memcache\Factory();
if($memcache->isAvailable()) {
$this->cache = $memcache->create();
} else {
$this->cache = \OC_Cache::getGlobalCache();
}
- $this->config['hasPagedResultSupport'] =
+ $this->hasPagedResultSupport =
$this->ldap->hasPagedResultSupport();
}
@@ -114,23 +80,21 @@ class Connection extends LDAPUtility {
$this->readConfiguration();
}
- if(isset($this->config[$name])) {
- return $this->config[$name];
+ if($name === 'hasPagedResultSupport') {
+ return $this->hasPagedResultSupport;
}
+
+ return $this->configuration->$name;
}
public function __set($name, $value) {
- $changed = false;
- //only few options are writable
- if($name === 'ldapUuidUserAttribute' || $name === 'ldapUuidGroupAttribute') {
- \OCP\Util::writeLog('user_ldap', 'Set config '.$name.' to '.$value, \OCP\Util::DEBUG);
- $this->config[$name] = $value;
+ $before = $this->configuration->$name;
+ $this->configuration->$name = $value;
+ $after = $this->configuration->$name;
+ if($before !== $after) {
if(!empty($this->configID)) {
- \OCP\Config::setAppValue($this->configID, $this->configPrefix.$name, $value);
+ $this->configuration->saveConfiguration();
}
- $changed = true;
- }
- if($changed) {
$this->validateConfiguration();
}
}
@@ -174,7 +138,7 @@ class Connection extends LDAPUtility {
if(!$this->configured) {
$this->readConfiguration();
}
- if(!$this->config['ldapCacheTTL']) {
+ if(!$this->configuration->ldapCacheTTL) {
return null;
}
if(!$this->isCached($key)) {
@@ -190,7 +154,7 @@ class Connection extends LDAPUtility {
if(!$this->configured) {
$this->readConfiguration();
}
- if(!$this->config['ldapCacheTTL']) {
+ if(!$this->configuration->ldapCacheTTL) {
return false;
}
$key = $this->getCacheKey($key);
@@ -201,156 +165,32 @@ class Connection extends LDAPUtility {
if(!$this->configured) {
$this->readConfiguration();
}
- if(!$this->config['ldapCacheTTL']
- || !$this->config['ldapConfigurationActive']) {
+ if(!$this->configuration->ldapCacheTTL
+ || !$this->configuration->ldapConfigurationActive) {
return null;
}
$key = $this->getCacheKey($key);
$value = base64_encode(serialize($value));
- $this->cache->set($key, $value, $this->config['ldapCacheTTL']);
+ $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
}
public function clearCache() {
$this->cache->clear($this->getCacheKey(null));
}
- private function getValue($varname) {
- static $defaults;
- if(is_null($defaults)) {
- $defaults = $this->getDefaults();
- }
- return \OCP\Config::getAppValue($this->configID,
- $this->configPrefix.$varname,
- $defaults[$varname]);
- }
-
- private function setValue($varname, $value) {
- \OCP\Config::setAppValue($this->configID,
- $this->configPrefix.$varname,
- $value);
- }
-
- /**
- * Special handling for reading Base Configuration
- *
- * @param $base the internal name of the config key
- * @param $value the value stored for the base
- */
- private function readBase($base, $value) {
- if(empty($value)) {
- $value = '';
- } else {
- $value = preg_split('/\r\n|\r|\n/', $value);
- }
-
- $this->config[$base] = $value;
- }
-
/**
- * Caches the general LDAP configuration.
+ * @brief Caches the general LDAP configuration.
+ * @param $force optional. true, if the re-read should be forced. defaults
+ * to false.
+ * @return null
*/
private function readConfiguration($force = false) {
if((!$this->configured || $force) && !is_null($this->configID)) {
- $v = 'getValue';
- $this->config['ldapHost'] = $this->$v('ldap_host');
- $this->config['ldapBackupHost'] = $this->$v('ldap_backup_host');
- $this->config['ldapPort'] = $this->$v('ldap_port');
- $this->config['ldapBackupPort'] = $this->$v('ldap_backup_port');
- $this->config['ldapOverrideMainServer']
- = $this->$v('ldap_override_main_server');
- $this->config['ldapAgentName'] = $this->$v('ldap_dn');
- $this->config['ldapAgentPassword']
- = base64_decode($this->$v('ldap_agent_password'));
- $this->readBase('ldapBase', $this->$v('ldap_base'));
- $this->readBase('ldapBaseUsers', $this->$v('ldap_base_users'));
- $this->readBase('ldapBaseGroups', $this->$v('ldap_base_groups'));
- $this->config['ldapTLS'] = $this->$v('ldap_tls');
- $this->config['ldapNoCase'] = $this->$v('ldap_nocase');
- $this->config['turnOffCertCheck']
- = $this->$v('ldap_turn_off_cert_check');
- $this->config['ldapUserDisplayName']
- = mb_strtolower($this->$v('ldap_display_name'), 'UTF-8');
- $this->config['ldapUserFilter']
- = $this->$v('ldap_userlist_filter');
- $this->config['ldapGroupFilter'] = $this->$v('ldap_group_filter');
- $this->config['ldapLoginFilter'] = $this->$v('ldap_login_filter');
- $this->config['ldapGroupDisplayName']
- = mb_strtolower($this->$v('ldap_group_display_name'), 'UTF-8');
- $this->config['ldapQuotaAttribute']
- = $this->$v('ldap_quota_attr');
- $this->config['ldapQuotaDefault']
- = $this->$v('ldap_quota_def');
- $this->config['ldapEmailAttribute']
- = $this->$v('ldap_email_attr');
- $this->config['ldapGroupMemberAssocAttr']
- = $this->$v('ldap_group_member_assoc_attribute');
- $this->config['ldapIgnoreNamingRules']
- = \OCP\Config::getSystemValue('ldapIgnoreNamingRules', false);
- $this->config['ldapCacheTTL'] = $this->$v('ldap_cache_ttl');
- $this->config['ldapUuidUserAttribute']
- = $this->$v('ldap_uuid_user_attribute');
- $this->config['ldapUuidGroupAttribute']
- = $this->$v('ldap_uuid_group_attribute');
- $this->config['ldapOverrideUuidAttribute']
- = $this->$v('ldap_override_uuid_attribute');
- $this->config['homeFolderNamingRule']
- = $this->$v('home_folder_naming_rule');
- $this->config['ldapConfigurationActive']
- = $this->$v('ldap_configuration_active');
- $this->config['ldapAttributesForUserSearch']
- = preg_split('/\r\n|\r|\n/', $this->$v('ldap_attributes_for_user_search'));
- $this->config['ldapAttributesForGroupSearch']
- = preg_split('/\r\n|\r|\n/', $this->$v('ldap_attributes_for_group_search'));
- $this->config['ldapExpertUsernameAttr']
- = $this->$v('ldap_expert_username_attr');
- $this->config['ldapExpertUUIDUserAttr']
- = $this->$v('ldap_expert_uuid_user_attr');
- $this->config['ldapExpertUUIDGroupAttr']
- = $this->$v('ldap_expert_uuid_group_attr');
-
+ $this->configuration->readConfiguration();
$this->configured = $this->validateConfiguration();
}
}
- /**
- * @return returns an array that maps internal variable names to database fields
- */
- private function getConfigTranslationArray() {
- static $array = array(
- 'ldap_host'=>'ldapHost',
- 'ldap_port'=>'ldapPort',
- 'ldap_backup_host'=>'ldapBackupHost',
- 'ldap_backup_port'=>'ldapBackupPort',
- 'ldap_override_main_server' => 'ldapOverrideMainServer',
- 'ldap_dn'=>'ldapAgentName',
- 'ldap_agent_password'=>'ldapAgentPassword',
- 'ldap_base'=>'ldapBase',
- 'ldap_base_users'=>'ldapBaseUsers',
- 'ldap_base_groups'=>'ldapBaseGroups',
- 'ldap_userlist_filter'=>'ldapUserFilter',
- 'ldap_login_filter'=>'ldapLoginFilter',
- 'ldap_group_filter'=>'ldapGroupFilter',
- 'ldap_display_name'=>'ldapUserDisplayName',
- 'ldap_group_display_name'=>'ldapGroupDisplayName',
- 'ldap_tls'=>'ldapTLS',
- 'ldap_nocase'=>'ldapNoCase',
- 'ldap_quota_def'=>'ldapQuotaDefault',
- 'ldap_quota_attr'=>'ldapQuotaAttribute',
- 'ldap_email_attr'=>'ldapEmailAttribute',
- 'ldap_group_member_assoc_attribute'=>'ldapGroupMemberAssocAttr',
- 'ldap_cache_ttl'=>'ldapCacheTTL',
- 'home_folder_naming_rule' => 'homeFolderNamingRule',
- 'ldap_turn_off_cert_check' => 'turnOffCertCheck',
- 'ldap_configuration_active' => 'ldapConfigurationActive',
- 'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
- 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
- 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
- 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
- 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
- );
- return $array;
- }
-
/**
* @brief set LDAP configuration with values delivered by an array, not read from configuration
* @param $config array that holds the config parameters in an associated array
@@ -358,79 +198,24 @@ class Connection extends LDAPUtility {
* @return true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
*/
public function setConfiguration($config, &$setParameters = null) {
- if(!is_array($config)) {
- return false;
+ if(is_null($setParameters)) {
+ $setParameters = array();
}
-
- $params = $this->getConfigTranslationArray();
-
- foreach($config as $parameter => $value) {
- if(($parameter === 'homeFolderNamingRule'
- || (isset($params[$parameter])
- && $params[$parameter] === 'homeFolderNamingRule'))
- && !empty($value)) {
- $value = 'attr:'.$value;
- } else if (strpos($parameter, 'ldapBase') !== false
- || (isset($params[$parameter])
- && strpos($params[$parameter], 'ldapBase') !== false)) {
- $this->readBase($params[$parameter], $value);
- if(is_array($setParameters)) {
- $setParameters[] = $parameter;
- }
- continue;
- }
- if(isset($this->config[$parameter])) {
- $this->config[$parameter] = $value;
- if(is_array($setParameters)) {
- $setParameters[] = $parameter;
- }
- } else if(isset($params[$parameter])) {
- $this->config[$params[$parameter]] = $value;
- if(is_array($setParameters)) {
- $setParameters[] = $params[$parameter];
- }
- }
+ $this->configuration->setConfiguration($config, $setParameters);
+ if(count($setParameters) > 0) {
+ $this->configured = $this->validateConfiguration();
}
- $this->configured = $this->validateConfiguration();
-
return $this->configured;
}
/**
- * @brief saves the current Configuration in the database
+ * @brief saves the current Configuration in the database and empties the
+ * cache
+ * @return null
*/
public function saveConfiguration() {
- $trans = array_flip($this->getConfigTranslationArray());
- foreach($this->config as $key => $value) {
- \OCP\Util::writeLog('user_ldap', 'LDAP: storing key '.$key.
- ' value '.print_r($value, true), \OCP\Util::DEBUG);
- switch ($key) {
- case 'ldapAgentPassword':
- $value = base64_encode($value);
- break;
- case 'ldapBase':
- case 'ldapBaseUsers':
- case 'ldapBaseGroups':
- case 'ldapAttributesForUserSearch':
- case 'ldapAttributesForGroupSearch':
- if(is_array($value)) {
- $value = implode("\n", $value);
- }
- break;
- case 'ldapIgnoreNamingRules':
- case 'ldapOverrideUuidAttribute':
- case 'ldapUuidUserAttribute':
- case 'ldapUuidGroupAttribute':
- case 'hasPagedResultSupport':
- continue 2;
- }
- if(is_null($value)) {
- $value = '';
- }
-
- $this->setValue($trans[$key], $value);
- }
+ $this->configuration->saveConfiguration();
$this->clearCache();
}
@@ -440,191 +225,197 @@ class Connection extends LDAPUtility {
*/
public function getConfiguration() {
$this->readConfiguration();
- $trans = $this->getConfigTranslationArray();
- $config = array();
- foreach($trans as $dbKey => $classKey) {
- if($classKey === 'homeFolderNamingRule') {
- if(strpos($this->config[$classKey], 'attr:') === 0) {
- $config[$dbKey] = substr($this->config[$classKey], 5);
- } else {
- $config[$dbKey] = '';
- }
- continue;
- } else if((strpos($classKey, 'ldapBase') !== false
- || strpos($classKey, 'ldapAttributes') !== false)
- && is_array($this->config[$classKey])) {
- $config[$dbKey] = implode("\n", $this->config[$classKey]);
- continue;
+ $config = $this->configuration->getConfiguration();
+ $cta = $this->configuration->getConfigTranslationArray();
+ $result = array();
+ foreach($cta as $dbkey => $configkey) {
+ switch($configkey) {
+ case 'homeFolderNamingRule':
+ if(strpos($config[$configkey], 'attr:') === 0) {
+ $result[$dbkey] = substr($config[$configkey], 5);
+ } else {
+ $result[$dbkey] = '';
+ }
+ break;
+ case 'ldapBase':
+ case 'ldapBaseUsers':
+ case 'ldapBaseGroups':
+ case 'ldapAttributesForUserSearch':
+ case 'ldapAttributesForGroupSearch':
+ if(is_array($config[$configkey])) {
+ $result[$dbkey] = implode("\n", $config[$configkey]);
+ break;
+ } //else follows default
+ default:
+ $result[$dbkey] = $config[$configkey];
}
- $config[$dbKey] = $this->config[$classKey];
}
-
- return $config;
+ return $result;
}
- /**
- * @brief Validates the user specified configuration
- * @returns true if configuration seems OK, false otherwise
- */
- private function validateConfiguration() {
- // first step: "soft" checks: settings that are not really
- // necessary, but advisable. If left empty, give an info message
- if(empty($this->config['ldapBaseUsers'])) {
- \OCP\Util::writeLog('user_ldap', 'Base tree for Users is empty, using Base DN', \OCP\Util::INFO);
- $this->config['ldapBaseUsers'] = $this->config['ldapBase'];
- }
- if(empty($this->config['ldapBaseGroups'])) {
- \OCP\Util::writeLog('user_ldap', 'Base tree for Groups is empty, using Base DN', \OCP\Util::INFO);
- $this->config['ldapBaseGroups'] = $this->config['ldapBase'];
- }
- if(empty($this->config['ldapGroupFilter']) && empty($this->config['ldapGroupMemberAssocAttr'])) {
- \OCP\Util::writeLog('user_ldap',
- 'No group filter is specified, LDAP group feature will not be used.',
- \OCP\Util::INFO);
- }
- $uuidAttributes = array(
- 'auto', 'entryuuid', 'nsuniqueid', 'objectguid', 'guid');
- $uuidSettings = array(
- 'ldapUuidUserAttribute' => 'ldapExpertUUIDUserAttr',
- 'ldapUuidGroupAttribute' => 'ldapExpertUUIDGroupAttr');
- $cta = array_flip($this->getConfigTranslationArray());
- foreach($uuidSettings as $defaultKey => $overrideKey) {
- if( !in_array($this->config[$defaultKey], $uuidAttributes)
- && is_null($this->config[$overrideKey])
- && !is_null($this->configID)) {
- \OCP\Config::setAppValue($this->configID,
- $this->configPrefix.$cta[$defaultKey],
- 'auto');
+ private function doSoftValidation() {
+ //if User or Group Base are not set, take over Base DN setting
+ foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
+ $val = $this->configuration->$keyBase;
+ if(empty($val)) {
+ $obj = strpos('Users', $keyBase) !== false ? 'Users' : 'Groups';
\OCP\Util::writeLog('user_ldap',
- 'Illegal value for'.$defaultKey.', reset to autodetect.',
- \OCP\Util::DEBUG);
+ 'Base tree for '.$obj.
+ ' is empty, using Base DN',
+ \OCP\Util::INFO);
+ $this->configuration->$keyBase = $this->configuration->ldapBase;
}
}
- if(empty($this->config['ldapBackupPort'])) {
- //force default
- $this->config['ldapBackupPort'] = $this->config['ldapPort'];
+ $groupFilter = $this->configuration->ldapGroupFilter;
+ if(empty($groupFilter)) {
+ \OCP\Util::writeLog('user_ldap',
+ 'No group filter is specified, LDAP group '.
+ 'feature will not be used.',
+ \OCP\Util::INFO);
}
- foreach(array('ldapAttributesForUserSearch', 'ldapAttributesForGroupSearch') as $key) {
- if(is_array($this->config[$key])
- && count($this->config[$key]) === 1
- && empty($this->config[$key][0])) {
- $this->config[$key] = array();
+
+ foreach(array('ldapExpertUUIDUserAttr' => 'ldapUuidUserAttribute',
+ 'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
+ as $expertSetting => $effectiveSetting) {
+ $uuidOverride = $this->configuration->$expertSetting;
+ if(!empty($uuidOverride)) {
+ $this->configuration->$effectiveSetting = $uuidOverride;
+ } else {
+ $uuidAttributes = array('auto', 'entryuuid', 'nsuniqueid',
+ 'objectguid', 'guid');
+ if(!in_array($this->configuration->$effectiveSetting,
+ $uuidAttributes)
+ && (!is_null($this->configID))) {
+ $this->configuration->$effectiveSetting = 'auto';
+ $this->configuration->saveConfiguration();
+ \OCP\Util::writeLog('user_ldap',
+ 'Illegal value for the '.
+ $effectiveSetting.', '.'reset to '.
+ 'autodetect.', \OCP\Util::INFO);
+ }
+
}
}
- if((strpos($this->config['ldapHost'], 'ldaps') === 0)
- && $this->config['ldapTLS']) {
- $this->config['ldapTLS'] = false;
- \OCP\Util::writeLog('user_ldap',
- 'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
- \OCP\Util::INFO);
- }
- //second step: critical checks. If left empty or filled wrong, set as unconfigured and give a warning.
- $configurationOK = true;
- if(empty($this->config['ldapHost'])) {
- \OCP\Util::writeLog('user_ldap', 'No LDAP host given, won`t connect.', \OCP\Util::WARN);
- $configurationOK = false;
+ $backupPort = $this->configuration->ldapBackupPort;
+ if(empty($backupPort)) {
+ $this->configuration->backupPort = $this->configuration->ldapPort;
}
- if(empty($this->config['ldapPort'])) {
- \OCP\Util::writeLog('user_ldap', 'No LDAP Port given, won`t connect.', \OCP\Util::WARN);
- $configurationOK = false;
+
+ //make sure empty search attributes are saved as simple, empty array
+ $sakeys = array('ldapAttributesForUserSearch',
+ 'ldapAttributesForGroupSearch');
+ foreach($sakeys as $key) {
+ $val = $this->configuration->$key;
+ if(is_array($val) && count($val) === 1 && empty($val[0])) {
+ $this->configuration->$key = array();
+ }
}
- if((empty($this->config['ldapAgentName']) && !empty($this->config['ldapAgentPassword']))
- || (!empty($this->config['ldapAgentName']) && empty($this->config['ldapAgentPassword']))) {
+
+ if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
+ && $this->configuration->ldapTLS) {
+ $this->configuration->ldapTLS = false;
\OCP\Util::writeLog('user_ldap',
- 'Either no password given for the user agent or a password is given, but no LDAP agent; won`t connect.',
- \OCP\Util::WARN);
- $configurationOK = false;
+ 'LDAPS (already using secure connection) and '.
+ 'TLS do not work together. Switched off TLS.',
+ \OCP\Util::INFO);
}
- //TODO: check if ldapAgentName is in DN form
- if(empty($this->config['ldapBase'])
- && (empty($this->config['ldapBaseUsers'])
- && empty($this->config['ldapBaseGroups']))) {
- \OCP\Util::writeLog('user_ldap', 'No Base DN given, won`t connect.', \OCP\Util::WARN);
- $configurationOK = false;
+ }
+
+ private function doCriticalValidation() {
+ $configurationOK = true;
+ $errorStr = 'Configuration Error (prefix '.
+ strval($this->configPrefix).'): ';
+
+ //options that shall not be empty
+ $options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
+ 'ldapGroupDisplayName', 'ldapLoginFilter');
+ foreach($options as $key) {
+ $val = $this->configuration->$key;
+ if(empty($val)) {
+ switch($key) {
+ case 'ldapHost':
+ $subj = 'LDAP Host';
+ break;
+ case 'ldapPort':
+ $subj = 'LDAP Port';
+ break;
+ case 'ldapUserDisplayName':
+ $subj = 'LDAP User Display Name';
+ break;
+ case 'ldapGroupDisplayName':
+ $subj = 'LDAP Group Display Name';
+ break;
+ case 'ldapLoginFilter':
+ $subj = 'LDAP Login Filter';
+ break;
+ default:
+ $subj = $key;
+ break;
+ }
+ $configurationOK = false;
+ \OCP\Util::writeLog('user_ldap',
+ $errorStr.'No '.$subj.' given!',
+ \OCP\Util::WARN);
+ }
}
- if(empty($this->config['ldapUserDisplayName'])) {
+
+ //combinations
+ $agent = $this->configuration->ldapAgentName;
+ $pwd = $this->configuration->ldapAgentPassword;
+ if((empty($agent) && !empty($pwd)) || (!empty($agent) && empty($pwd))) {
\OCP\Util::writeLog('user_ldap',
- 'No user display name attribute specified, won`t connect.',
+ $errorStr.'either no password is given for the'.
+ 'user agent or a password is given, but not an'.
+ 'LDAP agent.',
\OCP\Util::WARN);
$configurationOK = false;
}
- if(empty($this->config['ldapGroupDisplayName'])) {
+
+ $base = $this->configuration->ldapBase;
+ $baseUsers = $this->configuration->ldapBaseUsers;
+ $baseGroups = $this->configuration->ldapBaseGroups;
+
+ if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
\OCP\Util::writeLog('user_ldap',
- 'No group display name attribute specified, won`t connect.',
- \OCP\Util::WARN);
- $configurationOK = false;
- }
- if(empty($this->config['ldapLoginFilter'])) {
- \OCP\Util::writeLog('user_ldap', 'No login filter specified, won`t connect.', \OCP\Util::WARN);
+ $errorStr.'Not a single Base DN given.',
+ \OCP\Util::WARN);
$configurationOK = false;
}
- if(mb_strpos($this->config['ldapLoginFilter'], '%uid', 0, 'UTF-8') === false) {
+
+ if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
+ === false) {
\OCP\Util::writeLog('user_ldap',
- 'Login filter does not contain %uid place holder, won`t connect.',
- \OCP\Util::WARN);
- \OCP\Util::writeLog('user_ldap', 'Login filter was ' . $this->config['ldapLoginFilter'], \OCP\Util::DEBUG);
+ $errorStr.'login filter does not contain %uid '.
+ 'place holder.',
+ \OCP\Util::WARN);
$configurationOK = false;
}
- if(!empty($this->config['ldapExpertUUIDUserAttr'])) {
- $this->config['ldapUuidUserAttribute'] = $this->config['ldapExpertUUIDUserAttr'];
- }
- if(!empty($this->config['ldapExpertUUIDGroupAttr'])) {
- $this->config['ldapUuidGroupAttribute'] = $this->config['ldapExpertUUIDGroupAttr'];
- }
-
return $configurationOK;
}
/**
- * @returns an associative array with the default values. Keys are correspond
- * to config-value entries in the database table
+ * @brief Validates the user specified configuration
+ * @returns true if configuration seems OK, false otherwise
*/
- static public function getDefaults() {
- return array(
- 'ldap_host' => '',
- 'ldap_port' => '389',
- 'ldap_backup_host' => '',
- 'ldap_backup_port' => '',
- 'ldap_override_main_server' => '',
- 'ldap_dn' => '',
- 'ldap_agent_password' => '',
- 'ldap_base' => '',
- 'ldap_base_users' => '',
- 'ldap_base_groups' => '',
- 'ldap_userlist_filter' => 'objectClass=person',
- 'ldap_login_filter' => 'uid=%uid',
- 'ldap_group_filter' => 'objectClass=posixGroup',
- 'ldap_display_name' => 'cn',
- 'ldap_group_display_name' => 'cn',
- 'ldap_tls' => 1,
- 'ldap_nocase' => 0,
- 'ldap_quota_def' => '',
- 'ldap_quota_attr' => '',
- 'ldap_email_attr' => '',
- 'ldap_group_member_assoc_attribute' => 'uniqueMember',
- 'ldap_cache_ttl' => 600,
- 'ldap_uuid_user_attribute' => 'auto',
- 'ldap_uuid_group_attribute' => 'auto',
- 'ldap_override_uuid_attribute' => 0,
- 'home_folder_naming_rule' => '',
- 'ldap_turn_off_cert_check' => 0,
- 'ldap_configuration_active' => 1,
- 'ldap_attributes_for_user_search' => '',
- 'ldap_attributes_for_group_search' => '',
- 'ldap_expert_username_attr' => '',
- 'ldap_expert_uuid_user_attr' => '',
- 'ldap_expert_uuid_group_attr' => '',
- );
+ private function validateConfiguration() {
+ // first step: "soft" checks: settings that are not really
+ // necessary, but advisable. If left empty, give an info message
+ $this->doSoftValidation();
+
+ //second step: critical checks. If left empty or filled wrong, set as
+ //unconfigured and give a warning.
+ return $this->doCriticalValidation();
}
+
/**
* Connects and Binds to LDAP
*/
private function establishConnection() {
- if(!$this->config['ldapConfigurationActive']) {
+ if(!$this->configuration->ldapConfigurationActive) {
return null;
}
static $phpLDAPinstalled = true;
@@ -632,29 +423,36 @@ class Connection extends LDAPUtility {
return false;
}
if(!$this->configured) {
- \OCP\Util::writeLog('user_ldap', 'Configuration is invalid, cannot connect', \OCP\Util::WARN);
+ \OCP\Util::writeLog('user_ldap',
+ 'Configuration is invalid, cannot connect',
+ \OCP\Util::WARN);
return false;
}
if(!$this->ldapConnectionRes) {
if(!$this->ldap->areLDAPFunctionsAvailable()) {
$phpLDAPinstalled = false;
\OCP\Util::writeLog('user_ldap',
- 'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
- \OCP\Util::ERROR);
+ 'function ldap_connect is not available. Make '.
+ 'sure that the PHP ldap module is installed.',
+ \OCP\Util::ERROR);
return false;
}
- if($this->config['turnOffCertCheck']) {
+ if($this->configuration->turnOffCertCheck) {
if(putenv('LDAPTLS_REQCERT=never')) {
\OCP\Util::writeLog('user_ldap',
'Turned off SSL certificate validation successfully.',
\OCP\Util::WARN);
} else {
- \OCP\Util::writeLog('user_ldap', 'Could not turn off SSL certificate validation.', \OCP\Util::WARN);
+ \OCP\Util::writeLog('user_ldap',
+ 'Could not turn off SSL certificate validation.',
+ \OCP\Util::WARN);
}
}
- if(!$this->config['ldapOverrideMainServer'] && !$this->getFromCache('overrideMainServer')) {
- $this->doConnect($this->config['ldapHost'], $this->config['ldapPort']);
+ if(!$this->configuration->ldapOverrideMainServer
+ && !$this->getFromCache('overrideMainServer')) {
+ $this->doConnect($this->configuration->ldapHost,
+ $this->configuration->ldapPort);
$bindStatus = $this->bind();
$error = $this->ldap->isResource($this->ldapConnectionRes) ?
$this->ldap->errno($this->ldapConnectionRes) : -1;
@@ -665,9 +463,10 @@ class Connection extends LDAPUtility {
//if LDAP server is not reachable, try the Backup (Replica!) Server
if((!$bindStatus && ($error !== 0))
- || $this->config['ldapOverrideMainServer']
+ || $this->configuration->ldapOverrideMainServer
|| $this->getFromCache('overrideMainServer')) {
- $this->doConnect($this->config['ldapBackupHost'], $this->config['ldapBackupPort']);
+ $this->doConnect($this->configuration->ldapBackupHost,
+ $this->configuration->ldapBackupPort);
$bindStatus = $this->bind();
if(!$bindStatus && $error === -1) {
//when bind to backup server succeeded and failed to main server,
@@ -690,7 +489,7 @@ class Connection extends LDAPUtility {
$this->ldapConnectionRes = $this->ldap->connect($host, $port);
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
- if($this->config['ldapTLS']) {
+ if($this->configuration->ldapTLS) {
$this->ldap->startTls($this->ldapConnectionRes);
}
}
@@ -702,7 +501,7 @@ class Connection extends LDAPUtility {
*/
public function bind() {
static $getConnectionResourceAttempt = false;
- if(!$this->config['ldapConfigurationActive']) {
+ if(!$this->configuration->ldapConfigurationActive) {
return false;
}
if($getConnectionResourceAttempt) {
@@ -716,8 +515,8 @@ class Connection extends LDAPUtility {
return false;
}
$ldapLogin = @$this->ldap->bind($cr,
- $this->config['ldapAgentName'],
- $this->config['ldapAgentPassword']);
+ $this->configuration->ldapAgentName,
+ $this->configuration->ldapAgentPassword);
if(!$ldapLogin) {
\OCP\Util::writeLog('user_ldap',
'Bind failed: ' . $this->ldap->errno($cr) . ': ' . $this->ldap->error($cr),
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..20587cba7db 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
@@ -97,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
@@ -105,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 b63e969912a..bc963191722 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);
}
@@ -65,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
new file mode 100644
index 00000000000..9b84c3d5a44
--- /dev/null
+++ b/apps/user_ldap/lib/wizard.php
@@ -0,0 +1,1024 @@
+.
+ *
+ */
+
+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 = 2;
+ const LRESULT_PROCESSED_INVALID = 3;
+ const LRESULT_PROCESSED_SKIP = 4;
+
+ const LFILTER_LOGIN = 2;
+ const LFILTER_USER_LIST = 3;
+ const LFILTER_GROUP_LIST = 4;
+
+ const LDAP_NW_TIMEOUT = 4;
+
+ /**
+ * @brief Constructor
+ * @param $configuration an instance of Configuration
+ * @param $ldap an instance of ILDAPWrapper
+ */
+ public function __construct(Configuration $configuration, ILDAPWrapper $ldap) {
+ parent::__construct($ldap);
+ $this->configuration = $configuration;
+ if(is_null(Wizard::$l)) {
+ Wizard::$l = \OC_L10N::get('user_ldap');
+ }
+ $this->result = new WizardResult;
+ }
+
+ public function __destruct() {
+ if($this->result->hasChanges()) {
+ $this->configuration->saveConfiguration();
+ }
+ }
+
+ 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);
+ $l = \OC_L10N::get('user_ldap');
+ if(empty($filter)) {
+ $output = $l->n('%s group found', '%s groups found', 0, array(0));
+ $this->result->addChange('ldap_group_count', $output);
+ 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;
+ $output = $l->n('%s group found', '%s groups found', $entries, $entries);
+ $this->result->addChange('ldap_group_count', $output);
+
+ return $this->result;
+ }
+
+ 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;
+ $l = \OC_L10N::get('user_ldap');
+ $output = $l->n('%s user found', '%s users found', $entries, $entries);
+ $this->result->addChange('ldap_user_count', $output);
+
+ 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
+ */
+ 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',
+ 'ldapAgentPassword',
+ 'ldapBase',
+ ))) {
+ return false;
+ }
+ $cr = $this->getConnection();
+ if(!$cr) {
+ throw new \Excpetion('Could not connect to LDAP');
+ }
+
+ $obclasses = array('posixGroup', 'group', '*');
+ $this->determineFeature($obclasses, 'cn', $dbkey, $confkey);
+
+ if($testMemberOf) {
+ $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf();
+ $this->result->markChange();
+ if(!$this->configuration->hasMemberOfFilterSupport) {
+ throw new \Exception('memberOf is not supported by the server');
+ }
+ }
+
+ 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
+ */
+ 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',
+ 'ldapAgentPassword',
+ 'ldapBase',
+ ))) {
+ return false;
+ }
+ $cr = $this->getConnection();
+ if(!$cr) {
+ throw new \Excpetion('Could not connect to LDAP');
+ }
+
+ $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',
+ 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;
+ }
+
+ 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;
+ }
+
+ 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
+ */
+ public function guessPortAndTLS() {
+ if(!$this->checkRequirements(array('ldapHost',
+ 'ldapAgentName',
+ 'ldapAgentPassword'
+ ))) {
+ return false;
+ }
+ $this->checkHost();
+ $portSettings = $this->getPortSettingsToTry();
+
+ if(!is_array($portSettings)) {
+ throw new \Exception(print_r($portSettings, true));
+ }
+
+ //proceed from the best configuration and return on first success
+ foreach($portSettings as $setting) {
+ $p = $setting['port'];
+ $t = $setting['tls'];
+ \OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG);
+ //connectAndBind may throw Exception, it needs to be catched by the
+ //callee of this method
+ if($this->connectAndBind($p, $t) === true) {
+ $config = array('ldapPort' => $p,
+ 'ldapTLS' => intval($t)
+ );
+ $this->configuration->setConfiguration($config);
+ \OCP\Util::writeLog('user_ldap', 'Wiz: detected Port '. $p, \OCP\Util::DEBUG);
+ $this->result->addChange('ldap_port', $p);
+ $this->result->addChange('ldap_tls', intval($t));
+ return $this->result;
+ }
+ }
+
+ //custom port, undetected (we do not brute force)
+ 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',
+ 'ldapAgentPassword',
+ 'ldapPort',
+ ))) {
+ return false;
+ }
+
+ //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);
+ 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);
+ 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));
+ }
+
+ /**
+ * @brief Checks, whether a port was entered in the Host configuration
+ * field. In this case the port will be stripped off, but also stored as
+ * setting.
+ */
+ private function checkHost() {
+ $host = $this->configuration->ldapHost;
+ $hostInfo = parse_url($host);
+
+ //removes Port from Host
+ if(is_array($hostInfo) && isset($hostInfo['port'])) {
+ $port = $hostInfo['port'];
+ $host = str_replace(':'.$port, '', $host);
+ $this->applyFind('ldap_host', $host);
+ $this->applyFind('ldap_port', $port);
+ }
+ }
+
+ /**
+ * @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
+ * @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);
+ }
+
+ /**
+ * @brief Checks whether the server supports memberOf in LDAP Filter.
+ * Requires that groups are determined, thus internally called from within
+ * determineGroups()
+ * @return bool, true if it does, false otherwise
+ */
+ private function testMemberOf() {
+ $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=';
+ $filterSuffix = '))';
+
+ foreach($this->resultCache as $dn => $properties) {
+ if(!isset($properties['cn'])) {
+ //assuming only groups have their cn cached :)
+ continue;
+ }
+ $filter = strtolower($filterPrefix . $dn . $filterSuffix);
+ $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;
+ }
+
+ /**
+ * @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;
+ //glue objectclasses
+ if(is_array($objcs) && count($objcs) > 0) {
+ $filter .= '(|';
+ foreach($objcs as $objc) {
+ $filter .= '(objectclass=' . $objc . ')';
+ }
+ $filter .= ')';
+ $parts++;
+ }
+ //glue group memberships
+ if($this->configuration->hasMemberOfFilterSupport) {
+ $cns = $this->configuration->ldapUserFilterGroups;
+ if(is_array($cns) && count($cns) > 0) {
+ $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++;
+ }
+ //wrap parts in AND condition
+ if($parts > 1) {
+ $filter = '(&' . $filter . ')';
+ }
+ if(empty($filter)) {
+ $filter = '(objectclass=*)';
+ }
+ 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';
+ $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;
+ }
+
+ \OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG);
+
+ return $filter;
+ }
+
+ /**
+ * Connects and Binds to an LDAP Server
+ * @param $port the port to connect with
+ * @param $tls whether startTLS is to be used
+ * @return
+ */
+ private function connectAndBind($port = 389, $tls = false, $ncc = false) {
+ if($ncc) {
+ //No certificate check
+ //FIXME: undo afterwards
+ putenv('LDAPTLS_REQCERT=never');
+ }
+
+ //connect, does not really trigger any server communication
+ \OCP\Util::writeLog('user_ldap', 'Wiz: Checking Host Info ', \OCP\Util::DEBUG);
+ $host = $this->configuration->ldapHost;
+ $hostInfo = parse_url($host);
+ if(!$hostInfo) {
+ throw new \Exception($this->l->t('Invalid Host'));
+ }
+ if(isset($hostInfo['scheme'])) {
+ if(isset($hostInfo['port'])) {
+ //problem
+ } else {
+ $host .= ':' . $port;
+ }
+ }
+ \OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG);
+ $cr = $this->ldap->connect($host, $port);
+ if(!is_resource($cr)) {
+ throw new \Exception($this->l->t('Invalid Host'));
+ }
+
+ \OCP\Util::writeLog('user_ldap', 'Wiz: Setting LDAP Options ', \OCP\Util::DEBUG);
+ //set LDAP options
+ $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);
+ //interesting part: do the bind!
+ $login = $this->ldap->bind($cr,
+ $this->configuration->ldapAgentName,
+ $this->configuration->ldapAgentPassword);
+
+ if($login === true) {
+ $this->ldap->unbind($cr);
+ if($ncc) {
+ throw new \Exception('Certificate cannot be validated.');
+ }
+ \OCP\Util::writeLog('user_ldap', 'Wiz: Bind succesfull with Port '. $port, \OCP\Util::DEBUG);
+ return true;
+ }
+
+ $errno = $this->ldap->errno($cr);
+ $error = ldap_error($cr);
+ $this->ldap->unbind($cr);
+ if($errno === -1 || ($errno === 2 && $ncc)) {
+ //host, port or TLS wrong
+ return false;
+ } else if ($errno === 2) {
+ return $this->connectAndBind($port, $tls, true);
+ }
+ throw new \Exception($error);
+ }
+
+ private function checkRequirements($reqs) {
+ foreach($reqs as $option) {
+ $value = $this->configuration->$option;
+ if(empty($value)) {
+ return false;
+ }
+ }
+ 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)) {
+ 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;
+ }
+ $newItems = array();
+ $state = $this->getAttributeValuesFromEntry($attributes,
+ $attr,
+ $newItems);
+ $foundItems = array_merge($foundItems, $newItems);
+ $this->resultCache[$dn][$attr] = $newItems;
+ $dnRead[] = $dn;
+ $getEntryFunc = 'nextEntry';
+ $rr = $entry; //will be expected by nextEntry next round
+ } while($state === self::LRESULT_PROCESSED_SKIP
+ || $this->ldap->isResource($entry));
+ }
+ }
+
+ return array_unique($foundItems);
+ }
+
+ /**
+ * @brief determines if and which $attr are available on the LDAP server
+ * @param $objectclasses the objectclasses to use as search filter
+ * @param $attr the attribute to look for
+ * @param $dbkey the dbkey of the setting the feature is connected to
+ * @param $confkey the confkey counterpart for the $dbkey as used in the
+ * Configuration class
+ * @param $po boolean, whether the objectClass with most result entries
+ * shall be pre-selected via the result
+ * @returns array, list of found items.
+ */
+ private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) {
+ $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 = '';
+ $availableFeatures =
+ $this->cumulativeSearchOnAttribute($objectclasses, $attr,
+ true, $maxEntryObjC);
+ if(is_array($availableFeatures)
+ && count($availableFeatures) > 0) {
+ natcasesort($availableFeatures);
+ //natcasesort keeps indices, but we must get rid of them for proper
+ //sorting in the web UI. Therefore: array_values
+ $this->result->addOptions($dbkey, array_values($availableFeatures));
+ } else {
+ throw new \Exception(self::$l->t('Could not find the desired feature'));
+ }
+
+ $setFeatures = $this->configuration->$confkey;
+ if(is_array($setFeatures) && !empty($setFeatures)) {
+ //something is already configured? pre-select it.
+ $this->result->addChange($dbkey, $setFeatures);
+ } else if($po && !empty($maxEntryObjC)) {
+ //pre-select objectclass with most result entries
+ $maxEntryObjC = str_replace($p, '', $maxEntryObjC);
+ $this->applyFind($dbkey, $maxEntryObjC);
+ $this->result->addChange($dbkey, $maxEntryObjC);
+ }
+
+ return $availableFeatures;
+ }
+
+ /**
+ * @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)) {
+ $known[] = $val;
+ }
+ }
+ return self::LRESULT_PROCESSED_OK;
+ } else {
+ return self::LRESULT_PROCESSED_SKIP;
+ }
+ }
+
+ private function getConnection() {
+ if(!is_null($this->cr)) {
+ return $cr;
+ }
+ $cr = $this->ldap->connect(
+ $this->configuration->ldapHost.':'.$this->configuration->ldapPort,
+ $this->configuration->ldapPort);
+
+ $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,
+ $this->configuration->ldapAgentName,
+ $this->configuration->ldapAgentPassword);
+ if($lo === true) {
+ $this->$cr = $cr;
+ return $cr;
+ }
+
+ return false;
+ }
+
+ private function getDefaultLdapPortSettings() {
+ static $settings = array(
+ array('port' => 7636, 'tls' => false),
+ array('port' => 636, 'tls' => false),
+ array('port' => 7389, 'tls' => true),
+ array('port' => 389, 'tls' => true),
+ array('port' => 7389, 'tls' => false),
+ array('port' => 389, 'tls' => false),
+ );
+ return $settings;
+ }
+
+ private function getPortSettingsToTry() {
+ //389 ← LDAP / Unencrypted or StartTLS
+ //636 ← LDAPS / SSL
+ //7xxx ← UCS. need to be checked first, because both ports may be open
+ $host = $this->configuration->ldapHost;
+ $port = intval($this->configuration->ldapPort);
+ $portSettings = array();
+
+ //In case the port is already provided, we will check this first
+ if($port > 0) {
+ $hostInfo = parse_url($host);
+ if(is_array($hostInfo)
+ && isset($hostInfo['scheme'])
+ && stripos($hostInfo['scheme'], 'ldaps') === false) {
+ $portSettings[] = array('port' => $port, 'tls' => true);
+ }
+ $portSettings[] =array('port' => $port, 'tls' => false);
+ }
+
+ //default ports
+ $portSettings = array_merge($portSettings,
+ $this->getDefaultLdapPortSettings());
+
+ return $portSettings;
+ }
+
+
+}
\ No newline at end of file
diff --git a/apps/user_ldap/lib/wizardresult.php b/apps/user_ldap/lib/wizardresult.php
new file mode 100644
index 00000000000..542f106cad8
--- /dev/null
+++ b/apps/user_ldap/lib/wizardresult.php
@@ -0,0 +1,58 @@
+.
+ *
+ */
+
+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);
+ }
+ $this->options[$key] = $values;
+ }
+
+ public function hasChanges() {
+ return (count($this->changes) > 0 || $this->markedChange);
+ }
+
+ 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 f20bc191183..d077eafdde9 100644
--- a/apps/user_ldap/settings.php
+++ b/apps/user_ldap/settings.php
@@ -25,19 +25,50 @@
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');
$prefixes = \OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes();
$hosts = \OCA\user_ldap\lib\Helper::getServerConfigurationHosts();
-$tmpl->assign('serverConfigurationPrefixes', $prefixes);
-$tmpl->assign('serverConfigurationHosts', $hosts);
+
+$wizardHtml = '';
+$toc = array();
+
+$wControls = new OCP\Template('user_ldap', 'part.wizardcontrols');
+$wControls = $wControls->fetchPage();
+$sControls = new OCP\Template('user_ldap', 'part.settingcontrols');
+$sControls = $sControls->fetchPage();
+
+$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');
+
+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);
+$tmpl->assign('settingControls', $sControls);
// assign default values
-$defaults = \OCA\user_ldap\lib\Connection::getDefaults();
+$config = new \OCA\user_ldap\lib\Configuration('', false);
+$defaults = $config->getDefaults();
foreach($defaults as $key => $default) {
$tmpl->assign($key.'_default', $default);
}
diff --git a/apps/user_ldap/templates/part.settingcontrols.php b/apps/user_ldap/templates/part.settingcontrols.php
new file mode 100644
index 00000000000..017f21c8b1c
--- /dev/null
+++ b/apps/user_ldap/templates/part.settingcontrols.php
@@ -0,0 +1,12 @@
+