You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2014/05/12 13:51:09 UTC

git commit: AMBARI-5731 UI unit tests for Add Security step 3. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk 7ee8d998a -> bab427fc4


AMBARI-5731 UI unit tests for Add Security step 3. (atkach)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/bab427fc
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/bab427fc
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/bab427fc

Branch: refs/heads/trunk
Commit: bab427fc4b0493b55fd5d6416210e5b8062fcb8c
Parents: 7ee8d99
Author: atkach <at...@hortonworks.com>
Authored: Mon May 12 14:48:58 2014 +0300
Committer: atkach <at...@hortonworks.com>
Committed: Mon May 12 14:48:58 2014 +0300

----------------------------------------------------------------------
 .../main/admin/security/add/step3.js            | 465 ++++++++++------
 .../templates/main/admin/security/add/step3.hbs |   8 +-
 .../main/admin/security/add/step3_test.js       | 526 ++++++++++++++++++-
 3 files changed, 812 insertions(+), 187 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bab427fc/ambari-web/app/controllers/main/admin/security/add/step3.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/security/add/step3.js b/ambari-web/app/controllers/main/admin/security/add/step3.js
index 7c8c7fb..1966e60 100644
--- a/ambari-web/app/controllers/main/admin/security/add/step3.js
+++ b/ambari-web/app/controllers/main/admin/security/add/step3.js
@@ -22,6 +22,127 @@ var stringUtils = require('utils/string_utils');
 App.MainAdminSecurityAddStep3Controller = Em.Controller.extend({
   name: 'mainAdminSecurityAddStep3Controller',
   hostComponents: [],
+
+  componentToUserMap: {
+    'NAMENODE': 'hdfs_user',
+    'SECONDARY_NAMENODE': 'hdfs_user',
+    'DATANODE': 'hdfs_user',
+    'JOURNALNODE': 'hdfs_user',
+    'TASKTRACKER': 'mapred_user',
+    'JOBTRACKER': 'mapred_user',
+    'HISTORYSERVER': 'mapred_user',
+    'RESOURCEMANAGER': 'yarn_user',
+    'NODEMANAGER': 'yarn_user',
+    'ZOOKEEPER_SERVER': 'zk_user',
+    'HIVE_SERVER': 'hive_user',
+    'OOZIE_SERVER': 'oozie_user',
+    'NAGIOS_SERVER': 'nagios_user',
+    'HBASE_MASTER': 'hbase_user',
+    'HBASE_REGIONSERVER': 'hbase_user',
+    'SUPERVISOR': 'storm_user',
+    'NIMBUS': 'storm_user',
+    'STORM_UI_SERVER': 'storm_user',
+    'FALCON_SERVER': 'falcon_user'
+  },
+
+  componentToConfigMap: [
+    {
+      componentName: 'NAMENODE',
+      principal: 'hadoop_http_principal_name',
+      keytab: 'hadoop_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.hdfs.user.httpUser')
+    },
+    {
+      componentName: 'SECONDARY_NAMENODE',
+      principal: 'hadoop_http_principal_name',
+      keytab: 'hadoop_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.hdfs.user.httpUser')
+    },
+    {
+      componentName: 'JOURNALNODE',
+      principal: 'hadoop_http_principal_name',
+      keytab: 'hadoop_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.hdfs.user.httpUser')
+    },
+    {
+      componentName: 'WEBHCAT_SERVER',
+      principal: 'webHCat_http_principal_name',
+      keytab: 'webhcat_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.webhcat.user.httpUser')
+    },
+    {
+      componentName: 'OOZIE_SERVER',
+      principal: 'oozie_http_principal_name',
+      keytab: 'oozie_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.oozie.user.httpUser')
+    },
+    {
+      componentName: 'FALCON_SERVER',
+      principal: 'falcon_http_principal_name',
+      keytab: 'falcon_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.falcon.user.httpUser')
+    },
+    {
+      componentName: 'HISTORYSERVER',
+      principal: 'jobhistory_http_principal_name',
+      keytab: 'jobhistory_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.historyServer.user.httpUser'),
+      isHadoop2Stack: true
+    },
+    {
+      componentName: 'RESOURCEMANAGER',
+      principal: 'resourcemanager_http_principal_name',
+      keytab: 'resourcemanager_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.rm.user.httpUser'),
+      isHadoop2Stack: true
+    },
+    {
+      componentName: 'NODEMANAGER',
+      principal: 'nodemanager_http_principal_name',
+      keytab: 'nodemanager_http_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.nm.user.httpUser'),
+      isHadoop2Stack: true
+    }
+  ],
+
+  mandatoryConfigs: [
+    {
+      userConfig: 'smokeuser',
+      keytab: 'smokeuser_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.user.smokeUser')
+    },
+    {
+      userConfig: 'hdfs_user',
+      keytab: 'hdfs_user_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.user.hdfsUser')
+    },
+    {
+      userConfig: 'hbase_user',
+      keytab: 'hbase_user_keytab',
+      displayName: Em.I18n.t('admin.addSecurity.user.hbaseUser'),
+      checkService: 'HBASE'
+    }
+  ],
+  /**
+   * mock users that used in testMode
+   */
+  testModeUsers: [
+    { name: 'hdfs_user', value: 'hdfs'},
+    { name: 'mapred_user', value: 'mapred'},
+    { name: 'yarn_user', value: 'yarn'},
+    { name: 'hbase_user', value: 'hbase'},
+    { name: 'hive_user', value: 'hive'},
+    { name: 'falcon_user', value: 'falcon'},
+    { name: 'smokeuser', value: 'ambari-qa'},
+    { name: 'zk_user', value: 'zookeeper'},
+    { name: 'oozie_user', value: 'oozie'},
+    { name: 'nagios_user', value: 'nagios'},
+    { name: 'user_group', value: 'hadoop'}
+  ],
+
+  /**
+   * download CSV file
+   */
   doDownloadCsv: function () {
     if ($.browser.msie && $.browser.version < 10) {
       this.openInfoInNewTab();
@@ -29,211 +150,215 @@ App.MainAdminSecurityAddStep3Controller = Em.Controller.extend({
       try {
         var blob = new Blob([stringUtils.arrayToCSV(this.get('hostComponents'))], {type: "text/csv;charset=utf-8;"});
         saveAs(blob, "host-principal-keytab-list.csv");
-      } catch(e) {
-         this.openInfoInNewTab();
+      } catch (e) {
+        this.openInfoInNewTab();
       }
     }
   },
+
+  /**
+   * open content of CSV file in new window
+   */
   openInfoInNewTab: function () {
     var newWindow = window.open('');
     var newDocument = newWindow.document;
     newDocument.write(stringUtils.arrayToCSV(this.get('hostComponents')));
     newWindow.focus();
   },
-  loadStep: function(){
-    var configs = this.get('content.serviceConfigProperties');
+
+  /**
+   * load step info
+   */
+  loadStep: function () {
     var hosts = App.Host.find();
     var result = [];
-    var componentsToDisplay = ['NAMENODE', 'SECONDARY_NAMENODE', 'DATANODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER', 'TASKTRACKER',
-      'OOZIE_SERVER', 'NAGIOS_SERVER', 'HBASE_MASTER', 'HBASE_REGIONSERVER','HISTORYSERVER','RESOURCEMANAGER','NODEMANAGER','JOURNALNODE',
-      'SUPERVISOR', 'NIMBUS', 'STORM_UI_SERVER','FALCON_SERVER'];
-    var securityUsers = [];
-    if (!securityUsers || securityUsers.length < 1) { // Page could be refreshed in middle
-      securityUsers = this.getSecurityUsers();
-    }
-    var isHbaseInstalled = App.Service.find().findProperty('serviceName', 'HBASE');
-    var isStormInstalled = App.Service.find().findProperty('serviceName', 'STORM');
-    var generalConfigs = configs.filterProperty('serviceName', 'GENERAL');
-    var hdfsConfigs = configs.filterProperty('serviceName', 'HDFS');
-    var realm = generalConfigs.findProperty('name', 'kerberos_domain').value;
-    var smokeUserId = securityUsers.findProperty('name', 'smokeuser').value;
-    var hdfsUserId = securityUsers.findProperty('name', 'hdfs_user').value;
-    var hbaseUserId = securityUsers.findProperty('name', 'hbase_user').value;
-    var mapredUserId = securityUsers.findProperty('name', 'mapred_user').value;
-    var yarnUserId =  securityUsers.findProperty('name', 'yarn_user').value;
-    var hiveUserId = securityUsers.findProperty('name', 'hive_user').value;
-    var zkUserId = securityUsers.findProperty('name', 'zk_user').value;
-    var oozieUserId = securityUsers.findProperty('name', 'oozie_user').value;
-    var nagiosUserId = securityUsers.findProperty('name', 'nagios_user').value;
+    var securityUsers = this.getSecurityUsers();
     var hadoopGroupId = securityUsers.findProperty('name', 'user_group').value;
-    var stormUserId = securityUsers.findProperty('name', 'storm_user').value;
-    var falconUserId =  securityUsers.findProperty('name', 'falcon_user').value;
-
-    var smokeUser = smokeUserId + '@' + realm;
-    var hdfsUser = hdfsUserId + '@' + realm;
-    var hbaseUser = hbaseUserId + '@' + realm;
-    var stormUser = stormUserId + '@' + realm;
-
-    var smokeUserKeytabPath = generalConfigs.findProperty('name', 'smokeuser_keytab').value;
-    var hdfsUserKeytabPath = generalConfigs.findProperty('name', 'hdfs_user_keytab').value;
-    var hbaseUserKeytabPath = generalConfigs.findProperty('name', 'hbase_user_keytab').value;
-
-    var hadoopHttpPrincipal = hdfsConfigs.findProperty('name', 'hadoop_http_principal_name');
-    var hadoopHttpKeytabPath = hdfsConfigs.findProperty('name', 'hadoop_http_keytab').value;
-    var componentToOwnerMap = {
-      'NAMENODE': hdfsUserId,
-      'SECONDARY_NAMENODE': hdfsUserId,
-      'DATANODE': hdfsUserId,
-      'JOURNALNODE': hdfsUserId,
-      'TASKTRACKER': mapredUserId,
-      'JOBTRACKER': mapredUserId,
-      'HISTORYSERVER': mapredUserId,
-      'RESOURCEMANAGER':yarnUserId,
-      'NODEMANAGER':yarnUserId,
-      'ZOOKEEPER_SERVER': zkUserId,
-      'HIVE_SERVER': hiveUserId,
-      'OOZIE_SERVER': oozieUserId,
-      'NAGIOS_SERVER': nagiosUserId,
-      'HBASE_MASTER': hbaseUserId,
-      'HBASE_REGIONSERVER': hbaseUserId,
-      'SUPERVISOR': stormUserId,
-      'NIMBUS': stormUserId,
-      'STORM_UI_SERVER': stormUserId,
-      'FALCON_SERVER': falconUserId
-    };
-
     var addedPrincipalsHost = {}; //Keys = host_principal, Value = 'true'
 
     hosts.forEach(function (host) {
-      result.push({
-        host: host.get('hostName'),
-        component: Em.I18n.t('admin.addSecurity.user.smokeUser'),
-        principal: smokeUser,
-        keytabFile: stringUtils.getFileFromPath(smokeUserKeytabPath),
-        keytab: stringUtils.getPath(smokeUserKeytabPath),
-        owner: smokeUserId,
-        group: hadoopGroupId,
-        acl: '440'
-      });
-      result.push({
-        host: host.get('hostName'),
-        component: Em.I18n.t('admin.addSecurity.user.hdfsUser'),
-        principal: hdfsUser,
-        keytabFile: stringUtils.getFileFromPath(hdfsUserKeytabPath),
-        keytab: stringUtils.getPath(hdfsUserKeytabPath),
-        owner: hdfsUserId,
-        group: hadoopGroupId,
-        acl: '440'
-      });
-      if (isHbaseInstalled) {
+      this.setMandatoryConfigs(result, securityUsers, host.get('hostName'), hadoopGroupId);
+      this.setComponentsConfig(result, host, hadoopGroupId);
+      this.setHostComponentsSecureValue(result, host, addedPrincipalsHost, securityUsers, hadoopGroupId);
+    }, this);
+    this.set('hostComponents', result);
+  },
+
+  /**
+   * build map of connections between component and user
+   * @param securityUsers
+   */
+  buildComponentToOwnerMap: function (securityUsers) {
+    var componentToUserMap = this.get('componentToUserMap');
+    var componentToOwnerMap = {};
+    for (var component in componentToUserMap) {
+      componentToOwnerMap[component] = securityUsers.findProperty('name', componentToUserMap[component]).value;
+    }
+    return componentToOwnerMap;
+  },
+
+  /**
+   * set security settings(principal and keytab) to component depending on whether host has such component
+   * @param result
+   * @param host
+   * @param hadoopGroupId
+   */
+  setComponentsConfig: function (result, host, hadoopGroupId) {
+    var hostComponents = host.get('hostComponents');
+    this.get('componentToConfigMap').forEach(function (component) {
+      //add specific components that supported only in Hadoop2 stack
+      if (component.isHadoop2Stack && !App.get('isHadoop2Stack')) return;
+
+      if (hostComponents.someProperty('componentName', component.componentName)) {
+        var configs = this.get('content.serviceConfigProperties');
+        var serviceName = App.QuickDataMapper.componentServiceMap()[component.componentName];
+        var serviceConfigs = configs.filterProperty('serviceName', serviceName);
+        var servicePrincipal = serviceConfigs.findProperty('name', component.principal);
+        var serviceKeytabPath = serviceConfigs.findProperty('name', component.keytab).value;
         result.push({
           host: host.get('hostName'),
-          component: Em.I18n.t('admin.addSecurity.user.hbaseUser'),
-          principal: hbaseUser,
-          keytabFile: stringUtils.getFileFromPath(hbaseUserKeytabPath),
-          keytab: stringUtils.getPath(hbaseUserKeytabPath),
-          owner: hbaseUserId,
+          component: component.displayName,
+          principal: this.getPrincipal(servicePrincipal, host.get('hostName')),
+          keytabfile: stringUtils.getFileFromPath(serviceKeytabPath),
+          keytab: stringUtils.getPath(serviceKeytabPath),
+          owner: 'root',
           group: hadoopGroupId,
           acl: '440'
         });
       }
+    }, this);
+  },
 
-      this.setComponentConfig(result,host,'NAMENODE','HDFS','hadoop_http_principal_name','hadoop_http_keytab',Em.I18n.t('admin.addSecurity.hdfs.user.httpUser'),hadoopGroupId);
-      this.setComponentConfig(result,host,'SECONDARY_NAMENODE','HDFS','hadoop_http_principal_name','hadoop_http_keytab',Em.I18n.t('admin.addSecurity.hdfs.user.httpUser'),hadoopGroupId);
-      this.setComponentConfig(result,host,'JOURNALNODE','HDFS','hadoop_http_principal_name','hadoop_http_keytab',Em.I18n.t('admin.addSecurity.hdfs.user.httpUser'),hadoopGroupId);
-      this.setComponentConfig(result,host,'WEBHCAT_SERVER','WEBHCAT','webHCat_http_principal_name','webhcat_http_keytab',Em.I18n.t('admin.addSecurity.webhcat.user.httpUser'),hadoopGroupId);
-      this.setComponentConfig(result,host,'OOZIE_SERVER','OOZIE','oozie_http_principal_name','oozie_http_keytab',Em.I18n.t('admin.addSecurity.oozie.user.httpUser'),hadoopGroupId);
-      this.setComponentConfig(result,host,'FALCON_SERVER','FALCON','falcon_http_principal_name','falcon_http_keytab',Em.I18n.t('admin.addSecurity.falcon.user.httpUser'),hadoopGroupId);
-      //Derive Principal name and Keytabs only if its HDP-2 stack
-      if (App.get('isHadoop2Stack')) {
-        this.setComponentConfig(result,host,'HISTORYSERVER','MAPREDUCE2','jobhistory_http_principal_name','jobhistory_http_keytab',Em.I18n.t('admin.addSecurity.historyServer.user.httpUser'),hadoopGroupId);
-        this.setComponentConfig(result,host,'RESOURCEMANAGER','YARN','resourcemanager_http_principal_name','resourcemanager_http_keytab',Em.I18n.t('admin.addSecurity.rm.user.httpUser'),hadoopGroupId);
-        this.setComponentConfig(result,host,'NODEMANAGER','YARN','nodemanager_http_principal_name','nodemanager_http_keytab',Em.I18n.t('admin.addSecurity.nm.user.httpUser'),hadoopGroupId);
-      }
+  /**
+   * set security settings(principal and keytab) to component
+   * if checkService is passed then verify that service to his existence in order to set configs to such service
+   * @param result
+   * @param securityUsers
+   * @param hostName
+   * @param hadoopGroupId
+   */
+  setMandatoryConfigs: function (result, securityUsers, hostName, hadoopGroupId) {
+    var generalConfigs = this.get('content.serviceConfigProperties').filterProperty('serviceName', 'GENERAL');
+    var realm = generalConfigs.findProperty('name', 'kerberos_domain').value;
+    var installedServices = App.Service.find().mapProperty('serviceName');
+
+    this.get('mandatoryConfigs').forEach(function (config) {
+      if (config.checkService && !installedServices.contains(config.checkService)) return;
+
+      var userId = securityUsers.findProperty('name', config.userConfig).value;
+      var userKeytabPath = generalConfigs.findProperty('name', config.keytab).value;
+      result.push({
+        host: hostName,
+        component: config.displayName,
+        principal: userId + '@' + realm,
+        keytabFile: stringUtils.getFileFromPath(userKeytabPath),
+        keytab: stringUtils.getPath(userKeytabPath),
+        owner: userId,
+        group: hadoopGroupId,
+        acl: '440'
+      });
+    }, this);
+  },
+
+  /**
+   * set secure properties(keytab and principal) for components, which should be displayed
+   * @param result
+   * @param host
+   * @param addedPrincipalsHost
+   * @param securityUsers
+   * @param hadoopGroupId
+   */
+  setHostComponentsSecureValue: function (result, host, addedPrincipalsHost, securityUsers, hadoopGroupId) {
+    var componentsToDisplay = ['NAMENODE', 'SECONDARY_NAMENODE', 'DATANODE', 'JOBTRACKER', 'ZOOKEEPER_SERVER', 'HIVE_SERVER', 'TASKTRACKER',
+      'OOZIE_SERVER', 'NAGIOS_SERVER', 'HBASE_MASTER', 'HBASE_REGIONSERVER', 'HISTORYSERVER', 'RESOURCEMANAGER', 'NODEMANAGER', 'JOURNALNODE',
+      'SUPERVISOR', 'NIMBUS', 'STORM_UI_SERVER', 'FALCON_SERVER'];
+    var configs = this.get('content.serviceConfigProperties');
+    var componentToOwnerMap = this.buildComponentToOwnerMap(securityUsers);
+    var hostName = host.get('hostName');
+
+    host.get('hostComponents').forEach(function (hostComponent) {
+      if (componentsToDisplay.contains(hostComponent.get('componentName'))) {
+        var serviceConfigs = configs.filterProperty('serviceName', hostComponent.get('service.serviceName'));
+        var secureProperties = this.getSecureProperties(serviceConfigs, hostComponent.get('componentName'), hostName);
+        var displayName = this.changeDisplayName(hostComponent.get('displayName'));
+        var key = hostName + "--" + secureProperties.principal;
 
-      host.get('hostComponents').forEach(function(hostComponent){
-        if(componentsToDisplay.contains(hostComponent.get('componentName'))){
-          var serviceConfigs = configs.filterProperty('serviceName', hostComponent.get('service.serviceName'));
-          var principal, keytab;
-          serviceConfigs.forEach(function (config) {
-            if (config.component && config.component === hostComponent.get('componentName')) {
-              if (config.name.endsWith('_principal_name')) {
-                principal = config.value.replace('_HOST', host.get('hostName').toLowerCase()) + config.unit;
-              } else if (config.name.endsWith('_keytab') || config.name.endsWith('_keytab_path')) {
-                keytab = config.value;
-              }
-            } else if (config.components && config.components.contains(hostComponent.get('componentName'))) {
-              if (config.name.endsWith('_principal_name')) {
-                principal = config.value.replace('_HOST', host.get('hostName').toLowerCase()) + config.unit;
-              } else if (config.name.endsWith('_keytab') || config.name.endsWith('_keytab_path')) {
-                keytab = config.value;
-              }
-            }
+        if (Em.isNone(addedPrincipalsHost[key])) {
+          var owner = componentToOwnerMap[hostComponent.get('componentName')] || '';
+
+          result.push({
+            host: hostName,
+            component: displayName,
+            principal: secureProperties.principal,
+            keytabFile: stringUtils.getFileFromPath(secureProperties.keytab),
+            keytab: stringUtils.getPath(secureProperties.keytab),
+            owner: owner,
+            group: hadoopGroupId,
+            acl: '400'
           });
-          var displayName = this.changeDisplayName(hostComponent.get('displayName'));
-          var key = host.get('hostName') + "--" + principal;
-          if (!addedPrincipalsHost[key]) {
-            var owner = componentToOwnerMap[hostComponent.get('componentName')];
-            if(!owner){
-              owner = '';
-            }
-            result.push({
-              host: host.get('hostName'),
-              component: displayName,
-              principal: principal,
-              keytabFile: stringUtils.getFileFromPath(keytab),
-              keytab: stringUtils.getPath(keytab),
-              owner: owner,
-              group: hadoopGroupId,
-              acl: '400'
-            });
-            addedPrincipalsHost[key] = true;
-          }
+          addedPrincipalsHost[key] = true;
         }
-      },this);
-    },this);
-    this.set('hostComponents', result);
+      }
+    }, this);
+  },
+
+  /**
+   * get properties (keytab and principle) of secure config that match component
+   * @param serviceConfigs
+   * @param componentName
+   * @param hostName
+   * @return {Object}
+   */
+  getSecureProperties: function (serviceConfigs, componentName, hostName) {
+    var secureProperties = {};
+    serviceConfigs.forEach(function (config) {
+      if ((config.component && config.component === componentName) ||
+        (config.components && config.components.contains(componentName))) {
+        if (config.name.endsWith('_principal_name')) {
+          secureProperties.principal = this.getPrincipal(config, hostName);
+        } else if (config.name.endsWith('_keytab') || config.name.endsWith('_keytab_path')) {
+          secureProperties.keytab = config.value;
+        }
+      }
+    }, this);
+    return secureProperties;
   },
 
-  getSecurityUsers: function() {
+  /**
+   * get formatted principal value
+   * @param config
+   * @param hostName
+   * @return {String}
+   */
+  getPrincipal: function (config, hostName) {
+    return config.value.replace('_HOST', hostName.toLowerCase()) + config.unit;
+  },
+
+  /**
+   * get users from security configs
+   * @return {Array}
+   */
+  getSecurityUsers: function () {
     var securityUsers = [];
     if (App.testMode) {
-      securityUsers.pushObject({id: 'puppet var', name: 'hdfs_user', value: 'hdfs'});
-      securityUsers.pushObject({id: 'puppet var', name: 'mapred_user', value: 'mapred'});
-      securityUsers.pushObject({id: 'puppet var', name: 'yarn_user', value: 'yarn'});
-      securityUsers.pushObject({id: 'puppet var', name: 'hbase_user', value: 'hbase'});
-      securityUsers.pushObject({id: 'puppet var', name: 'hive_user', value: 'hive'});
-      securityUsers.pushObject({id: 'puppet var', name: 'falcon_user', value: 'falcon'});
-      securityUsers.pushObject({id: 'puppet var', name: 'smokeuser', value: 'ambari-qa'});
-      securityUsers.pushObject({id: 'puppet var', name: 'zk_user', value: 'zookeeper'});
-      securityUsers.pushObject({id: 'puppet var', name: 'oozie_user', value: 'oozie'});
-      securityUsers.pushObject({id: 'puppet var', name: 'nagios_user', value: 'nagios'});
-      securityUsers.pushObject({id: 'puppet var', name: 'user_group', value: 'hadoop'});
+      this.get('testModeUsers').forEach(function (user) {
+        securityUsers.push({
+          id: 'puppet var',
+          name: user.name,
+          value: user.value
+        });
+      });
     } else {
       securityUsers = App.db.getSecureUserInfo();
     }
     return securityUsers;
   },
 
-  setComponentConfig: function(hostComponents,host,componentName,serviceName,principal,keytab,displayName,groupId) {
-    if (host.get('hostComponents').someProperty('componentName', componentName)) {
-      var result = {};
-      var configs = this.get('content.serviceConfigProperties');
-      var serviceConfigs = configs.filterProperty('serviceName', serviceName);
-      var servicePrincipal = serviceConfigs.findProperty('name', principal);
-      var serviceKeytabPath = serviceConfigs.findProperty('name', keytab).value;
-      result.host = host.get('hostName');
-      result.component = displayName;
-      result.principal = servicePrincipal.value.replace('_HOST', host.get('hostName').toLowerCase()) + servicePrincipal.unit;
-      result.keytabfile = stringUtils.getFileFromPath(serviceKeytabPath);
-      result.keytab = stringUtils.getPath(serviceKeytabPath);
-      result.owner = 'root';
-      result.group = groupId;
-      result.acl = '440';
-      hostComponents.push(result);
-    }
-  },
-
+  /**
+   * format  display names of specific components
+   * @param name
+   * @return {*}
+   */
   changeDisplayName: function (name) {
     if (name === 'HiveServer2') {
       return 'Hive Metastore and HiveServer2';

http://git-wip-us.apache.org/repos/asf/ambari/blob/bab427fc/ambari-web/app/templates/main/admin/security/add/step3.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/security/add/step3.hbs b/ambari-web/app/templates/main/admin/security/add/step3.hbs
index 04ecc3e..fd3e4d0 100644
--- a/ambari-web/app/templates/main/admin/security/add/step3.hbs
+++ b/ambari-web/app/templates/main/admin/security/add/step3.hbs
@@ -26,7 +26,7 @@
             <th>{{t common.component}}</th>
             <th>{{t admin.security.step3.table.principal}}</th>
             <th>{{t admin.security.step3.table.keytab}}</th>
-            </tr>
+        </tr>
         </thead>
         <tbody>
         {{#each hostComponent in hostComponents}}
@@ -37,13 +37,13 @@
                 <td>{{hostComponent.keytab}}</td>
             </tr>
         {{/each}}
-    </tbody>
+        </tbody>
     </table>
 </div>
 <div class="btn-area">
     <a class="btn" {{action back}}>&larr; {{t common.back}}</a>
     <div class="pull-right">
-        <a class="btn btn-info" {{action doDownloadCsv target="controller"}}>{{t admin.security.step3.downloadCSV}}</a>
-        <a class="btn btn-success" {{bindAttr disabled="isSubmitDisabled"}} {{action next}}>{{t common.apply}} &rarr;</a>
+        <button class="btn btn-info" {{action doDownloadCsv target="controller"}}>{{t admin.security.step3.downloadCSV}}</button>
+        <button class="btn btn-success" {{bindAttr disabled="isSubmitDisabled"}} {{action next}}>{{t common.apply}} &rarr;</button>
     </div>
 </div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bab427fc/ambari-web/test/controllers/main/admin/security/add/step3_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/admin/security/add/step3_test.js b/ambari-web/test/controllers/main/admin/security/add/step3_test.js
index faa848b..839bdf4 100644
--- a/ambari-web/test/controllers/main/admin/security/add/step3_test.js
+++ b/ambari-web/test/controllers/main/admin/security/add/step3_test.js
@@ -20,28 +20,528 @@
 var App = require('app');
 
 require('controllers/main/admin/security/add/step3');
-require('models/host_component');
-require('models/host');
-require('models/service');
+var stringUtils = require('utils/string_utils');
 
 describe('App.MainAdminSecurityAddStep3Controller', function () {
 
-  var mainAdminSecurityAddStep3Controller = App.MainAdminSecurityAddStep3Controller.create();
+  var controller = App.MainAdminSecurityAddStep3Controller.create({
+    content: {}
+  });
 
-  describe('#getSecurityUsers', function() {
-    it('no hosts, just check users (testMode = true)', function() {
-      App.testMode = true;
-      expect(mainAdminSecurityAddStep3Controller.getSecurityUsers().length).to.equal(11);
+  describe('#openInfoInNewTab()', function() {
+    it('Correct data', function() {
+      var mock = {
+        document: {
+          write: function(){}
+        },
+        focus: function(){}
+      };
+      sinon.stub(window, 'open', function () {
+        return mock;
+      });
+      sinon.stub(stringUtils, 'arrayToCSV', function () {
+        return 'CSV_CONTENT';
+      });
+      sinon.spy(mock.document, 'write');
+      sinon.spy(mock, 'focus');
+      controller.set('hostComponents', ['comp1']);
+
+      controller.openInfoInNewTab();
+      expect(window.open.calledWith('')).to.be.true;
+      expect(stringUtils.arrayToCSV.calledWith(['comp1'])).to.be.true;
+      expect(mock.document.write.calledWith('CSV_CONTENT')).to.be.true;
+      expect(mock.focus.calledOnce).to.be.true;
+      window.open.restore();
+      stringUtils.arrayToCSV.restore();
+    });
+  });
+
+  describe('#loadStep()', function() {
+
+    beforeEach(function(){
+      sinon.stub(controller, 'getSecurityUsers', function () {
+        return [{
+          name: 'user_group',
+          value: 'value1'
+        }];
+      });
+    });
+    afterEach(function(){
+      App.Host.find.restore();
+      controller.getSecurityUsers.restore();
+    });
+
+    it('No hosts installed', function() {
+      sinon.stub(App.Host, 'find', function(){
+        return [];
+      });
+      controller.loadStep();
+      expect(controller.get('hostComponents')).to.be.empty;
+    });
+    it('One host installed', function () {
+      sinon.stub(App.Host, 'find', function () {
+        return [Em.Object.create({hostName: 'host1'})];
+      });
+      sinon.stub(controller, 'setMandatoryConfigs', function (result) {
+        return result.push('setMandatoryConfigs');
+      });
+      sinon.stub(controller, 'setComponentsConfig', function (result) {
+        return result.push('setComponentsConfig');
+      });
+      sinon.stub(controller, 'setHostComponentsSecureValue', function (result) {
+        return result.push('setHostComponentsSecureValue');
+      });
+
+      controller.loadStep();
+      expect(controller.setMandatoryConfigs.calledOnce).to.be.true;
+      expect(controller.setComponentsConfig.calledOnce).to.be.true;
+      expect(controller.setHostComponentsSecureValue.calledOnce).to.be.true;
+      expect(controller.get('hostComponents')).to.eql(["setMandatoryConfigs", "setComponentsConfig", "setHostComponentsSecureValue"]);
+
+      controller.setMandatoryConfigs.restore();
+      controller.setComponentsConfig.restore();
+      controller.setHostComponentsSecureValue.restore();
+    });
+  });
+
+  describe('#buildComponentToOwnerMap()', function() {
+    it('componentToUserMap is empty', function() {
+      controller.set('componentToUserMap', {});
+      expect(controller.buildComponentToOwnerMap([])).to.eql({});
+    });
+    it('componentToUserMap has properties', function() {
+      controller.set('componentToUserMap', {'COMP1': 'config1'});
+      var securityUsers = [{
+        name: 'config1',
+        value: 'value1'
+      }];
+      expect(controller.buildComponentToOwnerMap(securityUsers)).to.eql({'COMP1': 'value1'});
+    });
+  });
+
+  describe('#setComponentsConfig()', function() {
+
+    beforeEach(function(){
+      controller.set('content.serviceConfigProperties', [
+        {
+          serviceName: 'HDFS',
+          name: 'principal1',
+          value: '_HOST'
+        },
+        {
+          serviceName: 'HDFS',
+          name: 'keytab1',
+          value: 'value1'
+        }
+      ]);
+    });
+
+    it('componentToConfigMap is empty', function() {
+      controller.set('componentToConfigMap', []);
+      var result = [];
+      controller.setComponentsConfig(result, Em.Object.create(), 'hadoopGroupId');
+      expect(result).to.be.empty;
+    });
+    it('isHadoop2Stack = false, when component from stack2', function() {
+      sinon.stub(App, 'get', function () {
+        return false;
+      });
+      controller.set('componentToConfigMap', [{
+        componentName: 'DATANODE',
+        principal: 'principal1',
+        keytab: 'keytab1',
+        displayName: 'displayName1',
+        isHadoop2Stack: true
+      }]);
+      var host = Em.Object.create({
+        hostComponents: [{componentName: 'DATANODE'}],
+        hostName: 'host1'
+      });
+      var result = [];
+      controller.setComponentsConfig(result, host, 'hadoopGroupId');
+      expect(result).to.be.empty;
+      App.get.restore();
+    });
+    it('isHadoop2Stack = true, when component from stack2', function() {
+      sinon.stub(App, 'get', function () {
+        return true;
+      });
+      controller.set('componentToConfigMap', [{
+        componentName: 'DATANODE',
+        principal: 'principal1',
+        keytab: 'keytab1',
+        displayName: 'displayName1',
+        isHadoop2Stack: true
+      }]);
+      var host = Em.Object.create({
+        hostComponents: [{componentName: 'DATANODE'}],
+        hostName: 'host1'
+      });
+      var result = [];
+      controller.setComponentsConfig(result, host, 'hadoopGroupId');
+      expect(result.length).to.equal(1);
+      App.get.restore();
+    });
+    it('Component does not match host-component', function() {
+      controller.set('componentToConfigMap', [{
+        componentName: 'DATANODE',
+        principal: 'principal1',
+        keytab: 'keytab1',
+        displayName: 'displayName1'
+      }]);
+      var host = Em.Object.create({
+        hostComponents: [{componentName: 'DATANODE1'}],
+        hostName: 'host1'
+      });
+      var result = [];
+      controller.setComponentsConfig(result, host, 'hadoopGroupId');
+      expect(result).to.be.empty;
+    });
+    it('Component matches host-component', function() {
+      controller.set('componentToConfigMap', [{
+        componentName: 'DATANODE',
+        principal: 'principal1',
+        keytab: 'keytab1',
+        displayName: 'displayName1'
+      }]);
+      var host = Em.Object.create({
+        hostComponents: [{componentName: 'DATANODE'}],
+        hostName: 'host1'
+      });
+      var result = [];
+      controller.setComponentsConfig(result, host, 'hadoopGroupId');
+      expect(result.length).to.equal(1);
+    });
+  });
+
+  describe('#setMandatoryConfigs()', function() {
+
+    beforeEach(function () {
+      sinon.stub(App.Service, 'find', function () {
+        return [
+          {serviceName: 'SERVICE1'}
+        ];
+      });
+      controller.set('content.serviceConfigProperties', [
+        {
+          serviceName: 'GENERAL',
+          name: 'kerberos_domain',
+          value: 'realm1'
+        }
+      ]);
+    });
+    afterEach(function () {
+      App.Service.find.restore();
+    });
+
+    it('mandatoryConfigs is empty', function() {
+      var result = [];
+      controller.set('mandatoryConfigs', []);
+
+      controller.setMandatoryConfigs(result, [], '', '');
+      expect(result).to.be.empty;
+    });
+    it('config has unknown service to check', function() {
+      var result = [];
+      controller.set('mandatoryConfigs', [{
+        userConfig: 'kerberos_domain',
+        keytab: 'kerberos_domain',
+        displayName: '',
+        checkService: 'HBASE'
+      }]);
+
+      controller.setMandatoryConfigs(result, [], '', '');
+      expect(result).to.be.empty;
+    });
+    it('config should be added', function() {
+      var result = [];
+      controller.set('mandatoryConfigs', [{
+        userConfig: 'userConfig1',
+        keytab: 'kerberos_domain',
+        displayName: ''
+      }]);
+      var securityUsers = [{
+        name: 'userConfig1',
+        value: 'value1'
+      }];
+
+      controller.setMandatoryConfigs(result, securityUsers, '', '');
+      expect(result.length).to.equal(1);
+    });
+  });
+
+  describe('#setHostComponentsSecureValue()', function() {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'buildComponentToOwnerMap', Em.K);
+      sinon.stub(controller, 'changeDisplayName', Em.K);
+      sinon.stub(controller, 'getSecureProperties', function(){
+        return {principal: '', keytab: ''};
+      });
+    });
+    afterEach(function () {
+      controller.buildComponentToOwnerMap.restore();
+      controller.changeDisplayName.restore();
+      controller.getSecureProperties.restore();
+    });
+
+    it('host.hostComponents is empty', function() {
+      var result = [];
+      var host = Em.Object.create({
+        hostComponents: []
+      });
+
+      controller.setHostComponentsSecureValue(result, host);
+      expect(result).to.be.empty;
+    });
+    it('host-component does not match component to display', function() {
+      var result = [];
+      var host = Em.Object.create({
+        hostComponents: [Em.Object.create({
+          componentName: 'UNKNOWN'
+        })]
+      });
+
+      controller.setHostComponentsSecureValue(result, host);
+      expect(result).to.be.empty;
+    });
+    it('host-component matches component to display', function() {
+      var result = [];
+      var host = Em.Object.create({
+        hostComponents: [Em.Object.create({
+          componentName: 'DATANODE'
+        })]
+      });
+
+      controller.setHostComponentsSecureValue(result, host, {}, [], '');
+      expect(result.length).to.equal(1);
+    });
+    it('addedPrincipalsHost already contain such config', function() {
+      var result = [];
+      var host = Em.Object.create({
+        hostName: 'host1',
+        hostComponents: [Em.Object.create({
+          componentName: 'DATANODE'
+        })]
+      });
+
+      controller.setHostComponentsSecureValue(result, host, {'host1--': true}, [], '');
+      expect(result.length).to.be.empty;
+    });
+  });
+
+  describe('#getSecureProperties()', function () {
+
+    beforeEach(function () {
+      sinon.stub(controller, 'getPrincipal', function () {
+        return 'principal';
+      });
+    });
+    afterEach(function () {
+      controller.getPrincipal.restore();
+    });
+
+    var testCases = [
+      {
+        title: 'serviceConfigs is empty',
+        content: {
+          serviceConfigs: [],
+          componentName: ''
+        },
+        result: {}
+      },
+      {
+        title: 'Config has component that does not match component name',
+        content: {
+          serviceConfigs: [{
+            component: 'comp1'
+          }],
+          componentName: 'comp2'
+        },
+        result: {}
+      },
+      {
+        title: 'Config has components that does not match component name',
+        content: {
+          serviceConfigs: [{
+            components: ['comp1']
+          }],
+          componentName: 'comp2'
+        },
+        result: {}
+      },
+      {
+        title: 'Config has component that matches component name',
+        content: {
+          serviceConfigs: [{
+            name: 'C_principal_name',
+            component: 'comp1',
+            value: 'value1'
+          }],
+          componentName: 'comp1'
+        },
+        result: {
+          principal: 'principal'
+        }
+      },
+      {
+        title: 'Config has components that matches component name',
+        content: {
+          serviceConfigs: [{
+            name: 'C_principal_name',
+            components: ['comp1'],
+            value: 'value1'
+          }],
+          componentName: 'comp1'
+        },
+        result: {
+          principal: 'principal'
+        }
+      },
+      {
+        title: 'Config name without correct postfix',
+        content: {
+          serviceConfigs: [{
+            name: 'config1',
+            component: 'comp1',
+            value: 'value1'
+          }],
+          componentName: 'comp1'
+        },
+        result: {}
+      },
+      {
+        title: 'Config name with "_keytab" postfix',
+        content: {
+          serviceConfigs: [{
+            name: 'c_keytab',
+            component: 'comp1',
+            value: 'value1'
+          }],
+          componentName: 'comp1'
+        },
+        result: {
+          keytab: 'value1'
+        }
+      },
+      {
+        title: 'Config name with "_keytab_path" postfix',
+        content: {
+          serviceConfigs: [{
+            name: 'c_keytab_path',
+            component: 'comp1',
+            value: 'value1'
+          }],
+          componentName: 'comp1'
+        },
+        result: {
+          keytab: 'value1'
+        }
+      }
+    ];
+
+    testCases.forEach(function (test) {
+      it(test.title, function () {
+        expect(controller.getSecureProperties(test.content.serviceConfigs, test.content.componentName, '')).to.eql(test.result);
+      });
+    });
+  });
+
+  describe('#getPrincipal()', function () {
+
+    var testCases = [
+      {
+        title: 'Config value missing "_HOST" string, unit is empty',
+        content: {
+          config: {
+            value: 'value1',
+            unit: ''
+          },
+          hostName: ''
+        },
+        result: 'value1'
+      },
+      {
+        title: 'Config value missing "_HOST" string, unit is correct',
+        content: {
+          config: {
+            value: 'value1',
+            unit: 'unit1'
+          },
+          hostName: ''
+        },
+        result: 'value1unit1'
+      },
+      {
+        title: 'Config value contains "_HOST" string, host name in lowercase',
+        content: {
+          config: {
+            value: '_HOST',
+            unit: 'unit1'
+          },
+          hostName: 'host1'
+        },
+        result: 'host1unit1'
+      },
+      {
+        title: 'Config value contains "_HOST" string, host name in uppercase',
+        content: {
+          config: {
+            value: '_HOST',
+            unit: 'unit1'
+          },
+          hostName: 'HOST1'
+        },
+        result: 'host1unit1'
+      }
+    ];
+
+    testCases.forEach(function (test) {
+      it(test.title, function () {
+        expect(controller.getPrincipal(test.content.config, test.content.hostName)).to.equal(test.result);
+      });
     });
   });
 
-  describe('#changeDisplayName', function() {
-    it('HiveServer2', function() {
-      expect(mainAdminSecurityAddStep3Controller.changeDisplayName('HiveServer2')).to.equal('Hive Metastore and HiveServer2');
+  describe('#changeDisplayName()', function() {
+    it('name is HiveServer2', function() {
+      expect(controller.changeDisplayName('HiveServer2')).to.equal('Hive Metastore and HiveServer2');
     });
-    it('Not HiveServer2', function() {
-      expect(mainAdminSecurityAddStep3Controller.changeDisplayName('something')).to.equal('something');
+    it('name is not HiveServer2', function() {
+      expect(controller.changeDisplayName('something')).to.equal('something');
     });
   });
 
+  describe('#getSecurityUsers()', function () {
+    it('testMode is true, testModeUsers is empty', function () {
+      controller.set('testModeUsers', []);
+      App.testMode = true;
+      expect(controller.getSecurityUsers()).to.eql([]);
+    });
+    it('testMode is true, testModeUsers is correct', function () {
+      controller.set('testModeUsers', [
+        {
+          name: 'user1',
+          value: 'value1'
+        }
+      ]);
+      App.testMode = true;
+      expect(controller.getSecurityUsers()).to.eql([
+        {
+          id: 'puppet var',
+          name: 'user1',
+          value: 'value1'
+        }
+      ]);
+    });
+    it('testMode is false', function () {
+      sinon.stub(App.db, 'getSecureUserInfo', function () {
+        return [{}];
+      });
+      App.testMode = false;
+      expect(controller.getSecurityUsers()).to.eql([{}]);
+      expect(App.db.getSecureUserInfo.calledOnce).to.be.true;
+      App.db.getSecureUserInfo.restore();
+    });
+  });
 });