summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <alec@alec.pl>2014-01-17 10:02:18 (GMT)
committerAleksander Machniak <alec@alec.pl>2014-01-17 10:02:18 (GMT)
commitf434be6ad70510471bf1ccada311c869a5bc6f62 (patch)
tree2db03286b4e4c77d6038f3a9ff4915b753212f94
parent955f4186c5e3681226d01e5f4e77ff0af99f09d6 (diff)
downloadkolab-wap-f434be6ad70510471bf1ccada311c869a5bc6f62.tar.gz
Delete domains by status change and related improvements e.g.
check if domain is empty and warn the user before setting status to deleted TODO: shell script for real domains deletion
-rw-r--r--lib/Auth.php5
-rw-r--r--lib/Auth/LDAP.php63
-rw-r--r--lib/api/kolab_api_service_domain.php30
-rw-r--r--lib/api/kolab_api_service_domain_types.php2
-rw-r--r--lib/api/kolab_api_service_domains.php1
-rw-r--r--lib/client/kolab_client_task_domain.php19
-rw-r--r--lib/client/kolab_client_task_user.php7
-rw-r--r--lib/ext/Net/LDAP3.php28
-rw-r--r--lib/kolab_client_task.php32
-rw-r--r--lib/locale/en_US.php3
-rw-r--r--public_html/js/kolab_admin.js29
-rw-r--r--public_html/skins/default/style.css4
12 files changed, 189 insertions, 34 deletions
diff --git a/lib/Auth.php b/lib/Auth.php
index 40f3049..4aee7ad 100644
--- a/lib/Auth.php
+++ b/lib/Auth.php
@@ -234,6 +234,11 @@ class Auth {
return $this->auth_instance()->domain_info($domaindata);
}
+ public function domain_is_empty($domain)
+ {
+ return $this->auth_instance()->domain_is_empty($domain);
+ }
+
public function find_recipient($address)
{
return $this->auth_instance()->find_recipient($address);
diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php
index 0075166..5958166 100644
--- a/lib/Auth/LDAP.php
+++ b/lib/Auth/LDAP.php
@@ -483,9 +483,18 @@ class LDAP extends Net_LDAP3 {
public function domain_delete($domain)
{
- $base_dn = $this->conf->get('ldap', 'domain_base_dn');
+ $domain = $this->domain_info($domain);
+
+ if (empty($domain)) {
+ return false;
+ }
+
+ $domain_dn = key($domain);
+ $attributes = array_merge($domain[$domain_dn], array('inetdomainstatus' => 'deleted'));
- return $this->entry_delete($domain, array(), $base_dn);
+ // for performance reasons we set only domain status,
+ // cronjob script should delete such domain later
+ return $this->modify_entry($domain_dn, $domain[$domain_dn], $attributes);
}
public function domain_find_by_attribute($attribute)
@@ -521,6 +530,38 @@ class LDAP extends Net_LDAP3 {
}
/**
+ * Checkes if specified domain is empty (no users assigned)
+ *
+ * @param string $domain Domain name
+ *
+ * @return bool True if domain is empty, False otherwise
+ */
+ public function domain_is_empty($domain)
+ {
+ $this->_log(LOG_DEBUG, "Auth::LDAP::domain_is_empty($domain)");
+
+ $domain_name_attribute = $this->conf->get('ldap', 'domain_name_attribute');
+
+ if (empty($domain_name_attribute)) {
+ $domain_name_attribute = 'associateddomain';
+ }
+
+ $domain = $this->domain_info($domain);
+
+ if (!empty($domain)) {
+ $domain_dn = key($domain);
+ $domain_name = $domain[$domain_dn][$domain_name_attribute];
+ }
+ else {
+ return false;
+ }
+
+ $result = $this->list_users(array('entrydn'), null, array('page_size' => 1), $domain_name);
+
+ return is_array($result) && $result['count'] == 0;
+ }
+
+ /**
* Proxy to parent function in order to enable us to insert our
* configuration.
*/
@@ -746,11 +787,11 @@ class LDAP extends Net_LDAP3 {
return $this->_list($base_dn, $filter, 'sub', $attributes, $search, $params);
}
- public function list_users($attributes = array(), $search = array(), $params = array())
+ public function list_users($attributes = array(), $search = array(), $params = array(), $domain = null)
{
- $this->_log(LOG_DEBUG, "Auth::LDAP::list_users(" . var_export($attributes, true) . ", " . var_export($search, true) . ", " . var_export($params, true));
+ $this->_log(LOG_DEBUG, "Auth::LDAP::list_users(" . var_export($attributes, true) . ", " . var_export($search, true) . ", " . var_export($params, true) . ", " . $domain . ")");
- $base_dn = $this->_subject_base_dn('user');
+ $base_dn = $this->_subject_base_dn('user', false, $domain);
$filter = $this->conf->get('user_filter');
if (empty($filter)) {
@@ -1189,9 +1230,13 @@ class LDAP extends Net_LDAP3 {
}
}
- private function _subject_base_dn($subject, $strict = false)
+ private function _subject_base_dn($subject, $strict = false, $domain = null)
{
- $subject_base_dn = $this->conf->get_raw($this->domain, $subject . "_base_dn");
+ if (empty($domain)) {
+ $domain = $this->domain;
+ }
+
+ $subject_base_dn = $this->conf->get_raw($domain, $subject . "_base_dn");
if (empty($subject_base_dn)) {
$subject_base_dn = $this->conf->get_raw("ldap", $subject . "_base_dn");
@@ -1203,10 +1248,10 @@ class LDAP extends Net_LDAP3 {
}
// Attempt to get a configured base_dn
- $base_dn = $this->conf->get($this->domain, "base_dn");
+ $base_dn = $this->conf->get($domain, "base_dn");
if (empty($base_dn)) {
- $base_dn = $this->domain_root_dn($this->domain);
+ $base_dn = $this->domain_root_dn($domain);
}
if (!empty($subject_base_dn)) {
diff --git a/lib/api/kolab_api_service_domain.php b/lib/api/kolab_api_service_domain.php
index 4d5fcaa..711b37b 100644
--- a/lib/api/kolab_api_service_domain.php
+++ b/lib/api/kolab_api_service_domain.php
@@ -105,6 +105,7 @@ class kolab_api_service_domain extends kolab_api_service
* @param array $post POST parameters
*
* @return bool True on success, False on failure
+ * @throws kolab_api_exception
*/
public function domain_delete($getdata, $postdata)
{
@@ -115,8 +116,15 @@ class kolab_api_service_domain extends kolab_api_service
return false;
}
- // TODO: Input validation
- $auth = Auth::get_instance();
+ $auth = Auth::get_instance();
+
+ // check if domain is empty
+ if (empty($postdata['force']) || strtolower($postdata['force']) == 'false') {
+ if (!$auth->domain_is_empty($postdata['id'])) {
+ throw new kolab_api_exception(kolab_api_exception::DOMAIN_NOT_EMPTY);
+ }
+ }
+
$result = $auth->domain_delete($postdata['id']);
if ($result) {
@@ -135,13 +143,25 @@ class kolab_api_service_domain extends kolab_api_service
return false;
}
- $auth = Auth::get_instance();
+ $auth = Auth::get_instance();
+
+ // check if domain is empty when changing status to deleted, as in domain.delete
+ if ($postdata['inetdomainstatus'] == 'deleted'
+ && (empty($postdata['force']) || strtolower($postdata['force']) == 'false')
+ ) {
+ $domain = $auth->domain_info($postdata['id']);
+
+ if ($domain['inetdomainstatus'] != 'deleted' && !$auth->domain_is_empty($postdata['id'])) {
+ throw new kolab_api_exception(kolab_api_exception::DOMAIN_NOT_EMPTY);
+ }
+ }
+
+
$attributes = $this->parse_input_attributes('domain', $postdata);
$result = $auth->domain_edit($postdata['id'], $attributes, $postdata['type_id']);
- // @TODO: return unique attribute or all attributes as domain_add()
if ($result) {
- return true;
+ return $result;
}
return false;
diff --git a/lib/api/kolab_api_service_domain_types.php b/lib/api/kolab_api_service_domain_types.php
index 6829047..189b39f 100644
--- a/lib/api/kolab_api_service_domain_types.php
+++ b/lib/api/kolab_api_service_domain_types.php
@@ -41,7 +41,7 @@ class kolab_api_service_domain_types extends kolab_api_service
'optional' => true,
'type' => 'select',
'values' => array(
- '', 'active', 'suspended',
+ '', 'active', 'suspended', 'deleted',
),
),
),
diff --git a/lib/api/kolab_api_service_domains.php b/lib/api/kolab_api_service_domains.php
index ca9ea01..2373877 100644
--- a/lib/api/kolab_api_service_domains.php
+++ b/lib/api/kolab_api_service_domains.php
@@ -31,6 +31,7 @@ class kolab_api_service_domains extends kolab_api_service
public $list_attribs = array(
'associateddomain',
+ 'inetdomainstatus',
'objectclass',
'entrydn',
);
diff --git a/lib/client/kolab_client_task_domain.php b/lib/client/kolab_client_task_domain.php
index 4a1190a..5c23e8a 100644
--- a/lib/client/kolab_client_task_domain.php
+++ b/lib/client/kolab_client_task_domain.php
@@ -34,7 +34,7 @@ class kolab_client_task_domain extends kolab_client_task
'name' => array('associateddomain'),
);
- protected $list_attribs = array('associateddomain');
+ protected $list_attribs = array('associateddomain', 'inetdomainstatus');
/**
* Default action.
@@ -122,6 +122,7 @@ class kolab_client_task_domain extends kolab_client_task
'type_id' => 'system',
'type_id_name' => 'system',
'associateddomain' => 'system',
+ 'inetdomainstatus' => 'system',
);
//console("domain_form() \$data", $data);
@@ -190,12 +191,26 @@ class kolab_client_task_domain extends kolab_client_task
/**
* List item handler
*/
- protected function list_item_handler($item)
+ protected function list_item_handler($item, &$class)
{
+ if ($item['inetdomainstatus'] == 'deleted') {
+ $class[] = 'deleted';
+ }
+
if (is_array($item['associateddomain'])) {
return $item['associateddomain'][0];
}
return $item['associateddomain'];
}
+
+ /**
+ * Returns false when object matches current domain
+ */
+ protected function is_deletable($data)
+ {
+ // domain delete is done by setting inetdomainstatus to 'deleted'
+ return false;
+ }
+
}
diff --git a/lib/client/kolab_client_task_user.php b/lib/client/kolab_client_task_user.php
index 40c2fcc..6d51754 100644
--- a/lib/client/kolab_client_task_user.php
+++ b/lib/client/kolab_client_task_user.php
@@ -255,4 +255,11 @@ class kolab_client_task_user extends kolab_client_task
return empty($item['displayname']) ? $item['cn'] : $item['displayname'];
}
+ /**
+ * Returns true when current object matches logged user
+ */
+ protected function is_deletable($data)
+ {
+ return parent::is_deletable($data) && $data['id'] != $_SESSION['user']['id'];
+ }
}
diff --git a/lib/ext/Net/LDAP3.php b/lib/ext/Net/LDAP3.php
index 9a4ecb2..3f69613 100644
--- a/lib/ext/Net/LDAP3.php
+++ b/lib/ext/Net/LDAP3.php
@@ -677,7 +677,6 @@ class Net_LDAP3
if (ldap_delete($this->conn, $entry_dn) === false) {
$this->_debug("LDAP: S: " . ldap_error($this->conn));
- $this->_debug("LDAP: Delete failed. " . ldap_error($this->conn));
return false;
}
@@ -686,6 +685,32 @@ class Net_LDAP3
return true;
}
+ /**
+ * Deletes specified entry and all entries in the tree
+ */
+ public function delete_entry_recursive($entry_dn)
+ {
+ // searching for sub entries, but not scope sub, just one level
+ $this->config_set('return_attributes', array('entrydn'));
+ $result = $this->search($entry_dn, '(objectclass=*)', 'one');
+
+ if ($result) {
+ $entries = $result->entries(true);
+
+ foreach (array_keys($entries) as $sub_dn) {
+ if (!$this->delete_entry_recursive($sub_dn)) {
+ return false;
+ }
+ }
+ }
+
+ if (!$this->delete_entry($entry_dn)) {
+ return false;
+ }
+
+ return true;
+ }
+
public function effective_rights($subject)
{
$effective_rights_control_oid = "1.3.6.1.4.1.42.2.27.9.5.2";
@@ -1411,7 +1436,6 @@ class Net_LDAP3
if ($result) {
return $mod_array;
}
-
}
/**
diff --git a/lib/kolab_client_task.php b/lib/kolab_client_task.php
index 20c4bc0..8cac7e0 100644
--- a/lib/kolab_client_task.php
+++ b/lib/kolab_client_task.php
@@ -1358,16 +1358,13 @@ class kolab_client_task
));
}
- if (!empty($data['id']) && in_array('delete', (array) $data['effective_rights']['entry'])) {
+ // add delete button
+ if ($this->is_deletable($data)) {
$id = $data['id'];
-
- // disable delete for self
- if ($id != $_SESSION['user']['id']) {
- $form->add_button(array(
- 'value' => kolab_html::escape($this->translate('button.delete')),
- 'onclick' => "kadm.{$name}_delete('{$id}')",
- ));
- }
+ $form->add_button(array(
+ 'value' => kolab_html::escape($this->translate('button.delete')),
+ 'onclick' => "kadm.{$name}_delete('{$id}')",
+ ));
}
$ac_min_len = $this->config_get('autocomplete_min_length', 1, Conf::INT);
@@ -1378,12 +1375,21 @@ class kolab_client_task
$this->output->set_env('autocomplete_min_length', $ac_min_len);
$this->output->add_translation('form.required.empty', 'form.maxcount.exceeded',
$name . '.add.success', $name . '.edit.success', $name . '.delete.success',
- $name . '.delete.confirm', 'add', 'edit', 'delete');
+ $name . '.delete.confirm', $name . '.delete.force',
+ 'add', 'edit', 'delete');
return $form;
}
/**
+ * Check wether specified object can be deleted
+ */
+ protected function is_deletable($data)
+ {
+ return !empty($data['id']) && in_array('delete', (array) $data['effective_rights']['entry']);
+ }
+
+ /**
* Search form.
*
* @return string HTML output of the form
@@ -1564,8 +1570,10 @@ class kolab_client_task
continue;
}
+ $class = array('selectable');
+
if (method_exists($this, 'list_item_handler')) {
- $item = $this->list_item_handler($item);
+ $item = $this->list_item_handler($item, $class);
}
else {
$item = array_shift($item);
@@ -1579,7 +1587,7 @@ class kolab_client_task
$cells = array();
$cells[] = array('class' => 'name', 'body' => kolab_html::escape($item),
'onclick' => "kadm.command('$task.info', '$idx')");
- $rows[] = array('id' => $i, 'class' => 'selectable', 'cells' => $cells);
+ $rows[] = array('id' => $i, 'class' => implode(' ', $class), 'cells' => $cells);
}
}
else {
diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php
index 5e288e9..7f59947 100644
--- a/lib/locale/en_US.php
+++ b/lib/locale/en_US.php
@@ -49,10 +49,11 @@ $LANG['domain.add'] = 'Add Domain';
$LANG['domain.add.success'] = 'Domain created successfully.';
$LANG['domain.associateddomain'] = 'Domain name(s)';
$LANG['domain.delete.confirm'] = 'Are you sure, you want to delete this domain?';
+$LANG['domain.delete.force'] = "There are users assigned to this domain.\nAre you sure, you want to delete this domain and all assigned objects?";
$LANG['domain.delete.success'] = 'Domain deleted successfully.';
$LANG['domain.edit'] = 'Edit domain';
$LANG['domain.edit.success'] = 'Domain updated successfully.';
-$LANG['domain.inetdomainbasedn'] = 'Custom Root DN(s)';
+$LANG['domain.inetdomainbasedn'] = 'Custom Root DN';
$LANG['domain.inetdomainstatus'] = 'Status';
$LANG['domain.list'] = 'Domains List';
$LANG['domain.norecords'] = 'No domain records found!';
diff --git a/public_html/js/kolab_admin.js b/public_html/js/kolab_admin.js
index e487688..87f355b 100644
--- a/public_html/js/kolab_admin.js
+++ b/public_html/js/kolab_admin.js
@@ -1406,6 +1406,7 @@ function kolab_admin()
this.domain_delete = function(id)
{
+ this.env.delete_domain_id = id;
this.delete_handler(id, 'domain');
};
@@ -1433,7 +1434,17 @@ function kolab_admin()
this.domain_delete_response = function(response)
{
- this.response_handler(response, 'domain.delete', 'domain.list', {refresh: 1});
+ // domain is not empty
+ if (response && response.code == 450) {
+ this.set_busy(false);
+
+ if (confirm(this.t('domain.delete.force'))) {
+ this.set_busy(true, 'deleting');
+ this.api_post('domain.delete', {'id': this.env.delete_domain_id, force: 1}, 'domain_delete_response');
+ }
+ }
+ else
+ this.response_handler(response, 'domain.delete', 'domain.list', {refresh: 1});
};
this.domain_add_response = function(response)
@@ -1443,7 +1454,21 @@ function kolab_admin()
this.domain_edit_response = function(response)
{
- this.response_handler(response, 'domain.edit', 'domain.list', {refresh: 1});
+ // domain is not empty and delete was requested
+ if (response && response.code == 450) {
+ this.set_busy(false);
+
+ // warn the user and re-send the request
+ if (confirm(this.t('domain.delete.force'))) {
+ var data = this.serialize_form('#'+this.env.form_id);
+ data.force = 1;
+
+ this.set_busy(true, 'saving');
+ this.api_post('domain.edit', data, 'domain_edit_response');
+ }
+ }
+ else
+ this.response_handler(response, 'domain.edit', 'domain.list', {refresh: 1});
};
this.user_info = function(id)
diff --git a/public_html/skins/default/style.css b/public_html/skins/default/style.css
index 6647caa..c6af986 100644
--- a/public_html/skins/default/style.css
+++ b/public_html/skins/default/style.css
@@ -95,6 +95,10 @@ table.list tbody tr td.empty-body {
text-align: center;
}
+table.list tbody tr.deleted td {
+ color: #999;
+}
+
fieldset {
border: 1px solid #d0d0d0;
border-radius: 3px;