/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var App = require('app'); require('controllers/main/admin/kerberos/step4_controller'); App.MainAdminKerberosController = App.KerberosWizardStep4Controller.extend({ name: 'mainAdminKerberosController', securityEnabled: false, defaultKerberosLoaded: false, dataIsLoaded: false, isRecommendedLoaded: true, isEditMode: false, kdc_type: '', kdcTypesValues: { 'mit-kdc': Em.I18n.t('admin.kerberos.wizard.step1.option.kdc'), 'active-directory': Em.I18n.t('admin.kerberos.wizard.step1.option.ad'), 'ipa': Em.I18n.t('admin.kerberos.wizard.step1.option.ipa'), 'none': Em.I18n.t('admin.kerberos.wizard.step1.option.manual') }, // use cluster descriptor instead of stack loadStackDescriptorConfigs: Em.alias('loadClusterDescriptorConfigs'), getAddSecurityWizardStatus: function () { return App.db.getSecurityWizardStatus(); }, setAddSecurityWizardStatus: function (status) { App.db.setSecurityWizardStatus(status); }, setDisableSecurityStatus: function (status) { App.db.setDisableSecurityStatus(status); }, getDisableSecurityStatus: function (status) { return App.db.getDisableSecurityStatus(); }, notifySecurityOff: false, notifySecurityAdd: false, notifySecurityOffPopup: function () { var self = this; this.checkServiceWarnings().then(function() { App.ModalPopup.show({ header: Em.I18n.t('popup.confirmation.commonHeader'), primary: Em.I18n.t('ok'), onPrimary: function () { App.db.setSecurityDeployCommands(undefined); self.setDisableSecurityStatus("RUNNING"); App.router.transitionTo('disableSecurity'); this.hide(); }, bodyClass: Ember.View.extend({ templateName: require('templates/main/admin/kerberos/notify_security_off_popup') }) }); }); }, /** * Show confirmation popup for regenerate keytabs * @method regenerateKeytabs * @param callback function (optional) * @return {App.ModalPopup} */ regenerateKeytabs: function (callback) { var self = this; return App.ModalPopup.show({ /** * True - regenerate keytabs only for missing hosts and components, false - regenerate for all hosts and components * @type {boolean} */ regenerateKeytabsOnlyForMissing: false, header: Em.I18n.t('admin.kerberos.button.regenerateKeytabs'), bodyClass: Em.View.extend({ templateName: require('templates/main/admin/kerberos/regenerate_keytabs_popup_body') }), onPrimary: function () { this._super(); return self.restartServicesAfterRegenerate(this.get('regenerateKeytabsOnlyForMissing'), callback); } }); }, /** * Show confirmation popup for restarting all services and after confirmation regenerate keytabs * * @param regenerateKeytabsOnlyForMissing {Boolean} * @param callback (optional) * @returns {*} */ restartServicesAfterRegenerate: function (regenerateKeytabsOnlyForMissing, callback) { var self = this; return App.ModalPopup.show({ /** * True - automatically restart services, false - user will have to restart required services manually * @type {boolean} */ restartComponents: false, header: Em.I18n.t('admin.kerberos.button.regenerateKeytabs'), bodyClass: Em.View.extend({ templateName: require('templates/main/admin/kerberos/restart_services_after_regenerate_body') }), onPrimary: function () { this._super(); var popupContext = this; // Keytabs can either be regenerated directly or after updating kerberos descriptor in the callback function if (Em.typeOf(callback) === 'function') { callback().done(function () { self.regenerateKeytabsRequest(regenerateKeytabsOnlyForMissing, popupContext.get('restartComponents')); }); } else { self.regenerateKeytabsRequest(regenerateKeytabsOnlyForMissing, popupContext.get('restartComponents')); } } }); }, /** * Send request to regenerate keytabs * @param {boolean} missingOnly determines type of regeneration - missing|all * @param {boolean} withAutoRestart determines if the system should automatically restart all services or not after regeneration * @returns {$.ajax} */ regenerateKeytabsRequest: function (missingOnly, withAutoRestart) { missingOnly = missingOnly || false; return App.ajax.send({ name: "admin.kerberos_security.regenerate_keytabs", sender: this, data: { type: missingOnly ? 'missing' : 'all', withAutoRestart: withAutoRestart || false }, success: "regenerateKeytabsSuccess" }); }, /** * Success callback of regenerateKeytabs * show background operations popup if appropriate option is set * * @param data * @param opt * @param params * @param request */ regenerateKeytabsSuccess: function (data, opt, params, request) { var self = this; App.router.get('userSettingsController').dataLoading('show_bg').done(function (initValue) { if (initValue) { App.router.get('backgroundOperationsController').showPopup(); } self.set('needsRestartAfterRegenerate', params.withAutoRestart); }); }, /** * Do request to server for restarting all services * @method restartAllServices * @return {$.ajax} */ restartAllServices: function () { if (!App.router.get('backgroundOperationsController.allOperationsCount')) { if (this.get('needsRestartAfterRegenerate')) { this.set('needsRestartAfterRegenerate', false); App.router.get('mainServiceController').restartAllServices(); } } }.observes('controllers.backgroundOperationsController.allOperationsCount'), /** * performs cluster check before kerbefos security * wizard starts if preKerberizeCheck supports is true * otherwise runs startKerberosWizard * @method checkAndStartKerberosWizard */ checkAndStartKerberosWizard: function () { if (App.get('supports.preKerberizeCheck')) { App.ajax.send({ name: "admin.kerberos_security.checks", sender: this, success: "runSecurityCheckSuccess" }); } else { this.startKerberosWizard(); } }, /** * success callback of checkAndStartKerberosWizard() * if there are some fails - it shows popup else open security wizard * @param data {object} * @param opt {object} * @param params {object} */ runSecurityCheckSuccess: function (data, opt, params) { //TODO correct check if (data.items.someProperty('UpgradeChecks.status', "FAIL")) { var hasFails = data.items.someProperty('UpgradeChecks.status', 'FAIL'), header = Em.I18n.t('popup.clusterCheck.Security.header').format(params.label), title = Em.I18n.t('popup.clusterCheck.Security.title'), alert = Em.I18n.t('popup.clusterCheck.Security.alert'); App.showClusterCheckPopup(data, { header: header, failTitle: title, failAlert: alert, noCallbackCondition: hasFails }); } else { this.startKerberosWizard(); } }, startKerberosWizard: function () { var self = this; this.checkServiceWarnings().then(function() { self.setAddSecurityWizardStatus('RUNNING'); App.router.get('kerberosWizardController').setDBProperty('onClosePath', 'main.admin.adminKerberos.index'); App.router.transitionTo('adminKerberos.adminAddKerberos'); }); }, /** * Loads the security status from server (security_enabled property in cluster-env configuration) */ loadSecurityStatusFromServer: function () { if (App.get('testMode')) { this.set('securityEnabled', !App.get('testEnableSecurity')); this.set('dataIsLoaded', true); } else { //get Security Status From Server this.getSecurityType(); return this.getSecurityStatus(); } }, /** * Load security status from server. * @returns {$.Deferred} */ getSecurityStatus: function () { var self = this; var dfd = $.Deferred(); if (App.get('testMode')) { this.set('securityEnabled', !App.get('testEnableSecurity')); this.set('dataIsLoaded', true); dfd.resolve(); } else { //get Security Status From Server App.ajax.send({ name: 'admin.security_status', sender: this, success: 'getSecurityStatusSuccessCallback', error: 'errorCallback' }) .always(function() { self.getSecurityType(function() { dfd.resolve(); }); }); } return dfd.promise(); }, getSecurityStatusSuccessCallback: function (data) { this.set('dataIsLoaded', true); var securityType = data.Clusters.security_type; this.set('securityEnabled', securityType === 'KERBEROS'); }, errorCallback: function (jqXHR) { this.set('dataIsLoaded', true); // Show the error popup if the API call received a response from the server. // jqXHR.status will be empty when browser cancels the request. Refer to AMBARI-5921 for more info if (!!jqXHR.status) { this.showSecurityErrorPopup(); } }, showSecurityErrorPopup: function () { App.ModalPopup.show({ header: Em.I18n.t('common.error'), secondary: false, bodyClass: Ember.View.extend({ template: Ember.Handlebars.compile('

{{t admin.security.status.error}}

') }) }); }, /** * Override App.KerberosWizardStep4Controller */ clearStep: function() { this.set('isEditMode', false); this._super(); }, /** * Override App.KerberosWizardStep4Controller * * @param {App.ServiceConfigProperty[]} properties */ setStepConfigs: function (properties) { this.get('stepConfigs').clear(); this._super(properties); this.get('stepConfigs').forEach(function (serviceConfig) { serviceConfig.set('initConfigsLength', serviceConfig.get('configs.length')); }); }, /** * Override App.KerberosWizardStep4Controller * * @param {App.ServiceConfigProperty[]} configs * @returns {App.ServiceConfigProperty[]} */ prepareConfigProperties: function (configs) { var self = this; var configProperties = configs.slice(0); var siteProperties = App.configsCollection.getAll(); var installedServiceNames = ['Cluster'].concat(App.Service.find().mapProperty('serviceName')); configProperties = configProperties.filter(function (item) { return installedServiceNames.contains(item.get('serviceName')); }); configProperties.setEach('isSecureConfig', false); configProperties.forEach(function (property, item, allConfigs) { if (['spnego_keytab', 'spnego_principal'].contains(property.get('name'))) { property.addObserver('value', self, 'spnegoPropertiesObserver'); } if (property.get('observesValueFrom')) { var observedValue = allConfigs.findProperty('name', property.get('observesValueFrom')).get('value'); property.set('value', observedValue); property.set('recommendedValue', observedValue); } if (property.get('serviceName') == 'Cluster') { property.set('category', 'Global'); } else { property.set('category', property.get('serviceName')); } // All user identity should be grouped under "Ambari Principals" category if (property.get('identityType') == 'user') property.set('category', 'Ambari Principals'); var siteProperty = siteProperties.findProperty('name', property.get('name')); if (siteProperty) { if (siteProperty.category === property.get('category')) { property.set('displayName', siteProperty.displayName); if (siteProperty.index) { property.set('index', siteProperty.index); } } if (siteProperty.displayType) { property.set('displayType', siteProperty.displayType); } } }); configProperties.setEach('isEditable', false); return configProperties; }, getKDCSessionState: function (callback, kdcCancelHandler) { var self = this; if (this.get('securityEnabled') || App.get('isKerberosEnabled')) { this.getSecurityType(function () { if (!self.get('isManualKerberos')) { App.ajax.send({ name: 'kerberos.session.state', sender: self, data: { callback: callback }, success: 'checkState', kdcCancelHandler: kdcCancelHandler }) } else { callback(); } }); } else { callback(); } }, /** * Determines security type. * * @param {function} [callback] callback function to execute * @returns {$.Deferred|null} */ getSecurityType: function (callback) { if (this.get('securityEnabled') || App.get('isKerberosEnabled')) { if (!this.get('kdc_type')) { return App.ajax.send({ name: 'admin.security.cluster_configs.kerberos', sender: this, data: { clusterName: App.get('clusterName'), additionalCallback: callback }, success: 'getSecurityTypeSuccess' }); } else { if (Em.typeOf(callback) === 'function') { callback(); } return $.Deferred().resolve().promise; } } else if (Em.typeOf(callback) === 'function') { callback(); } else { return $.Deferred().resolve().promise; } }, getSecurityTypeSuccess: function (data, opt, params) { var kdcType = data.items && data.items[0] && Em.getWithDefault(Em.getWithDefault(data.items[0], 'configurations', []).findProperty('type', 'kerberos-env') || {}, 'properties.kdc_type', 'none') || 'none'; this.set('kdc_type', kdcType); if (Em.typeOf(params.additionalCallback) === 'function') { params.additionalCallback(); } }, isManualKerberos: Em.computed.equal('kdc_type', 'none'), checkState: function (data, opt, params) { var res = Em.get(data, 'Services.attributes.kdc_validation_result'); var message = Em.get(data, 'Services.attributes.kdc_validation_failure_details'); if (res.toUpperCase() === "OK") { params.callback(); } else { App.showInvalidKDCPopup(opt, App.format.kdcErrorMsg(message, false)); } }, /** * Determines if some config value is changed * @type {boolean} */ isPropertiesChanged: Em.computed.someBy('stepConfigs', 'isPropertiesChanged', true), /** * Determines if the save button is disabled */ isSaveButtonDisabled: Em.computed.or('isSubmitDisabled', '!isPropertiesChanged'), /** * Determines if the `Disbale Kerberos` and `Regenerate Keytabs` button are disabled */ isKerberosButtonsDisabled: Em.computed.not('isSaveButtonDisabled'), makeConfigsEditable: function () { if (this.get('stepConfigs') && this.get('stepConfigs.length')) { this.set('isEditMode', true); this.get('stepConfigs').forEach(function (_stepConfig) { _stepConfig.get('configs').setEach('isEditable', true); _stepConfig.get('configs').forEach(function (_config) { _config.set('isEditable', _config.get('name') != 'realm'); }); }, this); } }, _updateConfigs: function () { this.makeConfigsUneditable(true); }, makeConfigsUneditable: function (configsUpdated) { this.set('isEditMode', false); this.get('stepConfigs').forEach(function (_stepConfig) { _stepConfig.get('configs').forEach(function (_config) { if (configsUpdated === true) { // configsUpdated should be checked for boolean true _config.set('savedValue', _config.get('value')); _config.set('defaultValue', _config.get('value')); } else { _config.set('value', _config.get('savedValue')); } _config.set('isEditable', false); }); }, this); }, /** * Update kerberos descriptor and regenerate keytabs */ submit: function (context) { var callback; var self = this; var kerberosDescriptor = this.get('kerberosDescriptor'); var configs = []; this.get('stepConfigs').forEach(function (_stepConfig) { configs = configs.concat(_stepConfig.get('configs')); }); callback = function () { return App.ajax.send({ name: 'admin.kerberos.cluster.artifact.update', sender: self, data: { artifactName: 'kerberos_descriptor', data: { artifact_data: kerberosDescriptor } }, success: '_updateConfigs' }); }; this.updateKerberosDescriptor(kerberosDescriptor, configs); if (this.get('isManualKerberos')) { callback().done(function () { self.regenerateKeytabsRequest(false,false); }); } else { this.restartServicesAfterRegenerate(false, callback); } }, /** * List of the warnings regarding specific services before enabling/disabling Kerberos. * * @type {String[]} */ serviceAlerts: function() { var messages = []; var serviceAlertMap = { YARN: Em.I18n.t('admin.kerberos.service.alert.yarn') }; var installedServices = App.Service.find().mapProperty('serviceName'); Em.keys(serviceAlertMap).forEach(function(serviceName) { if (installedServices.contains(serviceName)) { messages.push(serviceAlertMap[serviceName]); } }); return messages; }.property(), /** * Check for additional info to display before enabling/disabling kerberos and show appropriate * messages in popup if needed. * @returns {$.Deferred} - promise */ checkServiceWarnings: function() { var dfd = $.Deferred(); this.displayServiceWarnings(this.get('serviceAlerts'), dfd); return dfd.promise(); }, /** * Show appropriate message regarding changes affected after enabling/disabling Kerberos * * @param {String[]} messages - list of the messages to display * @param {$.Deferred} dfd - used to break recursive calls and reject/resolve promise returned by checkServiceWarnings */ displayServiceWarnings: function(messages, dfd) { var self = this; if (!messages.get('length')) { dfd.resolve(); } else { App.showConfirmationPopup(function() { self.displayServiceWarnings(messages.slice(1), dfd); }, messages[0], function() { dfd.reject(); }, Em.I18n.t('common.warning'), Em.I18n.t('common.proceedAnyway')); } }, showManageKDCCredentialsPopup: function() { return App.showManageCredentialsPopup(); } });