From 7af20de2591ec4a76e837a08a61a5ba82701851e Mon Sep 17 00:00:00 2001 From: Endi S. Dewata Date: Tue, 7 Dec 2010 01:51:51 -0600 Subject: [PATCH] SUDO adjustments The SUDO rule details facet has been updated to support the latest UI spec. The facet consists of 5 sections: general, users, hosts, commands, and run-as. The general section contains the SUDO rule description and status. If the status is changed, the sudorule-enable/disable will be invoked. The other sections contain radio buttons for the association category and tables for the members. When a member is added or removed, the category will be adjusted appropriately. If the category is changed to 'all', 'allow', or 'deny', all members will be removed. The last section is currently not working because backend support is not yet available. The adder dialog boxes for users, groups, and hosts has been modified to accept external identities. The layout for the base adder dialog was updated. The base dialog class was updated to support templates. The SUDO dialog boxes were implemented using templates. New CSS classes were added to ipa.css. The HBAC rule details facet has been updated as well. --- install/static/associate.js | 21 +- install/static/details.js | 62 +- install/static/hbac.js | 137 ++--- install/static/hbacsvcgroup.js | 3 +- install/static/ipa.css | 68 ++ .../layouts/default/sudorule-details-general.html | 49 ++ .../layouts/default/sudorule-group-dialog.html | 110 +++ .../layouts/default/sudorule-host-dialog.html | 110 +++ .../layouts/default/sudorule-hostgroup-dialog.html | 110 +++ .../layouts/default/sudorule-user-dialog.html | 110 +++ install/static/rule.js | 47 ++ install/static/sudocmdgroup.js | 3 +- install/static/sudorule.js | 804 ++++++++++++++++++- install/static/widget.js | 196 +++-- 14 files changed, 1575 insertions(+), 255 deletions(-) create mode 100755 install/static/layouts/default/sudorule-details-general.html create mode 100755 install/static/layouts/default/sudorule-group-dialog.html create mode 100755 install/static/layouts/default/sudorule-host-dialog.html create mode 100755 install/static/layouts/default/sudorule-hostgroup-dialog.html create mode 100755 install/static/layouts/default/sudorule-user-dialog.html diff --git a/install/static/associate.js b/install/static/associate.js index e159c4dd600a18ea7434a46247c53afcb666259f..540b1a80f7ee36cbf647ecfdab83be2ad457a5b9 100644 --- a/install/static/associate.js +++ b/install/static/associate.js @@ -169,6 +169,9 @@ function ipa_association_adder_dialog(spec) { ipa_cmd('find', [that.get_filter()], {'all': true}, on_success, null, that.other_entity); }; + that.association_adder_dialog_init = that.init; + that.association_adder_dialog_setup = that.setup; + return that; } @@ -386,24 +389,28 @@ function ipa_association_table_widget(spec) { } }; - that.show_add_dialog = function() { - + that.create_add_dialog = function() { var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || ''; var label = IPA.metadata[that.other_entity].label; var title = 'Add '+label+' to '+that.entity_name+' '+pkey; - var dialog = ipa_association_adder_dialog({ + return ipa_association_adder_dialog({ 'title': title, 'entity_name': that.entity_name, 'pkey': pkey, 'other_entity': that.other_entity }); + }; + + that.show_add_dialog = function() { + + var dialog = that.create_add_dialog(); if (that.adder_columns.length) { dialog.set_columns(that.adder_columns); } - dialog.add = function() { + dialog.execute = function() { that.add( dialog.get_selected_values(), function() { @@ -493,10 +500,6 @@ function ipa_association_table_widget(spec) { command.execute(); }; - that.save = function() { - return null; - }; - // methods that should be invoked by subclasses that.association_table_widget_init = that.init; @@ -707,7 +710,7 @@ function ipa_association_facet(spec) { dialog.set_columns(that.adder_columns); } - dialog.add = function() { + dialog.execute = function() { var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || ''; diff --git a/install/static/details.js b/install/static/details.js index d9dc96bce4faa86ca81a069bb2108936b2d156ac..e3cee071fd7aa0652c708dc18c70e0c3b39b54e6 100644 --- a/install/static/details.js +++ b/install/static/details.js @@ -229,7 +229,7 @@ function ipa_details_section(spec){ } }; - that.load = function(result) { + that.load = function(record) { var fields = that.fields; @@ -242,7 +242,7 @@ function ipa_details_section(spec){ var field = fields[i]; var span = $('span[name='+field.name+']', this.container).first(); field.setup(span); - field.load(result); + field.load(record); } } ); @@ -252,7 +252,7 @@ function ipa_details_section(spec){ for (var j=0; j', { 'class': 'first', @@ -808,16 +812,6 @@ function _ipa_create_text_input(value, param_info, rights, index) return span; } -function ipa_details_reset() -{ - var that = this; - - for (var i=0; i * Adam Young + * Endi Sukma Dewata * * Copyright (C) 2010 Red Hat */ @@ -479,3 +480,70 @@ dl.modal dd { .ui-widget-content { border:0; } + +table.scrollable thead { + display: block; +} + +table.scrollable tbody { + display: block; + overflow: auto; +} + +.adder-dialog-filter { + height: 25px; +} + +.adder-dialog-filter { + height: 25px; +} + +.adder-dialog-results { + position: relative; + height: 200px; +} + +.adder-dialog-available { + border: 1px solid black; + position: absolute; + top: 0px; + left: 0px; + bottom: 0px; + width: 250px; +} + +.adder-dialog-buttons { + position: absolute; + top: 15px; + left: 250px; + right: 250px; + bottom: 0px; + text-align: center; +} + +.adder-dialog-selected { + border: 1px solid black; + position: absolute; + top: 0px; + right: 0px; + bottom: 0px; + width: 250px; +} + +.adder-dialog-internal { + border: 1px solid black; + position: absolute; + top: 0px; + left: 0px; + bottom: 45px; + width: 250px; +} + +.adder-dialog-external { + border: 1px solid black; + position: absolute; + left: 0px; + bottom: 0px; + width: 250px; + height: 40px; +} \ No newline at end of file diff --git a/install/static/layouts/default/sudorule-details-general.html b/install/static/layouts/default/sudorule-details-general.html new file mode 100755 index 0000000000000000000000000000000000000000..728ecf11e62a13ba0fa1ad94e29958b63c89fc8c --- /dev/null +++ b/install/static/layouts/default/sudorule-details-general.html @@ -0,0 +1,49 @@ + + + + General + + + + + +
+ + + + + + + + + + + + + +
+ Name: + + + + + +
+ Description: + + + + + +
+ Rule status: + + + Active + Inactive + + +
+
+ + diff --git a/install/static/layouts/default/sudorule-group-dialog.html b/install/static/layouts/default/sudorule-group-dialog.html new file mode 100755 index 0000000000000000000000000000000000000000..d576f1a1f6fe44f3777303b20277f1f9242ce9e1 --- /dev/null +++ b/install/static/layouts/default/sudorule-group-dialog.html @@ -0,0 +1,110 @@ + + + + Adder Dialog + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ Available +
+ + + + + + + + + + + + + + + + + + + +
+ + + Groups +
+ + + +
+ +
+
+ +
+

+

+
+ +
+ +
+ Prospective +
+ + + + + + + + + + + + + + + + + + + +
+ + + Groups +
+ + + +
+ +
+
+ +
+ +
+ External +
+ + +
+ +
+
+ + diff --git a/install/static/layouts/default/sudorule-host-dialog.html b/install/static/layouts/default/sudorule-host-dialog.html new file mode 100755 index 0000000000000000000000000000000000000000..5eec4186877f2405c265518f16b12a4060154643 --- /dev/null +++ b/install/static/layouts/default/sudorule-host-dialog.html @@ -0,0 +1,110 @@ + + + + Adder Dialog + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ Available +
+ + + + + + + + + + + + + + + + + + + +
+ + + Hosts +
+ + + +
+ +
+
+ +
+

+

+
+ +
+ +
+ Prospective +
+ + + + + + + + + + + + + + + + + + + +
+ + + Hosts +
+ + + +
+ +
+
+ +
+ +
+ External +
+ + +
+ +
+
+ + diff --git a/install/static/layouts/default/sudorule-hostgroup-dialog.html b/install/static/layouts/default/sudorule-hostgroup-dialog.html new file mode 100755 index 0000000000000000000000000000000000000000..57d72f387d8b5ff8377479f03a739ce4d61bbdf2 --- /dev/null +++ b/install/static/layouts/default/sudorule-hostgroup-dialog.html @@ -0,0 +1,110 @@ + + + + Adder Dialog + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ Available +
+ + + + + + + + + + + + + + + + + + + +
+ + + Host Groups +
+ + + +
+ +
+
+ +
+

+

+
+ +
+ +
+ Prospective +
+ + + + + + + + + + + + + + + + + + + +
+ + + Host Groups +
+ + + +
+ +
+
+ +
+ +
+ External +
+ + +
+ +
+
+ + diff --git a/install/static/layouts/default/sudorule-user-dialog.html b/install/static/layouts/default/sudorule-user-dialog.html new file mode 100755 index 0000000000000000000000000000000000000000..c40b97594ea0192140a55685880355a36880c3cc --- /dev/null +++ b/install/static/layouts/default/sudorule-user-dialog.html @@ -0,0 +1,110 @@ + + + + SAdder Dialog + + + + + +
+ +
+ + +
+ +
+ +
+ +
+ Available +
+ + + + + + + + + + + + + + + + + + + +
+ + + Users +
+ + + +
+ +
+
+ +
+

+

+
+ +
+ +
+ Prospective +
+ + + + + + + + + + + + + + + + + + + +
+ + + Users +
+ + + +
+ +
+
+ +
+ +
+ External +
+ + +
+ +
+
+ + diff --git a/install/static/rule.js b/install/static/rule.js index ec1eb72ce1e5f7898e233f8e05c3a43ec7aceff1..73c33b30eed0fa14d1b46890b6fb8836e58f1505 100755 --- a/install/static/rule.js +++ b/install/static/rule.js @@ -77,3 +77,50 @@ function ipa_rule_details_section(spec){ return that; } + +function ipa_rule_association_table_widget(spec) { + + spec = spec || {}; + + var that = ipa_association_table_widget(spec); + + that.category = spec.category; + + that.add = function(values, on_success, on_error) { + + var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || ''; + + var batch = ipa_batch_command({ + 'on_success': on_success, + 'on_error': on_error + }); + + var command; + + if (that.category.save() != '') { + command = ipa_command({ + 'method': that.entity_name+'_mod', + 'args': [pkey], + 'options': {'all': true, 'rights': true}, + 'on_success': function() { + var record = {}; + record[that.category.name] = ['']; + that.category.load(['']); + } + }); + command.set_option(that.category.name, ''); + batch.add_command(command); + } + + command = ipa_command({ + 'method': that.entity_name+'_'+that.add_method, + 'args': [pkey] + }); + command.set_option(that.other_entity, values.join(',')); + batch.add_command(command); + + batch.execute(); + }; + + return that; +} diff --git a/install/static/sudocmdgroup.js b/install/static/sudocmdgroup.js index 4188bc47834b47455e04eddcd7f408c12ac6d3b2..ecb5e0a9a385e4275f100b4625771935fa0724f7 100755 --- a/install/static/sudocmdgroup.js +++ b/install/static/sudocmdgroup.js @@ -155,7 +155,8 @@ function ipa_sudocmdgroup_details_facet(spec) { var field = ipa_sudocmdgroup_member_sudocmd_table_widget({ 'name': 'member_sudocmd', 'label': 'Commands', - 'other_entity': 'sudocmd' + 'other_entity': 'sudocmd', + 'save_values': false }); section.add_field(field); diff --git a/install/static/sudorule.js b/install/static/sudorule.js index 101f8c41fe171fb4ffcb376696c78fa55fcd3472..61eef6bf0b87790f851bfb4adb25b333c74578e7 100755 --- a/install/static/sudorule.js +++ b/install/static/sudorule.js @@ -110,20 +110,35 @@ function ipa_sudorule_details_facet(spec) { that.init = function() { - var section = ipa_details_list_section({ - 'name': 'general', - 'label': 'General' - }); - that.add_section(section); + var section; - section.create_field({'name': 'cn', 'read_only': true}); - section.create_field({'name': 'description'}); - section.create_field({'name': 'cmdcategory'}); + if (IPA.layout) { + section = that.create_section({ + 'name': 'general', + 'label': 'General', + 'template': 'sudorule-details-general.html #contents' + }); + + } else { + section = ipa_sudorule_details_general_section({ + 'name': 'general', + 'label': 'General' + }); + that.add_section(section); + } + + section.create_text({ 'name': 'cn', 'read_only': true }); + section.create_textarea({ 'name': 'description' }); + section.create_radio({ 'name': 'ipaenabledflag' }); section = ipa_rule_details_section({ 'name': 'user', 'label': 'Who', - 'field_name': 'memberuser', + 'field_name': 'usercategory', + 'options': [ + { 'value': 'all', 'label': 'Anyone' }, + { 'value': '', 'label': 'Specified Users and Groups' } + ], 'tables': [ { 'field_name': 'memberuser_user' }, { 'field_name': 'memberuser_group' } @@ -131,21 +146,26 @@ function ipa_sudorule_details_facet(spec) { }); that.add_section(section); - section.add_field(ipa_association_table_widget({ + var category = section.create_radio({ name: 'usercategory', label: 'User category' }); + section.add_field(ipa_sudorule_association_table_widget({ 'id': that.entity_name+'-memberuser_user', - 'name': 'memberuser_user', 'label': 'Users', + 'name': 'memberuser_user', 'label': 'Users', 'category': category, 'other_entity': 'user', 'add_method': 'add_user', 'remove_method': 'remove_user' })); - section.add_field(ipa_association_table_widget({ + section.add_field(ipa_sudorule_association_table_widget({ 'id': that.entity_name+'-memberuser_group', - 'name': 'memberuser_group', 'label': 'Groups', + 'name': 'memberuser_group', 'label': 'Groups', 'category': category, 'other_entity': 'group', 'add_method': 'add_user', 'remove_method': 'remove_user' })); section = ipa_rule_details_section({ 'name': 'host', - 'label': 'Where', - 'field_name': 'memberhost', + 'label': 'Access this host', + 'field_name': 'hostcategory', + 'options': [ + { 'value': 'all', 'label': 'Any Host' }, + { 'value': '', 'label': 'Specified Hosts and Groups' } + ], 'tables': [ { 'field_name': 'memberhost_host' }, { 'field_name': 'memberhost_hostgroup' } @@ -153,62 +173,760 @@ function ipa_sudorule_details_facet(spec) { }); that.add_section(section); - section.add_field(ipa_association_table_widget({ + category = section.create_radio({ 'name': 'hostcategory', 'label': 'Host category' }); + section.add_field(ipa_sudorule_association_table_widget({ 'id': that.entity_name+'-memberhost_host', - 'name': 'memberhost_host', 'label': 'Host', + 'name': 'memberhost_host', 'label': 'Host', 'category': category, 'other_entity': 'host', 'add_method': 'add_host', 'remove_method': 'remove_host' })); - section.add_field(ipa_association_table_widget({ + section.add_field(ipa_sudorule_association_table_widget({ 'id': that.entity_name+'-memberhost_hostgroup', - 'name': 'memberhost_hostgroup', 'label': 'Groups', + 'name': 'memberhost_hostgroup', 'label': 'Groups', 'category': category, 'other_entity': 'hostgroup', 'add_method': 'add_host', 'remove_method': 'remove_host' })); - section = ipa_rule_details_section({ - 'name': 'allow', - 'label': 'Allow', - 'field_name': 'memberallowcmd', - 'tables': [ - { 'field_name': 'memberallowcmd_sudocmd' }, - { 'field_name': 'memberallowcmd_sudocmdgroup' } - ] + section = ipa_sudorule_details_command_section({ + 'name': 'command', + 'label': 'Run Commands' }); that.add_section(section); - section.add_field(ipa_association_table_widget({ + section = ipa_sudorule_details_runas_section({ + 'name': 'runas', + 'label': 'As Whom' + }); + that.add_section(section); + + that.details_facet_init(); + }; + + that.load = function(record) { + var category = record['cmdcategory']; + if (category && category[0] == 'all') { + record['cmdcategory'] = ['allow']; + + } else { + var memberallowcmd_sudocmd = record['memberallowcmd_sudocmd']; + var memberallowcmd_sudocmdgroup = record['memberallowcmd_sudocmdgroup']; + var memberdenycmd_sudocmd = record['memberdenycmd_sudocmd']; + var memberdenycmd_sudocmdgroup = record['memberdenycmd_sudocmdgroup']; + + if (!memberallowcmd_sudocmd && !memberallowcmd_sudocmdgroup + && !memberdenycmd_sudocmd && !memberdenycmd_sudocmdgroup) { + record['cmdcategory'] = ['deny']; + + } else { + record['cmdcategory'] = ['']; + } + } + + that.details_facet_load(record); + }; + + that.update = function() { + + var pkey = $.bbq.getState(that.entity_name + '-pkey', true) || ''; + + var modify_operation = { + 'execute': false, + 'command': ipa_command({ + 'method': that.entity_name+'_mod', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }; + + var categories = { + 'usercategory': { + 'remove_values': false + }, + 'hostcategory': { + 'remove_values': false + }, + 'cmdcategory': { + 'remove_values': false + }, + 'runasusercategory': { + 'remove_values': false + }, + 'runasgroupcategory': { + 'remove_values': false + } + }; + + var member_operations = { + 'memberuser': { + 'category': 'usercategory', + 'has_values': false, + 'command': ipa_command({ + 'method': that.entity_name+'_remove_user', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }, + 'memberhost': { + 'category': 'hostcategory', + 'has_values': false, + 'command': ipa_command({ + 'method': that.entity_name+'_remove_host', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }, + 'memberallowcmd': { + 'category': 'cmdcategory', + 'has_values': false, + 'command': ipa_command({ + 'method': that.entity_name+'_remove_allow_command', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }, + 'memberdenycmd': { + 'category': 'cmdcategory', + 'has_values': false, + 'command': ipa_command({ + 'method': that.entity_name+'_remove_deny_command', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }, + 'runasuser': { + 'category': 'runasusercategory', + 'has_values': false, + 'command': ipa_command({ + 'method': that.entity_name+'_remove_runas_user', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }, + 'runasgroup': { + 'category': 'runasgroupcategory', + 'has_values': false, + 'command': ipa_command({ + 'method': that.entity_name+'_remove_runas_group', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + } + }; + + var enable_operation = { + 'execute': false, + 'command': ipa_command({ + 'method': that.entity_name+'_enable', + 'args': [pkey], + 'options': {'all': true, 'rights': true} + }) + }; + + for (var i=0; i= 0) { + // prepare command to remove members if needed + var attribute = field.name.substring(0, p); + var other_entity = field.name.substring(p+1); + + if (values.length) { + member_operations[attribute].command.set_option(other_entity, values.join(',')); + member_operations[attribute].has_values = true; + } + continue; + } + + // skip unchanged field + if (!field.is_dirty(span)) continue; + + // check enable/disable + if (field.name == 'ipaenabledflag') { + if (values[0] == 'FALSE') enable_operation.command.method = that.entity_name+'_disable'; + enable_operation.execute = true; + continue; + } + + if (field.name == 'cmdcategory') { + var value = values[0]; + if (value == 'allow') { + values = ['all']; + categories[field.name].remove_values = true; + } else if (value == 'deny') { + values = []; + categories[field.name].remove_values = true; + } else { + values = []; + } + + } else if (categories[field.name]) { + if (values[0] == 'all') { + categories[field.name].remove_values = true; + } + } + + // use setattr/addattr if param_info not available + if (!param_info) { + for (var k=0; k', { + 'style': 'width: 100%;' + }).appendTo(container); + + var tr = $('').appendTo(table); + + var td = $('', { + 'style': 'width: 100px; text-align: right;', + 'html': 'Name:' + }).appendTo(tr); + + td = $('').appendTo(tr); + + var span = $('', { 'name': 'cn' }).appendTo(td); + + $('', { + 'type': 'text', + 'name': 'cn', + 'size': 30 + }).appendTo(span); + + span.append(' '); + + $('', { + 'name': 'undo', + 'class': 'ui-state-highlight ui-corner-all', + 'style': 'display: none;', + 'html': 'undo' + }).appendTo(span); + + tr = $('').appendTo(table); + + td = $('', { + 'style': 'text-align: right; vertical-align: top;', + 'html': 'Description:' + }).appendTo(tr); + + td = $('').appendTo(tr); + + span = $('', { 'name': 'description' }).appendTo(td); + + $('