/* Authors: * Pavel Zuna * Endi S. Dewata * * Copyright (C) 2010 Red Hat * see file 'COPYING' for use and warranty information * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ define(['./ipa', './jquery', './phases', './reg', './text', './details', './search', './association', './entity', './certificate'], function(IPA, $, phases, reg, text) { var exp = IPA.host = {}; var make_spec = function() { return { name: 'host', policies: [ IPA.search_facet_update_policy, IPA.details_facet_update_policy, { $factory: IPA.cert.cert_update_policy, source_facet: 'details', dest_entity: 'cert', dest_facet: 'details' }, { $factory: IPA.cert.cert_update_policy, source_facet: 'details', dest_entity: 'cert', dest_facet: 'search' } ], facets: [ { $type: 'search', columns: [ 'fqdn', 'description', { name: 'has_keytab', label: '@i18n:objects.host.enrolled', formatter: 'boolean' } ] }, { $type: 'details', $factory: IPA.host.details_facet, sections: [ { name: 'details', fields: [ { $type: 'host_dnsrecord_entity_link', name: 'fqdn', other_entity: 'dnsrecord' }, 'krbprincipalname', { $type: 'textarea', name: 'description' }, 'l', 'nshostlocation', 'nshardwareplatform', 'nsosversion', { $type: 'sshkeys', name: 'ipasshpubkey', label: '@i18n:objects.sshkeystore.keys' }, { $type: 'multivalued', name: 'macaddress', flags: ['w_if_no_aci'] }, { name: 'ipakrbokasdelegate', $type: 'checkbox', acl_param: 'krbticketflags' } ] }, { name: 'enrollment', action_panel: { $factory: IPA.action_panel, name: 'enrollment_actions', actions: ['unprovision', 'set_otp', 'reset_otp'] }, fields: [ { $factory: IPA.host_keytab_widget, name: 'has_keytab', label: '@i18n:objects.host.keytab' }, { $type: 'host_password', name: 'has_password', label: '@i18n:objects.host.password' } ] }, { name: 'certificate', action_panel: { $factory: IPA.action_panel, name: 'cert_actions', actions: [ 'request_cert', 'view_cert', 'get_cert', 'revoke_cert', 'restore_cert' ] }, fields: [ { $type: 'certificate_status', name: 'certificate_status', label: '@i18n:objects.host.status' } ] } ], actions: [ 'host_unprovision', { $type: 'set_otp', name: 'set_otp', label: '@i18n:objects.host.password_set_title', status: 'missing', hide_cond: ['has_password'] }, { $type: 'set_otp', name: 'reset_otp', label: '@i18n:objects.host.password_reset_title', status: 'present', show_cond: ['has_password'] }, 'cert_view', 'cert_get', 'cert_request', 'cert_revoke', 'cert_restore' ], state: { evaluators: [ IPA.host.has_password_evaluator, IPA.host.has_keytab_evaluator, IPA.host.userpassword_acl_evaluator, IPA.host.krbprincipalkey_acl_evaluator, IPA.cert.certificate_evaluator ] }, policies: [ IPA.host.enrollment_policy, IPA.host.certificate_policy ] }, { $type: 'association', name: 'managedby_host', add_method: 'add_managedby', remove_method: 'remove_managedby' }, { $type: 'association', name: 'memberof_hostgroup', associator: IPA.serial_associator }, { $type: 'association', name: 'memberof_netgroup', associator: IPA.serial_associator }, { $type: 'association', name: 'memberof_role', associator: IPA.serial_associator }, { $type: 'association', name: 'memberof_hbacrule', associator: IPA.serial_associator, add_method: 'add_host', remove_method: 'remove_host' }, { $type: 'association', name: 'memberof_sudorule', associator: IPA.serial_associator, add_method: 'add_host', remove_method: 'remove_host' } ], standard_association_facets: true, adder_dialog: { $factory: IPA.host_adder_dialog, height: 300, sections: [ { $factory: IPA.composite_widget, name: 'fqdn', fields: [ { $type: 'host_fqdn', name: 'fqdn', required: true } ] }, { name: 'other', fields: [ { name: 'ip_address', validators: [ 'ip_address' ], metadata: '@mc-opt:host_add:ip_address' }, { $type: 'force_host_add_checkbox', name: 'force', metadata: '@mc-opt:host_add:force' } ] } ] }, deleter_dialog: { $factory: IPA.host_deleter_dialog } };}; IPA.host.details_facet = function(spec, no_init) { var that = IPA.details_facet(spec, true); that.certificate_loaded = IPA.observer(); that.certificate_updated = IPA.observer(); that.get_refresh_command_name = function() { return that.entity.name+'_show_'+that.get_pkey(); }; if (!no_init) that.init_details_facet(); return that; }; IPA.host_fqdn_widget = function(spec) { spec = spec || {}; spec.widgets = [ { $type: 'text', name: 'hostname', label: '@i18n:objects.service.host', required: true }, { $type: 'dnszone_select', name: 'dnszone', label: '@mo:dnszone.label_singular', editable: true, empty_option: false, required: true, searchable: true } ]; var that = IPA.composite_widget(spec); that.create = function(container) { that.container = container; var hostname = that.widgets.get_widget('hostname'); var dnszone = that.widgets.get_widget('dnszone'); var table = $('', { 'class': 'fqdn' }).appendTo(that.container); var tr = $('').appendTo(table); var th = $('').appendTo(table); var td = $('
', { 'class': 'hostname', title: hostname.label, text: hostname.label }).appendTo(tr); $('', { 'class': 'required-indicator', text: IPA.required_indicator }).appendTo(th); th = $('', { 'class': 'dnszone', title: dnszone.label, text: dnszone.label }).appendTo(tr); $('', { 'class': 'required-indicator', text: IPA.required_indicator }).appendTo(th); tr = $('
', { 'class': 'hostname' }).appendTo(tr); var widget_cont = $('
', { name: hostname.name }).appendTo(td); hostname.create(widget_cont); td = $('
', { 'class': 'dnszone' }).appendTo(tr); widget_cont = $('
', { name: dnszone.name }).appendTo(td); dnszone.create(widget_cont); var hostname_input = $('input', hostname.container); var dnszone_input = $('input', dnszone.container); hostname_input.keyup(function(e) { var value = hostname_input.val(); var i = value.indexOf('.'); if (i >= 0) { var hostname = value.substr(0, i); var dnszone = value.substr(i+1); hostname_input.val(hostname); if (dnszone) { dnszone_input.val(dnszone); dnszone_input.focus(); } IPA.select_range(dnszone_input, 0, dnszone_input.val().length); } }); }; return that; }; IPA.host_fqdn_field = function(spec) { spec = spec || {}; var that = IPA.field(spec); that.validate_required = function() { var hostname = that.hostname_widget.save(); var dnszone = that.dns_zone_widget.save(); var valid = true; if(!hostname.length || hostname[0] === '') { that.hostname_widget.show_error(text.get('@i18n:widget.validation.required')); that.valid = valid = false; } if(!dnszone.length || dnszone[0] === '') { that.dns_zone_widget.show_error(text.get('@i18n:widget.validation.required')); that.valid = valid = false; } return valid; }; that.hide_error = function() { that.hostname_widget.hide_error(); that.dns_zone_widget.hide_error(); }; that.save = function(record) { if(!record) record = {}; var hostname = that.hostname_widget.save()[0]; var dnszone = that.dns_zone_widget.save()[0]; record.fqdn = hostname && dnszone ? [ hostname+'.'+dnszone ] : []; return record.fqdn; }; that.reset = function() { that.hostname_widget.update([]); that.dns_zone_widget.update([]); }; that.widgets_created = function() { that.widget = that.container.widgets.get_widget(that.widget_name); that.hostname_widget = that.widget.widgets.get_widget('hostname'); that.dns_zone_widget = that.widget.widgets.get_widget('dnszone'); }; return that; }; IPA.host_adder_dialog = function(spec) { spec = spec || {}; spec.retry = spec.retry !== undefined ? spec.retry : false; if (!IPA.dns_enabled) { //When server is installed without DNS support, a use of host_fqdn_widget //is bad because there are no DNS zones. IP address field is useless as //well. Special section and IP address field should be removed and normal //fqdn textbox has to be added. spec.sections.shift(); spec.sections[0].fields.shift(); spec.sections[0].fields.unshift('fqdn'); delete spec.height; } var that = IPA.entity_adder_dialog(spec); that.create = function() { that.entity_adder_dialog_create(); that.container.addClass('host-adder-dialog'); }; that.on_error = IPA.create_4304_error_handler(that); return that; }; IPA.host_deleter_dialog = function(spec) { spec = spec || {}; var that = IPA.search_deleter_dialog(spec); that.create = function() { that.deleter_dialog_create(); var metadata = IPA.get_command_option('host_del', 'updatedns'); that.updatedns = $('', { type: 'checkbox', name: 'updatedns', title: metadata.doc }).appendTo(that.container); that.container.append(' '); that.container.append(metadata.doc); }; that.create_command = function() { var batch = that.search_deleter_dialog_create_command(); var updatedns = that.updatedns.is(':checked'); for (var i=0; i', { name: 'missing', style: 'display: none;' }).appendTo(container); $('', { src: 'images/caution-icon.png', 'class': 'status-icon' }).appendTo(that.missing_span); that.missing_span.append(' '); that.missing_span.append(text.get('@i18n:objects.host.keytab_missing')); that.present_span = $('', { name: 'present', style: 'display: none;' }).appendTo(container); $('', { src: 'images/check-icon.png', 'class': 'status-icon' }).appendTo(that.present_span); that.present_span.append(' '); that.present_span.append(text.get('@i18n:objects.host.keytab_present')); }; that.update = function(values) { set_status(values[0] ? 'present' : 'missing'); that.updated.notify([], that); }; that.clear = function() { that.present_span.css('display', 'none'); that.missing_span.css('display', 'none'); }; function set_status(status) { that.present_span.css('display', status == 'present' ? 'inline' : 'none'); that.missing_span.css('display', status == 'missing' ? 'inline' : 'none'); } return that; }; IPA.host_unprovision_dialog = function(spec) { spec.title = spec.title || '@i18n:objects.host.unprovision_title'; spec = spec || {}; var that = IPA.dialog(spec); that.facet = spec.facet; that.title = that.title.replace('${entity}', that.entity.metadata.label_singular); that.create = function() { that.container.append(text.get('@i18n:objects.host.unprovision_confirmation')); }; that.create_buttons = function() { that.create_button({ name: 'unprovision', label: '@i18n:objects.host.unprovision', click: function() { that.unprovision( function(data, text_status, xhr) { that.facet.refresh(); that.close(); IPA.notify_success('@i18n:objects.host.unprovisioned'); }, function(xhr, text_status, error_thrown) { that.close(); } ); } }); that.create_button({ name: 'cancel', label: '@i18n:buttons.cancel', click: function() { that.close(); } }); }; that.unprovision = function(on_success, on_error) { var pkey = that.facet.get_pkeys(); var command = IPA.command({ name: that.entity.name+'_disable_'+pkey, entity: that.entity.name, method: 'disable', args: pkey, on_success: on_success, on_error: on_error }); command.execute(); }; that.create_buttons(); return that; }; IPA.host.unprovision_action = function(spec) { spec = spec || {}; spec.name = spec.name || 'unprovision'; spec.label = spec.label || '@i18n:objects.host.unprovision'; spec.enable_cond = spec.enable_cond || ['has_keytab', 'krbprincipalkey_w']; var that = IPA.action(spec); that.execute_action = function(facet) { var dialog = IPA.host_unprovision_dialog({ entity: facet.entity, facet: facet }); dialog.open(); }; return that; }; IPA.host.krbprincipalkey_acl_evaluator = function(spec) { spec.name = spec.name || 'unprovision_acl_evaluator'; spec.attribute = spec.attribute || 'krbprincipalkey'; var that = IPA.acl_state_evaluator(spec); return that; }; IPA.host.has_keytab_evaluator = function(spec) { spec.name = spec.name || 'has_keytab_evaluator'; spec.attribute = spec.attribute || 'has_keytab'; spec.value = spec.value || [true]; spec.representation = spec.representation || 'has_keytab'; var that = IPA.value_state_evaluator(spec); return that; }; IPA.host_password_widget = function(spec) { spec = spec || {}; var that = IPA.input_widget(spec); that.create = function(container) { that.widget_create(container); that.missing_span = $('', { name: 'missing' }).appendTo(container); $('', { src: 'images/caution-icon.png', 'class': 'status-icon' }).appendTo(that.missing_span); that.missing_span.append(' '); that.missing_span.append(text.get('@i18n:objects.host.password_missing')); that.present_span = $('', { name: 'present', style: 'display: none;' }).appendTo(container); $('', { src: 'images/check-icon.png', 'class': 'status-icon' }).appendTo(that.present_span); that.present_span.append(' '); that.present_span.append(text.get('@i18n:objects.host.password_present')); }; that.update = function(values) { set_status(values[0] ? 'present' : 'missing'); that.updated.notify([], that); }; that.clear = function() { that.missing_span.css('display', 'none'); that.present_span.css('display', 'none'); }; function set_status(status) { that.status = status; if (status == 'missing') { that.missing_span.css('display', 'inline'); that.present_span.css('display', 'none'); } else { that.missing_span.css('display', 'none'); that.present_span.css('display', 'inline'); } } return that; }; IPA.host.set_otp_dialog = function(spec) { spec = spec || {}; spec.width = spec.width || 400; spec.sections = spec.sections || [ { fields: [ { name: 'password1', label: '@i18n:password.new_password', $type: 'password', required: true }, { name: 'password2', label: '@i18n:password.verify_password', $type: 'password', required: true, validators: [{ $type: 'same_password', other_field: 'password1' }] } ] } ]; var that = IPA.dialog(spec); IPA.confirm_mixin().apply(that); that.facet = spec.facet; that.set_status = function(status) { var button = that.get_button('set_password'); if (status == 'missing') { that.title = text.get('@i18n:objects.host.password_set_title'); button.label = text.get('@i18n:objects.host.password_set_button'); } else { that.title = text.get('@i18n:objects.host.password_reset_title'); button.label = text.get('@i18n:objects.host.password_reset_button'); } }; that.on_confirm = function() { if (!that.validate()) return; var new_password = that.fields.get_field('password1').save()[0]; that.set_otp(new_password); that.close(); }; that.create_buttons = function() { that.create_button({ name: 'set_password', label: '@i18n:objects.host.password_set_button', click: function() { that.on_confirm(); } }); that.create_button({ name: 'cancel', label: '@i18n:buttons.cancel', click: function() { that.close(); } }); }; that.set_otp = function(password) { var pkey = that.facet.get_pkeys(); var command = IPA.command({ entity: that.entity.name, method: 'mod', args: pkey, options: { all: true, rights: true, userpassword: password }, on_success: function(data) { that.facet.load(data); that.close(); IPA.notify_success('@i18n:objects.host.password_set_success'); }, on_error: function() { that.close(); } }); command.execute(); }; that.create_buttons(); return that; }; IPA.host.set_otp_action = function(spec) { spec = spec || {}; spec.name = spec.name || 'set_otp'; spec.label = spec.label || '@i18n:objects.host.password_set_title'; spec.enable_cond = spec.enable_cond || ['userpassword_w']; var that = IPA.action(spec); that.status = spec.status || 'missing'; that.execute_action = function(facet) { var dialog = IPA.host.set_otp_dialog({ entity: facet.entity, facet: facet }); dialog.set_status(that.status); dialog.open(); }; return that; }; IPA.host.userpassword_acl_evaluator = function(spec) { spec.name = spec.name || 'userpassword_acl_evaluator'; spec.attribute = spec.attribute || 'userpassword'; var that = IPA.acl_state_evaluator(spec); return that; }; IPA.host.has_password_evaluator = function(spec) { spec.name = spec.name || 'has_password_evaluator'; spec.attribute = spec.attribute || 'has_password'; spec.value = spec.value || [true]; spec.representation = spec.representation || 'has_password'; var that = IPA.value_state_evaluator(spec); return that; }; IPA.host.certificate_policy = function(spec) { spec = spec || {}; spec.get_pkey = spec.get_pkey || function(result) { var values = result.fqdn; return values ? values[0] : null; }; spec.get_name = spec.get_name || function(result) { var values = result.fqdn; return values ? values[0] : null; }; spec.get_principal = spec.get_principal || function(result) { var values = result.krbprincipalname; return values ? values[0] : null; }; spec.get_hostname = spec.get_hostname || spec.get_name; var that = IPA.cert.load_policy(spec); return that; }; exp.entity_spec = make_spec(); exp.register = function() { var e = reg.entity; var w = reg.widget; var f = reg.field; var a = reg.action; e.register({type: 'host', spec: exp.entity_spec}); f.register('host_fqdn', IPA.host_fqdn_field); w.register('host_fqdn', IPA.host_fqdn_widget); f.register('dnszone_select', IPA.field); w.register('dnszone_select', IPA.dnszone_select_widget); f.register('host_dnsrecord_entity_link', IPA.host_dnsrecord_entity_link_field); w.register('host_dnsrecord_entity_link', IPA.link_widget); f.register('force_host_add_checkbox', IPA.checkbox_field); w.register('force_host_add_checkbox', IPA.force_host_add_checkbox_widget); f.register('host_password', IPA.field); w.register('host_password', IPA.host_password_widget); a.register('host_unprovision', exp.unprovision_action); a.register('set_otp', exp.set_otp_action); }; phases.on('registration', exp.register); return exp; });