You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2016/03/23 22:55:03 UTC

[1/2] ambari git commit: AMBARI-6432. FreeIPA Support in Ambari (Bolke de Bruin via rlevas)

Repository: ambari
Updated Branches:
  refs/heads/trunk 2d7dffce5 -> 476d87b70


http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_simple.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_simple.json b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_simple.json
index 292ad25..fb884b7 100644
--- a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_simple.json
+++ b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_simple.json
@@ -25,7 +25,7 @@
     {
       "name": "hdfs",
       "principal": {
-        "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}",
+        "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}",
         "type": "user",
         "configuration": "hadoop-env/hdfs_principal_name",
         "local_username": "${hadoop-env/hdfs_user}"
@@ -46,7 +46,7 @@
     {
       "name": "smokeuser",
       "principal": {
-        "value": "${cluster-env/smokeuser}-${cluster_name}@${realm}",
+        "value": "${cluster-env/smokeuser}-${cluster_name|toLower()}@${realm}",
         "type": "user",
         "configuration": "cluster-env/smokeuser_principal_name",
         "local_username": "${cluster-env/smokeuser}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json b/ambari-server/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
index c285234..d53205d 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
@@ -18,7 +18,7 @@
         {
           "name": "hdfs",
           "principal": {
-            "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}",
+            "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user" ,
             "configuration": "hadoop-env/hdfs_principal_name",
             "local_username" : "${hadoop-env/hdfs_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/config.js b/ambari-web/app/config.js
index 5d3b27a..b1f6bd5 100644
--- a/ambari-web/app/config.js
+++ b/ambari-web/app/config.js
@@ -80,6 +80,7 @@ App.supports = {
   serviceAutoStart: false,
   logSearch: false,
   redhatSatellite: false,
+  enableIpa: false,
   addingNewRepository: false
 };
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/controllers/main/admin/kerberos.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/kerberos.js b/ambari-web/app/controllers/main/admin/kerberos.js
index 9512a51..5472413 100644
--- a/ambari-web/app/controllers/main/admin/kerberos.js
+++ b/ambari-web/app/controllers/main/admin/kerberos.js
@@ -32,6 +32,7 @@ App.MainAdminKerberosController = App.KerberosWizardStep4Controller.extend({
   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')
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/controllers/main/admin/kerberos/step1_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/kerberos/step1_controller.js b/ambari-web/app/controllers/main/admin/kerberos/step1_controller.js
index b9056ed..1b96b13 100644
--- a/ambari-web/app/controllers/main/admin/kerberos/step1_controller.js
+++ b/ambari-web/app/controllers/main/admin/kerberos/step1_controller.js
@@ -25,7 +25,30 @@ App.KerberosWizardStep1Controller = Em.Controller.extend({
 
   isSubmitDisabled: Em.computed.someBy('selectedOption.preConditions', 'checked', false),
 
-  options: [
+  ipaOption: Em.Object.create({
+    displayName: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa'),
+    value: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa'),
+    preConditions: [
+      Em.Object.create({
+        displayText: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa.condition.1'),
+        checked: false
+      }),
+      Em.Object.create({
+        displayText: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa.condition.2'),
+        checked: false
+      }),
+      Em.Object.create({
+        displayText: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa.condition.3'),
+        checked: false
+      }),
+      Em.Object.create({
+        displayText: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa.condition.4'),
+        checked: false
+      }),
+    ]
+  }),
+
+  options: Em.A([
     Em.Object.create({
       displayName: Em.I18n.t('admin.kerberos.wizard.step1.option.kdc'),
       value: Em.I18n.t('admin.kerberos.wizard.step1.option.kdc'),
@@ -96,7 +119,7 @@ App.KerberosWizardStep1Controller = Em.Controller.extend({
         })
       ]
     })
-  ],
+  ]),
 
   /**
    * precondition for the selected KDC option
@@ -108,9 +131,15 @@ App.KerberosWizardStep1Controller = Em.Controller.extend({
   }.property('selectedItem'),
 
 
-
   loadStep: function () {
     this.set('selectedItem', Em.I18n.t('admin.kerberos.wizard.step1.option.kdc'));
+
+    if (App.get('supports.enableIpa')) {
+      var ipaOption = this.get('ipaOption');
+      var options = this.get('options');
+
+      options.pushObject(ipaOption);
+    }
   },
 
   next: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/controllers/main/admin/kerberos/step2_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/kerberos/step2_controller.js b/ambari-web/app/controllers/main/admin/kerberos/step2_controller.js
index 36fb227..7f77c38 100644
--- a/ambari-web/app/controllers/main/admin/kerberos/step2_controller.js
+++ b/ambari-web/app/controllers/main/admin/kerberos/step2_controller.js
@@ -99,13 +99,15 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend(App.KDCCred
   },
 
   /**
-   * Make Active Directory specific configs visible if user has selected AD option
+   * Make Active Directory or IPA specific configs visible if user has selected AD or IPA option
    * @param configs
    */
   filterConfigs: function (configs) {
     var kdcType = this.get('content.kerberosOption');
     var adConfigNames = ['ldap_url', 'container_dn', 'ad_create_attributes_template'];
     var mitConfigNames = ['kdc_create_attributes'];
+    var ipaConfigNames = ['group', 'set_password_expiry', 'password_chat_timeout'];
+
     var kerberosWizardController = this.controllers.get('kerberosWizardController');
     var manageIdentitiesConfig = configs.findProperty('name', 'manage_identities');
 
@@ -134,6 +136,13 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend(App.KDCCred
         config.isVisible = kdcType === Em.I18n.t('admin.kerberos.wizard.step1.option.kdc');
       }
     }, this);
+
+    ipaConfigNames.forEach(function (_configName) {
+      var config = configs.findProperty('name', _configName);
+      if (config) {
+        config.isVisible = kdcType === Em.I18n.t('admin.kerberos.wizard.step1.option.ipa');
+      }
+    }, this);
   },
 
   submit: function () {
@@ -215,6 +224,7 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend(App.KDCCred
     }, this);
     this.tweakKdcTypeValue(properties);
     this.tweakManualKdcProperties(properties);
+    this.tweakIpaKdcProperties(properties);
     return {"type": site, "tag": tag, "properties": properties};
   },
 
@@ -243,6 +253,20 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend(App.KDCCred
     }
   },
 
+  tweakIpaKdcProperties: function (properties) {
+    if (typeof properties['kdc_type'] === 'undefined') {
+      return;
+    }
+    if (this.get('content.kerberosOption') === App.router.get('mainAdminKerberosController.kdcTypesValues')['ipa']) {
+      if (properties.hasOwnProperty('install_packages')) {
+        properties['install_packages'] = 'false';
+      }
+      if (properties.hasOwnProperty('manage_krb5_conf')) {
+        properties['manage_krb5_conf'] = 'false';
+      }
+    }
+  },
+
   /**
    * puts kerberos admin credentials in the live cluster session
    * @returns {*} jqXHr

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/controllers/main/admin/kerberos/step5_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/kerberos/step5_controller.js b/ambari-web/app/controllers/main/admin/kerberos/step5_controller.js
index 5aa4b8c..38150c8 100644
--- a/ambari-web/app/controllers/main/admin/kerberos/step5_controller.js
+++ b/ambari-web/app/controllers/main/admin/kerberos/step5_controller.js
@@ -130,6 +130,10 @@ App.KerberosWizardStep5Controller = App.KerberosProgressPageController.extend({
             properties: ['kdc_type', 'kdc_host', 'realm', 'ldap_url', 'container_dn', 'executable_search_paths']
           },
           {
+            key: Em.I18n.t('admin.kerberos.wizard.step1.option.ipa'),
+            properties: ['kdc_type', 'kdc_host', 'realm', 'executable_search_paths']
+          },
+          {
             key: Em.I18n.t('admin.kerberos.wizard.step1.option.manual'),
             properties: ['kdc_type', 'realm', 'executable_search_paths']
           }

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/controllers/main/service/info/configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js
index 8c855fc..b8a716c 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -372,6 +372,12 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A
       } else if (kdc_type.get('value') === 'active-directory') {
         configs.findProperty('name', 'container_dn').set('isVisible', true);
         configs.findProperty('name', 'ldap_url').set('isVisible', true);
+      } else if (kdc_type.get('value') === 'ipa') {
+        configs.findProperty('name', 'group').set('isVisible', true);
+        configs.findProperty('name', 'manage_krb5_conf').set('value', false);
+        configs.findProperty('name', 'install_packages').set('value', false);
+        configs.findProperty('name', 'admin_server_host').set('isVisible', false);
+        configs.findProperty('name', 'domains').set('isVisible', false);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/data/HDP2/site_properties.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/data/HDP2/site_properties.js b/ambari-web/app/data/HDP2/site_properties.js
index 5ad24fc..4b2dfb7 100644
--- a/ambari-web/app/data/HDP2/site_properties.js
+++ b/ambari-web/app/data/HDP2/site_properties.js
@@ -1498,6 +1498,14 @@ var hdp2properties = [
     "index" : 14
   },
   {
+    "id": "puppet var",
+    "name": "group",
+    "serviceName": "KERBEROS",
+    "filename": "kerberos-env.xml",
+    "category": "Advanced kerberos-env",
+    "index": 15
+  },
+  {
     "name": "admin_server_host",
     "serviceName": "KERBEROS",
     "filename": "kerberos-env.xml",
@@ -1505,6 +1513,7 @@ var hdp2properties = [
     "index": 0
   },
   {
+    "id": "puppet var",
     "name": "manage_krb5_conf",
     "dependentConfigPattern": "CATEGORY",
     "serviceName": "KERBEROS",

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 636f826..4fa6ba5 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1122,6 +1122,11 @@ Em.I18n.translations = {
   'admin.kerberos.wizard.step1.option.ad.condition.3': 'Active Directory User container for principals has been created and is on-hand (e.g. OU=Hadoop,OU=People,dc=apache,dc=org)',
   'admin.kerberos.wizard.step1.option.ad.condition.4': 'Active Directory administrative credentials with delegated control of “Create, delete, and manage user accounts” on the previously mentioned User container are on-hand.',
   'admin.kerberos.wizard.step1.option.ad.condition.5': 'The Java Cryptography Extensions (JCE) have been setup on the Ambari Server host and all hosts in the cluster.',
+  'admin.kerberos.wizard.step1.option.ipa': 'Existing IPA',
+  'admin.kerberos.wizard.step1.option.ipa.condition.1': 'Cluster hosts are joined to the IPA domain and hosts are registered in DNS',
+  'admin.kerberos.wizard.step1.option.ipa.condition.2': 'A password policy in place that sets no expiry for created principals or krbPasswordExpiry attribute is writable',
+  'admin.kerberos.wizard.step1.option.ipa.condition.3': 'The ipa managed krb5.conf sets default_ccache_name = /tmp/krb5cc_%{uid}',
+  'admin.kerberos.wizard.step1.option.ipa.condition.4': 'The Java Cryptography Extensions (JCE) have been setup on the Ambari Server host and all hosts in the cluster.',
   'admin.kerberos.wizard.step1.prerequisites.label': 'Following prerequisites needs to be checked to progress ahead in the wizard.',
   'admin.kerberos.wizard.step2.info.body': 'Please configure kerberos related properties.',
   'admin.kerberos.wizard.step3.task0.title': 'Install Kerberos Client',
@@ -1141,6 +1146,7 @@ Em.I18n.translations = {
   'admin.kerberos.wizard.step5.executable_search_paths.label': 'Executable path',
   'admin.kerberos.wizard.step5.exitWizard': 'Exit Wizard',
   'admin.kerberos.wizard.step5.downloadCSV': 'Download CSV',
+  'admin.kerberos.wizard.step5.group.label': 'Group user principals should be member of',
   'admin.kerberos.wizard.step6.task0.title' : 'Stop Services',
   'admin.kerberos.wizard.step6.task1.title' : 'Delete ATS',
   'admin.kerberos.wizard.step6.notice.inProgress': 'Please wait while services are being stopped.',

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/app/views/common/controls_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/controls_view.js b/ambari-web/app/views/common/controls_view.js
index 19d3cc5..661ef54 100644
--- a/ambari-web/app/views/common/controls_view.js
+++ b/ambari-web/app/views/common/controls_view.js
@@ -1090,7 +1090,14 @@ App.CheckDBConnectionView = Ember.View.extend({
   didInsertElement: function() {
     var kdc = this.get('parentView.categoryConfigsAll').findProperty('name', 'kdc_type');
     if (kdc) {
-      var name = kdc.get('value') == 'Existing MIT KDC' ? 'KDC' : 'AD';
+      var name = kdc.get('value');
+      if (name == 'Existing MIT KDC') {
+        name = 'KDC';
+      } else if (name == 'Existing IPA') {
+        name = 'IPA';
+      } else {
+        name = 'AD';
+      }
       App.popover(this.$(), {
         title: Em.I18n.t('services.service.config.database.btn.idle'),
         content: Em.I18n.t('installer.controls.checkConnection.popover').format(name),

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-web/test/utils/object_utils_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/object_utils_test.js b/ambari-web/test/utils/object_utils_test.js
index 0f9723b..f70259c 100644
--- a/ambari-web/test/utils/object_utils_test.js
+++ b/ambari-web/test/utils/object_utils_test.js
@@ -486,7 +486,7 @@ describe('utils/object_utils', function() {
           },
           {
             "principal" : {
-              "value" : "${cluster-env/smokeuser}-${cluster_name}@${realm}",
+              "value" : "${cluster-env/smokeuser}-${cluster_name|toLower()}@${realm}",
               "local_username" : "${cluster-env/smokeuser}",
               "configuration" : "cluster-env/smokeuser_principal_name",
               "type" : "user"


[2/2] ambari git commit: AMBARI-6432. FreeIPA Support in Ambari (Bolke de Bruin via rlevas)

Posted by rl...@apache.org.
AMBARI-6432. FreeIPA Support in Ambari (Bolke de Bruin via rlevas)


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

Branch: refs/heads/trunk
Commit: 476d87b70b42a58914c69c3ce8098531d9405e48
Parents: 2d7dffc
Author: Bolke de Bruin <bd...@gmail.com>
Authored: Wed Mar 23 17:55:01 2016 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Wed Mar 23 17:55:16 2016 -0400

----------------------------------------------------------------------
 .../HDP/2.0.8/services/HDFS/kerberos.json       |    2 +-
 .../server/controller/KerberosHelperImpl.java   |    8 +-
 .../kerberos/CreateKeytabFilesServerAction.java |    5 +-
 .../kerberos/IPAKerberosOperationHandler.java   | 1134 ++++++++++++++++++
 .../server/serveraction/kerberos/KDCType.java   |    7 +-
 .../kerberos/KerberosOperationHandler.java      |   41 +-
 .../KerberosOperationHandlerFactory.java        |    2 +
 .../kerberos/VariableReplacementHelper.java     |   15 +
 .../ambari/server/utils/ShellCommandUtil.java   |   29 +-
 .../ACCUMULO/1.6.1.2.2.0/kerberos.json          |    2 +-
 .../HBASE/0.96.0.2.0/kerberos.json              |    2 +-
 .../HDFS/2.1.0.2.0/kerberos.json                |    2 +-
 .../1.10.3-10/configuration/kerberos-env.xml    |   52 +-
 .../SPARK/1.2.0.2.2/kerberos.json               |    2 +-
 .../SPARK/1.4.1.2.3/kerberos.json               |    2 +-
 .../STORM/0.9.1.2.1/kerberos.json               |    2 +-
 .../resources/stacks/HDP/2.0.6/kerberos.json    |    2 +-
 .../HDP/2.3.ECS/services/ECS/kerberos.json      |    2 +-
 .../HDP/2.3.ECS/services/HBASE/kerberos.json    |    2 +-
 .../services/ACCUMULO/kerberos.json             |    2 +-
 .../HDP/2.3/services/ACCUMULO/kerberos.json     |    4 +-
 .../IPAKerberosOperationHandlerTest.java        |  154 +++
 .../kerberos/VariableReplacementHelperTest.java |    2 +
 .../test_kerberos_descriptor_2_1_3.json         |   14 +-
 .../test_kerberos_descriptor_no_hdfs.json       |    4 +-
 .../test_kerberos_descriptor_simple.json        |    4 +-
 .../HDP/2.0.8/services/HDFS/kerberos.json       |    2 +-
 ambari-web/app/config.js                        |    1 +
 .../app/controllers/main/admin/kerberos.js      |    1 +
 .../main/admin/kerberos/step1_controller.js     |   35 +-
 .../main/admin/kerberos/step2_controller.js     |   26 +-
 .../main/admin/kerberos/step5_controller.js     |    4 +
 .../controllers/main/service/info/configs.js    |    6 +
 ambari-web/app/data/HDP2/site_properties.js     |    9 +
 ambari-web/app/messages.js                      |    6 +
 ambari-web/app/views/common/controls_view.js    |    9 +-
 ambari-web/test/utils/object_utils_test.js      |    2 +-
 37 files changed, 1555 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-funtest/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-funtest/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json b/ambari-funtest/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
index c285234..d53205d 100644
--- a/ambari-funtest/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
+++ b/ambari-funtest/src/test/resources/stacks/HDP/2.0.8/services/HDFS/kerberos.json
@@ -18,7 +18,7 @@
         {
           "name": "hdfs",
           "principal": {
-            "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}",
+            "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user" ,
             "configuration": "hadoop-env/hdfs_principal_name",
             "local_username" : "${hadoop-env/hdfs_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
index be6edc9..f7326a0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
@@ -1640,7 +1640,6 @@ public class KerberosHelperImpl implements KerberosHelper {
                       Role.KERBEROS_CLIENT.name().equals(componentName) &&
                       (sch.getState() == State.INSTALLED)) {
                     hostsWithValidKerberosClient.add(hostname);
-
                     int identitiesAdded = 0;
 
                     // Lazily create the KerberosIdentityDataFileWriter instance...
@@ -1671,6 +1670,10 @@ public class KerberosHelperImpl implements KerberosHelper {
             String message = String.format("Failed to write index file - %s", identityDataFile.getAbsolutePath());
             LOG.error(message);
             throw new AmbariException(message, e);
+          } catch (Exception e) {
+            // make sure to log what is going wrong
+            LOG.error("Failed " + e);
+            throw e;
           } finally {
             if (kerberosIdentityDataFileWriter != null) {
               // Make sure the data file is closed
@@ -1687,7 +1690,8 @@ public class KerberosHelperImpl implements KerberosHelper {
           if (!serviceComponentHostsToProcess.isEmpty()) {
             try {
               validateKDCCredentials(kerberosDetails, cluster);
-            } catch (KerberosOperationException e) {
+            } catch (Exception e) {
+              LOG.error("Cannot validate credentials: " + e);
               try {
                 FileUtils.deleteDirectory(dataDirectory);
               } catch (Throwable t) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
index cadfe28..8aa816d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
@@ -298,6 +298,7 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction {
   public Keytab createKeytab(String principal, String password, Integer keyNumber,
                              KerberosOperationHandler operationHandler, boolean checkCache,
                              boolean canCache, ActionLog actionLog) throws AmbariException {
+    LOG.debug("Creating keytab for " + principal + " with kvno " + keyNumber);
     Keytab keytab = null;
 
     // Possibly get the keytab from the cache
@@ -335,8 +336,8 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction {
             File cachedKeytabFile = cacheKeytab(principal, keytab);
             String previousCachedFilePath = principalEntity.getCachedKeytabPath();
             String cachedKeytabFilePath = ((cachedKeytabFile == null) || !cachedKeytabFile.exists())
-                ? null
-                : cachedKeytabFile.getAbsolutePath();
+                    ? null
+                    : cachedKeytabFile.getAbsolutePath();
 
             principalEntity.setCachedKeytabPath(cachedKeytabFilePath);
             kerberosPrincipalDAO.merge(principalEntity);

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
new file mode 100644
index 0000000..537a334
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandler.java
@@ -0,0 +1,1134 @@
+/*
+ * 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.
+ */
+
+package org.apache.ambari.server.serveraction.kerberos;
+
+import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
+import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.commons.lang.StringUtils;
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * IPAKerberosOperationHandler is an implementation of a KerberosOperationHandler providing
+ * functionality specifically for IPA managed KDC. See http://www.freeipa.org
+ * <p/>
+ * It is assumed that the IPA admin tools are installed and that the ipa shell command is
+ * available
+ */
+public class IPAKerberosOperationHandler extends KerberosOperationHandler {
+  private final static Logger LOG = LoggerFactory.getLogger(IPAKerberosOperationHandler.class);
+
+  private String adminServerHost = null;
+
+  private HashMap<String, Keytab> cachedKeytabs = null;
+  /**
+   * This is where user principals are members of. Important as the password should not expire
+   * and thus a separate password policy should apply to this group
+   */
+  private String userPrincipalGroup = null;
+
+  /**
+   * The format used for krbPasswordExpiry
+   */
+  private final SimpleDateFormat expiryFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
+
+  /**
+   * Time zone for krbPasswordExpiry
+   */
+  private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
+
+  /**
+   * Years to add for password expiry
+   */
+  private static final int PASSWORD_EXPIRY_YEAR = 30;
+
+  /**
+   * A regular expression pattern to use to parse the key number from the text captured from the
+   * kvno command
+   */
+  private final static Pattern PATTERN_GET_KEY_NUMBER = Pattern.compile("^.*?: kvno = (\\d+).*$", Pattern.DOTALL);
+
+  /**
+   * A String containing the resolved path to the ipa executable
+   */
+  private String executableIpaGetKeytab = null;
+
+  /**
+   * A String containing the resolved path to the ipa executable
+   */
+  private String executableIpa = null;
+
+  /**
+   * A String containing the resolved path to the kinit executable
+   */
+  private String executableKinit = null;
+
+  /**
+   * A String containing the resolved path to the ipa-getkeytab executable
+   */
+  private String executableKvno = null;
+
+  /**
+   * A boolean indicating if password expiry should be set
+   */
+  private boolean usePasswordExpiry = false;
+
+  /**
+   * An int indicating the time out in seconds for the password chat;
+   */
+  private int timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
+
+  /**
+   * Credentials context stores a handler to the ccache so it can be reused and removed on request
+   */
+  private CredentialsContext credentialsContext;
+
+  /**
+   * Prepares and creates resources to be used by this KerberosOperationHandler
+   * <p/>
+   * It is expected that this KerberosOperationHandler will not be used before this call.
+   * <p/>
+   * The kerberosConfiguration Map is not being used.
+   *
+   * @param administratorCredentials a KerberosCredential containing the administrative credentials
+   *                                 for the relevant IPA KDC
+   * @param realm                    a String declaring the default Kerberos realm (or domain)
+   * @param kerberosConfiguration    a Map of key/value pairs containing data from the kerberos-env configuration set
+   * @throws KerberosKDCConnectionException       if a connection to the KDC cannot be made
+   * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
+   * @throws KerberosRealmException               if the realm does not map to a KDC
+   * @throws KerberosOperationException           if an unexpected error occurred
+   */
+  @Override
+  public void open(PrincipalKeyCredential administratorCredentials, String realm,
+                   Map<String, String> kerberosConfiguration)
+          throws KerberosOperationException {
+
+    setAdministratorCredential(administratorCredentials);
+    setDefaultRealm(realm);
+
+    if (kerberosConfiguration != null) {
+      // todo: ignore if ipa managed krb5.conf?
+      setKeyEncryptionTypes(translateEncryptionTypes(kerberosConfiguration.get(KERBEROS_ENV_ENCRYPTION_TYPES), "\\s+"));
+      setExecutableSearchPaths(kerberosConfiguration.get(KERBEROS_ENV_EXECUTABLE_SEARCH_PATHS));
+      setUserPrincipalGroup(kerberosConfiguration.get(KERBEROS_ENV_USER_PRINCIPAL_GROUP));
+      setAdminServerHost(kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST));
+      setUsePasswordExpiry(kerberosConfiguration.get(KERBEROS_ENV_SET_PASSWORD_EXPIRY));
+      setTimeout(kerberosConfiguration.get(KERBEROS_ENV_PASSWORD_CHAT_TIMEOUT));
+    } else {
+      setKeyEncryptionTypes(null);
+      setAdminServerHost(null);
+      setExecutableSearchPaths((String) null);
+      setUserPrincipalGroup(null);
+      setUsePasswordExpiry(null);
+      setTimeout(null);
+    }
+
+    // Pre-determine the paths to relevant Kerberos executables
+    executableIpa = getExecutable("ipa");
+    executableKvno = getExecutable("kvno");
+    executableKinit = getExecutable("kinit");
+    executableIpaGetKeytab = getExecutable("ipa-getkeytab");
+
+    credentialsContext = new CredentialsContext(administratorCredentials);
+    cachedKeytabs = new HashMap<>();
+    expiryFormat.setTimeZone(UTC);
+
+    setOpen(true);
+  }
+
+  private void setUsePasswordExpiry(String usePasswordExpiry) {
+    if (usePasswordExpiry == null) {
+      this.usePasswordExpiry = false;
+      return;
+    }
+
+    if (usePasswordExpiry.equalsIgnoreCase("true")) {
+      this.usePasswordExpiry = true;
+    } else {
+      this.usePasswordExpiry = false;
+    }
+  }
+
+  private void setTimeout(String timeout) {
+    if (timeout == null || timeout.isEmpty()) {
+      this.timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
+      return;
+    }
+
+    try {
+      this.timeout = Integer.parseInt(timeout);
+    } catch (NumberFormatException e) {
+      this.timeout = DEFAULT_PASSWORD_CHAT_TIMEOUT;
+    }
+  }
+
+  @Override
+  public void close() throws KerberosOperationException {
+    if (isOpen()) {
+      credentialsContext.delete();
+    }
+
+    // There is nothing to do here.
+    setOpen(false);
+
+    executableIpa = null;
+    executableKvno = null;
+    executableIpaGetKeytab = null;
+    executableKinit = null;
+    credentialsContext = null;
+    cachedKeytabs = null;
+  }
+
+  /**
+   * Test to see if the specified principal exists in a previously configured IPA KDC
+   * <p/>
+   * This implementation creates a query to send to the ipa shell command and then interrogates
+   * the result from STDOUT to determine if the presence of the specified principal.
+   *
+   * @param principal a String containing the principal to test
+   * @return true if the principal exists; false otherwise
+   * @throws KerberosOperationException if an unexpected error occurred
+   */
+  @Override
+  public boolean principalExists(String principal)
+          throws KerberosOperationException {
+
+    LOG.debug("Entering principal exists");
+
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not been opened");
+    }
+
+    if (principal == null) {
+      return false;
+    } else if (isServicePrincipal(principal)) {
+      return true;
+    } else {
+      // TODO: fix exception check to only check for relevant exceptions
+      try {
+        DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+        LOG.debug("Running IPA command user-show");
+
+        // Create the ipa query to execute:
+        ShellCommandUtil.Result result = invokeIpa(String.format("user-show %s", deconstructedPrincipal.getPrincipalName()));
+        if (result.isSuccessful()) {
+          return true;
+        }
+      } catch (KerberosOperationException e) {
+        LOG.error("Cannot invoke IPA: " + e);
+        throw e;
+      }
+    }
+
+    return false;
+  }
+
+
+  /**
+   * Creates a new principal in a previously configured IPA Realm
+   * <p/>
+   * This implementation creates a query to send to the kadmin shell command and then interrogates
+   * the result from STDOUT to determine if the operation executed successfully.
+   *
+   * @param principal a String containing the principal add
+   * @param password  a String containing the password to use when creating the principal
+   * @param service   a boolean value indicating whether the principal is to be created as a service principal or not
+   * @return an Integer declaring the generated key number
+   * @throws KerberosKDCConnectionException if a connection to the KDC cannot be made
+   */
+  @Override
+  public Integer createPrincipal(String principal, String password, boolean service)
+          throws KerberosOperationException {
+
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not been opened");
+    }
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to create new principal - no principal specified");
+    } else if (((password == null) || password.isEmpty()) && service) {
+      throw new KerberosOperationException("Failed to create new user principal - no password specified");
+    } else {
+      DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+
+      if (service) {
+        // Create the ipa query:  service-add --ok-as-delegate <principal>
+        ShellCommandUtil.Result result = invokeIpa(String.format("service-add %s", principal));
+        if (result.isSuccessful()) {
+          // IPA does not generate encryption types when no keytab has been generated
+          // So getKeyNumber(principal) cannot be used.
+          // createKeytabCredentials(principal, password);
+          // return getKeyNumber(principal);
+          return 0;
+        } else {
+          LOG.error("Failed to execute ipa query: service-add --ok-as-delegate=TRUE {}\nSTDOUT: {}\nSTDERR: {}",
+                  principal, result.getStdout(), result.getStderr());
+          throw new KerberosOperationException(String.format("Failed to create service principal for %s\nSTDOUT: %s\nSTDERR: %s",
+                  principal, result.getStdout(), result.getStderr()));
+        }
+      } else {
+        if (!StringUtils.isAllLowerCase(deconstructedPrincipal.getPrincipalName())) {
+          LOG.warn(deconstructedPrincipal.getPrincipalName() + " is not in lowercase. FreeIPA does not recognize user " +
+                  "principals that are not entirely in lowercase. This can lead to issues with kinit and keytabs. Make " +
+                  "sure users are in lowercase ");
+        }
+        // Create the ipa query: user-add <username> --principal=<principal_name> --first <primary> --last <primary>
+        // set-attr userPassword="<password>"
+        // first and last are required for IPA so we make it equal to the primary
+        // the --principal arguments makes sure that Kerberos keys are available for use in getKeyNumber
+        ShellCommandUtil.Result result = invokeIpa(String.format("user-add %s --principal=%s --first %s --last %s --setattr userPassword=%s",
+                deconstructedPrincipal.getPrimary(), deconstructedPrincipal.getPrincipalName(),
+                deconstructedPrincipal.getPrimary(), deconstructedPrincipal.getPrimary(), password));
+
+        if (!result.isSuccessful()) {
+          throw new KerberosOperationException(String.format("Failed to create user principal for %s\nSTDOUT: %s\nSTDERR: %s",
+                  principal, result.getStdout(), result.getStderr()));
+        }
+
+        if (getUserPrincipalGroup() != null && !getUserPrincipalGroup().isEmpty()) {
+          result = invokeIpa(String.format("group-add-member %s --users=%s",
+                  getUserPrincipalGroup(), deconstructedPrincipal.getPrimary()));
+          if (!result.isSuccessful()) {
+            throw new KerberosOperationException(String.format("Failed to create user principal for %s\nSTDOUT: %s\nSTDERR: %s",
+                    principal, result.getStdout(), result.getStderr()));
+          }
+        }
+
+        if (!usePasswordExpiry) {
+          updatePassword(deconstructedPrincipal.getPrimary(), password);
+          return getKeyNumber(principal);
+        }
+
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.YEAR, PASSWORD_EXPIRY_YEAR);
+
+        result = invokeIpa(String.format("user-mod %s --setattr krbPasswordExpiration=%s",
+                deconstructedPrincipal.getPrimary(), expiryFormat.format(calendar.getTime())));
+
+        if (result.isSuccessful()) {
+          return getKeyNumber(principal);
+        }
+
+        throw new KerberosOperationException(String.format("Unknown error while creating principal for %s\n" +
+                        "STDOUT: %s\n" +
+                        "STDERR: %s\n",
+                principal, result.getStdout(), result.getStderr()));
+      }
+    }
+  }
+
+  /**
+   * Updates the password for an existing user principal in a previously configured IPA KDC
+   * <p/>
+   * This implementation creates a query to send to the ipa shell command and then interrogates
+   * the exit code to determine if the operation executed successfully.
+   *
+   * @param principal a String containing the principal to update
+   * @param password  a String containing the password to set
+   * @return an Integer declaring the new key number
+   * @throws KerberosOperationException if an unexpected error occurred
+   */
+  @Override
+  public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not been opened");
+    }
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to set password - no principal specified");
+    } else if ((password == null) || password.isEmpty()) {
+      throw new KerberosOperationException("Failed to set password - no password specified");
+    } else if (!isServicePrincipal(principal)) {
+      DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+
+      if (usePasswordExpiry) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.YEAR, PASSWORD_EXPIRY_YEAR);
+
+        // Create the ipa query:  user-mod <user> --setattr userPassword=<password>
+        invokeIpa(String.format("user-mod %s --setattr userPassword=%s", deconstructedPrincipal.getPrimary(), password));
+
+        List<String> command = new ArrayList<>();
+        command.add(executableIpa);
+        command.add("user-mod");
+        command.add(deconstructedPrincipal.getPrimary());
+        command.add("--setattr");
+        command.add(String.format("krbPasswordExpiration=%s", expiryFormat.format(calendar.getTime())));
+        ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
+        if (!result.isSuccessful()) {
+          throw new KerberosOperationException("Failed to set password expiry");
+        }
+      } else {
+        updatePassword(deconstructedPrincipal.getPrimary(), password);
+      }
+    } else {
+      ShellCommandUtil.Result result = invokeIpa(String.format("service-show %s", principal));
+      // ignore the keytab but set the password for this principal
+      if (result.isSuccessful() && result.getStdout().contains("Keytab: False")) {
+        LOG.debug("Found service principal " + principal + " without password/keytab. Setting one");
+        createKeytab(principal, password, 0);
+      }
+    }
+    return getKeyNumber(principal);
+  }
+
+  /**
+   * Removes an existing principal in a previously configured KDC
+   * <p/>
+   * The implementation is specific to a particular type of KDC.
+   *
+   * @param principal a String containing the principal to remove
+   * @return true if the principal was successfully removed; otherwise false
+   * @throws KerberosKDCConnectionException       if a connection to the KDC cannot be made
+   * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
+   * @throws KerberosRealmException               if the realm does not map to a KDC
+   * @throws KerberosOperationException           if an unexpected error occurred
+   */
+  @Override
+  public boolean removePrincipal(String principal) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not been opened");
+    }
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to remove new principal - no principal specified");
+    } else {
+      ShellCommandUtil.Result result = null;
+      if (isServicePrincipal(principal)) {
+        result = invokeIpa(String.format("service-del %s", principal));
+      } else {
+        DeconstructedPrincipal deconstructedPrincipal = createDeconstructPrincipal(principal);
+        result = invokeIpa(String.format("user-del %s", deconstructedPrincipal.getPrincipalName()));
+      }
+      return result.isSuccessful();
+    }
+  }
+
+  /**
+   * Sets the name of the group where user principals should be members of
+   *
+   * @param userPrincipalGroup the name of the group
+   */
+  public void setUserPrincipalGroup(String userPrincipalGroup) {
+    this.userPrincipalGroup = userPrincipalGroup;
+  }
+
+  /**
+   * Gets the name of the group where user principals should be members of
+   *
+   * @return name of the group where user principals should be members of
+   */
+  public String getUserPrincipalGroup() {
+    return this.userPrincipalGroup;
+  }
+
+  /**
+   * Sets the KDC administrator server host address
+   *
+   * @param adminServerHost the ip address or FQDN of the IPA administrator server
+   */
+  public void setAdminServerHost(String adminServerHost) {
+    this.adminServerHost = adminServerHost;
+  }
+
+  /**
+   * Gets the IP address or FQDN of the IPA administrator server
+   *
+   * @return the IP address or FQDN of the IPA administrator server
+   */
+  public String getAdminServerHost() {
+    return this.adminServerHost;
+  }
+
+  /**
+   * Reads data from a stream without blocking and when available. Allows some time for the
+   * stream to become ready.
+   *
+   * @param stdin  the stdin BufferedReader to read from
+   * @param stderr the stderr BufferedReader in case something goes wrong
+   * @return a String with available data
+   * @throws KerberosOperationException if a timeout happens
+   * @throws IOException                when somethings goes wrong with the underlying stream
+   * @throws InterruptedException       if the thread is interrupted
+   */
+  private String readData(BufferedReader stdin, BufferedReader stderr) throws KerberosOperationException, IOException, InterruptedException {
+    char[] data = new char[1024];
+    StringBuilder sb = new StringBuilder();
+
+    int count = 0;
+    while (!stdin.ready()) {
+      Thread.sleep(1000L);
+      if (count >= timeout) {
+        char[] err_data = new char[1024];
+        StringBuilder err = new StringBuilder();
+        while (stderr.ready()) {
+          stderr.read(err_data);
+          err.append(err_data);
+        }
+        throw new KerberosOperationException("No answer data available from stdin stream. STDERR: " + err.toString());
+      }
+      count++;
+    }
+
+    while (stdin.ready()) {
+      stdin.read(data);
+      sb.append(data);
+    }
+
+    return sb.toString();
+  }
+
+  /**
+   * Updates a  password for a (user) principal. This is done by first setting a random password and
+   * then invoking kInit to directly set the password. This is done to circumvent issues with expired
+   * password in IPA, as IPA needs passwords set by the admin to be set again by the user. Note that
+   * this resets the current principal to the principal specified here. To invoke further administrative
+   * commands a new kInit to admin is required.
+   *
+   * @param principal The principal user name that needs to be updated
+   * @param password  The new password
+   * @throws KerberosOperationException if something is not as expected
+   */
+  private void updatePassword(String principal, String password) throws KerberosOperationException {
+    BufferedReader reader = null;
+    BufferedReader stderr = null;
+    OutputStreamWriter out = null;
+
+    LOG.debug("Updating password for: " + principal);
+
+    UUID uuid = UUID.randomUUID();
+    String fileName = System.getProperty("java.io.tmpdir") +
+            File.pathSeparator +
+            "krb5cc_" + uuid.toString();
+
+    try {
+      ShellCommandUtil.Result result = invokeIpa(String.format("user-mod %s --random", principal));
+      if (!result.isSuccessful()) {
+        throw new KerberosOperationException(result.getStderr());
+      }
+      Pattern pattern = Pattern.compile("password: (.*)");
+      Matcher matcher = pattern.matcher(result.getStdout());
+      if (!matcher.find()) {
+        throw new KerberosOperationException("Unexpected response from ipa: " + result.getStdout());
+      }
+      String old_password = matcher.group(1);
+
+      String credentialsCache = String.format("FILE:%s", fileName);
+      Process process = Runtime.getRuntime().exec(new String[]{executableKinit, "-c", credentialsCache, principal});
+      reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
+      stderr = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
+      out = new OutputStreamWriter(process.getOutputStream());
+
+      String data = readData(reader, stderr);
+      if (!data.startsWith("Password")) {
+        process.destroy();
+        throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
+                + principal + " got: " + data);
+      }
+      LOG.debug("Sending old password");
+      out.write(old_password);
+      out.write('\n');
+      out.flush();
+
+      data = readData(reader, stderr);
+      if (!data.contains("Enter")) {
+        process.destroy();
+        throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
+                + principal + " got: " + data);
+      }
+      LOG.debug("Sending new password");
+      out.write(password);
+      out.write('\n');
+      out.flush();
+
+      data = readData(reader, stderr);
+      if (!data.contains("again")) {
+        process.destroy();
+        throw new KerberosOperationException("Unexpected response from kinit while trying to password for "
+                + principal + " got: " + data);
+      }
+      LOG.debug("Sending new password again");
+      out.write(password);
+      out.write('\n');
+      out.flush();
+
+      process.waitFor();
+    } catch (IOException e) {
+      LOG.error("Cannot read stream: " + e);
+      throw new KerberosOperationException(e.getMessage());
+    } catch (InterruptedException e) {
+      LOG.error("Process interrupted: " + e);
+      throw new KerberosOperationException(e.getMessage());
+    } finally {
+      try {
+        if (out != null)
+          out.close();
+      } catch (IOException e) {
+        LOG.warn("Cannot close out stream: " + e);
+      }
+      try {
+        if (reader != null)
+          reader.close();
+      } catch (IOException e) {
+        LOG.warn("Cannot close stdin stream: " + e);
+      }
+      try {
+        if (stderr != null)
+          stderr.close();
+      } catch (IOException e) {
+        LOG.warn("Cannot close stderr stream: " + e);
+      }
+      File ccache = new File(fileName);
+      ccache.delete();
+    }
+
+  }
+
+  /**
+   * Invokes the ipa shell command with administrative credentials to issue queries
+   *
+   * @param query a String containing the query to send to the kdamin command
+   * @return a ShellCommandUtil.Result containing the result of the operation
+   * @throws KerberosOperationException if an unexpected error occurred
+   */
+  protected ShellCommandUtil.Result invokeIpa(String query)
+          throws KerberosOperationException {
+    LOG.debug("Entering invokeipa");
+
+    ShellCommandUtil.Result result = null;
+
+    if ((query == null) || query.isEmpty()) {
+      throw new KerberosOperationException("Missing ipa query");
+    }
+    PrincipalKeyCredential administratorCredentials = getAdministratorCredential();
+    String defaultRealm = getDefaultRealm();
+
+    List<String> command = new ArrayList<String>();
+    List<String> kinit = new ArrayList<String>();
+
+    String adminPrincipal = (administratorCredentials == null)
+            ? null
+            : administratorCredentials.getPrincipal();
+
+    if ((adminPrincipal == null) || adminPrincipal.isEmpty()) {
+      throw new KerberosOperationException("No admin principal for ipa available - " +
+              "this KerberosOperationHandler may not have been opened.");
+    }
+
+    if ((executableIpa == null) || executableIpa.isEmpty()) {
+      throw new KerberosOperationException("No path for ipa is available - " +
+              "this KerberosOperationHandler may not have been opened.");
+    }
+
+    // Set the ipa interface to be ipa
+    command.add(executableIpa);
+    command.add(query);
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug(String.format("Executing: %s", createCleanCommand(command)));
+    }
+
+    List<String> fixedCommand = fixCommandList(command);
+    result = executeCommand(fixedCommand.toArray(new String[fixedCommand.size()]));
+
+
+    LOG.debug("Done invokeipa");
+    return result;
+  }
+
+  /**
+   * Executes a shell command in a credentials context
+   * <p/>
+   * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
+   *
+   * @param command an array of String value representing the command and its arguments
+   * @return a ShellCommandUtil.Result declaring the result of the operation
+   * @throws KerberosOperationException
+   */
+  @Override
+  protected ShellCommandUtil.Result executeCommand(String[] command)
+          throws KerberosOperationException {
+    return credentialsContext.executeCommand(command);
+  }
+
+  /**
+   * Rebuilds the command line to make sure space are converted to arguments
+   *
+   * @param command a List of items making up the command
+   * @return the fixed command
+   */
+  private List<String> fixCommandList(List<String> command) {
+    List<String> fixedCommandList = new ArrayList<>();
+    Iterator<String> iterator = command.iterator();
+
+    if (iterator.hasNext()) {
+      fixedCommandList.add(iterator.next());
+    }
+
+    while (iterator.hasNext()) {
+      String part = iterator.next();
+
+      // split arguments
+      if (part.contains(" ")) {
+        StringTokenizer st = new StringTokenizer(part, " ");
+        while (st.hasMoreElements()) {
+          fixedCommandList.add(st.nextToken());
+        }
+      } else {
+        fixedCommandList.add(part);
+      }
+    }
+
+    return fixedCommandList;
+  }
+
+  /**
+   * Build the ipa command string, replacing administrator password with "********"
+   *
+   * @param command a List of items making up the command
+   * @return the cleaned command string
+   */
+  private String createCleanCommand(List<String> command) {
+    StringBuilder cleanedCommand = new StringBuilder();
+    Iterator<String> iterator = command.iterator();
+
+    if (iterator.hasNext()) {
+      cleanedCommand.append(iterator.next());
+    }
+
+    while (iterator.hasNext()) {
+      String part = iterator.next();
+
+      cleanedCommand.append(' ');
+      cleanedCommand.append(part);
+
+      if ("--setattr".equals(part)) {
+        // Skip the password and use "********" instead
+        String arg= null;
+        if (iterator.hasNext()) {
+          arg = iterator.next();
+          if (arg.contains("userPassword")) {
+            cleanedCommand.append("userPassword=******");
+          } else {
+            cleanedCommand.append(arg);
+          }
+        }
+      }
+    }
+
+    return cleanedCommand.toString();
+  }
+
+  /**
+   * Determine is a principal is a service principal
+   *
+   * @param principal
+   * @return true if the principal is a (existing) service principal
+   * @throws KerberosOperationException
+   */
+  private boolean isServicePrincipal(String principal)
+          throws KerberosOperationException {
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to determine principal type- no principal specified");
+    } else if (!principal.contains("/")) {
+      return false;
+    }
+
+    try {
+      ShellCommandUtil.Result result = invokeIpa(String.format("service-show %s", principal));
+
+      // TODO: unfortunately we can be in limbo if the "Keytab: False" is present
+      if (result.isSuccessful()) {
+        return true;
+      }
+    } catch (KerberosOperationException e) {
+      LOG.warn("Exception while invoking ipa service-show: " + e);
+      return false;
+    }
+
+    return false;
+  }
+
+  /**
+   * Retrieves the current key number assigned to the identity identified by the specified principal
+   *
+   * @param principal a String declaring the principal to look up
+   * @return an Integer declaring the current key number
+   * @throws KerberosKDCConnectionException       if a connection to the KDC cannot be made
+   * @throws KerberosAdminAuthenticationException if the administrator credentials fail to authenticate
+   * @throws KerberosRealmException               if the realm does not map to a KDC
+   * @throws KerberosOperationException           if an unexpected error occurred
+   */
+  private Integer getKeyNumber(String principal) throws KerberosOperationException {
+    if (!isOpen()) {
+      throw new KerberosOperationException("This operation handler has not been opened");
+    }
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to get key number for principal  - no principal specified");
+    } else {
+      // Create the kvno query:  <principal>
+      List<String> command = new ArrayList<>();
+      command.add(executableKvno);
+      command.add(principal);
+
+      ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
+      String stdOut = result.getStdout();
+      if (stdOut == null) {
+        String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
+                principal, result.getExitCode(), result.getStderr());
+        LOG.warn(message);
+        throw new KerberosOperationException(message);
+      }
+
+      Matcher matcher = PATTERN_GET_KEY_NUMBER.matcher(stdOut);
+      if (matcher.matches()) {
+        NumberFormat numberFormat = NumberFormat.getIntegerInstance();
+        String keyNumber = matcher.group(1);
+
+        numberFormat.setGroupingUsed(false);
+        try {
+          Number number = numberFormat.parse(keyNumber);
+          return (number == null) ? 0 : number.intValue();
+        } catch (ParseException e) {
+          String message = String.format("Failed to get key number for %s - invalid key number value (%s):\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
+                  principal, keyNumber, result.getExitCode(), result.getStderr());
+          LOG.warn(message);
+          throw new KerberosOperationException(message);
+        }
+      } else {
+        String message = String.format("Failed to get key number for %s - unexpected STDOUT data:\n\tExitCode: %s\n\tSTDOUT: NULL\n\tSTDERR: %s",
+                principal, result.getExitCode(), result.getStderr());
+        LOG.warn(message);
+        throw new KerberosOperationException(message);
+      }
+
+    }
+  }
+
+  /**
+   * Creates a key tab by using the ipa commandline utilities.
+   *
+   * @param principal a String containing the principal to test
+   * @param password  a String containing the password to use when creating the principal
+   * @return
+   * @throws KerberosOperationException
+   */
+  /*private Keytab createKeytabCredentials(String principal, String password)
+          throws KerberosOperationException {
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to create keytab file, missing principal");
+    }
+
+    BufferedReader reader = null;
+    BufferedReader stderr = null;
+    OutputStreamWriter out = null;
+
+    UUID uuid = UUID.randomUUID();
+    String fileName = System.getProperty("java.io.tmpdir") +
+            File.pathSeparator +
+            "ambari." + uuid.toString();
+
+    try {
+      // TODO: add ciphers
+      Process p = credentialsContext.exec(new String[]{executableIpaGetKeytab, "-s",
+              getAdminServerHost(), "-p", principal, "-k", fileName, "-P"});
+      reader = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8));
+      stderr = new BufferedReader(new InputStreamReader(p.getErrorStream(), StandardCharsets.UTF_8));
+      out = new OutputStreamWriter(p.getOutputStream());
+
+      String data = readData(reader, stderr);
+      if (!data.startsWith("New")) {
+        p.destroy();
+        throw new KerberosOperationException("Unexpected response from ipa-getkeytab while trying to password for "
+                + principal + " got: " + data);
+      }
+      LOG.debug("Sending password");
+      out.write(password);
+      out.write('\n');
+      out.flush();
+
+      data = readData(reader, stderr);
+      if (!data.contains("Verify")) {
+        p.destroy();
+        throw new KerberosOperationException("Unexpected response from ipa-getkeytab while trying to password for "
+                + principal + " got: " + data);
+      }
+      LOG.debug("Sending new password");
+      out.write(password);
+      out.write('\n');
+      out.flush();
+
+      p.waitFor();
+    } catch (IOException e) {
+      LOG.error("Cannot read stream: " + e);
+      throw new KerberosOperationException(e.getMessage());
+    } catch (InterruptedException e) {
+      LOG.error("Process interrupted: " + e);
+      throw new KerberosOperationException(e.getMessage());
+    } finally {
+      try {
+        if (out != null)
+          out.close();
+      } catch (IOException e) {
+        LOG.warn("Cannot close out stream: " + e);
+      }
+      try {
+        if (reader != null)
+          reader.close();
+      } catch (IOException e) {
+        LOG.warn("Cannot close stdin stream: " + e);
+      }
+      try {
+        if (stderr != null)
+          stderr.close();
+      } catch (IOException e) {
+        LOG.warn("Cannot close stderr stream: " + e);
+      }
+    }
+
+    File keytabFile = new File(fileName);
+    Keytab keytab = readKeytabFile(keytabFile);
+    keytabFile.delete();
+
+    return keytab;
+  }*/
+
+  /**
+   * Creates a key tab by using the ipa commandline utilities. It ignores key number and password
+   * as this will be handled by IPA
+   *
+   * @param principal a String containing the principal to test
+   * @param password  (IGNORED) a String containing the password to use when creating the principal
+   * @param keyNumber (IGNORED) a Integer indicating the key number for the keytab entries
+   * @return
+   * @throws KerberosOperationException
+   */
+  @Override
+  protected Keytab createKeytab(String principal, String password, Integer keyNumber)
+          throws KerberosOperationException {
+
+    if ((principal == null) || principal.isEmpty()) {
+      throw new KerberosOperationException("Failed to create keytab file, missing principal");
+    }
+
+    // use cache if available
+    if (cachedKeytabs.containsKey(principal)) {
+      return cachedKeytabs.get(principal);
+    }
+
+    UUID uuid = UUID.randomUUID();
+    String fileName = System.getProperty("java.io.tmpdir") +
+            File.pathSeparator +
+            "ambari." + uuid.toString();
+
+    // TODO: add ciphers
+    List<String> command = new ArrayList<>();
+    command.add(executableIpaGetKeytab);
+    command.add("-s");
+    command.add(getAdminServerHost());
+    command.add("-p");
+    command.add(principal);
+    command.add("-k");
+    command.add(fileName);
+
+    // TODO: is it really required to set the password?
+    ShellCommandUtil.Result result = executeCommand(command.toArray(new String[command.size()]));
+    if (!result.isSuccessful()) {
+      String message = String.format("Failed to get key number for %s:\n\tExitCode: %s\n\tSTDOUT: %s\n\tSTDERR: %s",
+              principal, result.getExitCode(), result.getStdout(), result.getStderr());
+      LOG.warn(message);
+      throw new KerberosOperationException(message);
+    }
+
+    File keytabFile = new File(fileName);
+    Keytab keytab = readKeytabFile(keytabFile);
+    keytabFile.delete();
+
+    cachedKeytabs.put(principal, keytab);
+    return keytab;
+  }
+
+
+  /**
+   * Credentials context executes commands wrapped with kerberos credentials
+   */
+  class CredentialsContext {
+    private PrincipalKeyCredential credentials;
+    Map<String, String> env = new HashMap();
+    private String fileName;
+    private List<Process> processes = new ArrayList<>();
+
+    public CredentialsContext(PrincipalKeyCredential credentials) throws KerberosOperationException {
+      this.credentials = credentials;
+
+      UUID uuid = UUID.randomUUID();
+      fileName = System.getProperty("java.io.tmpdir") +
+              File.pathSeparator +
+              "krb5cc_" + uuid.toString();
+      env.put("KRB5CCNAME", String.format("FILE:%s", fileName));
+
+      init(credentials, fileName);
+    }
+
+    protected ShellCommandUtil.Result executeCommand(String[] command)
+            throws KerberosOperationException {
+
+      if ((command == null) || (command.length == 0)) {
+        return null;
+      } else {
+        try {
+          return ShellCommandUtil.runCommand(command, env);
+        } catch (IOException e) {
+          String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
+          LOG.error(message, e);
+          throw new KerberosOperationException(message, e);
+        } catch (InterruptedException e) {
+          String message = String.format("Failed to wait for the command to complete: %s", e.getLocalizedMessage());
+          LOG.error(message, e);
+          throw new KerberosOperationException(message, e);
+        }
+      }
+    }
+
+    /**
+     * Does a kinit to obtain a ticket for the specified principal and stores it in the specified cache
+     *
+     * @param credentials Credentials to be used to obtain the ticket
+     * @param fileName    Filename where to store the credentials
+     * @throws KerberosOperationException In case the ticket cannot be obtained
+     */
+    private void init(PrincipalKeyCredential credentials, String fileName) throws KerberosOperationException {
+      Process process;
+      BufferedReader reader = null;
+      OutputStreamWriter osw = null;
+
+      LOG.debug("Entering doKinit");
+      try {
+        String credentialsCache = String.format("FILE:%s", fileName);
+
+        LOG.debug("start subprocess " + executableKinit + " " + credentials.getPrincipal());
+        process = Runtime.getRuntime().exec(new String[]{executableKinit, "-c", credentialsCache, credentials.getPrincipal()});
+        reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
+        osw = new OutputStreamWriter(process.getOutputStream());
+
+        char[] data = new char[1024];
+        StringBuilder sb = new StringBuilder();
+
+        int count = 0;
+        while (!reader.ready()) {
+          Thread.sleep(1000L);
+          if (count >= 5) {
+            process.destroy();
+            throw new KerberosOperationException("No answer from kinit");
+          }
+          count++;
+        }
+
+        while (reader.ready()) {
+          reader.read(data);
+          sb.append(data);
+        }
+
+        String line = sb.toString();
+        LOG.debug("Reading a line: " + line);
+        if (!line.startsWith("Password")) {
+          throw new KerberosOperationException("Unexpected response from kinit while trying to get ticket for "
+                  + credentials.getPrincipal() + " got: " + line);
+        }
+        osw.write(credentials.getKey());
+        osw.write('\n');
+        osw.close();
+
+        process.waitFor();
+
+        LOG.debug("done subprocess");
+      } catch (IOException e) {
+        String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
+        LOG.error(message, e);
+        throw new KerberosOperationException(message, e);
+      } catch (InterruptedException e) {
+        String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
+        LOG.error(message, e);
+        throw new KerberosOperationException(message, e);
+      } finally {
+        if (osw != null) {
+          try {
+            osw.close();
+          } catch (IOException e) {
+          }
+        }
+
+        if (reader != null) {
+          try {
+            reader.close();
+          } catch (IOException e) {
+          }
+        }
+      }
+
+      if (process.exitValue() != 0) {
+        throw new KerberosOperationException("kinit failed for " + credentials.getPrincipal() + ". Wrong password?");
+      }
+
+    }
+
+    public Process exec(String[] args) throws IOException {
+      Process process = Runtime.getRuntime().exec(args);
+      processes.add(process);
+
+      return process;
+    }
+
+    public void delete() {
+      File ccache = new File(fileName);
+      ccache.delete();
+      for (Process p : processes) {
+        p.destroy();
+      }
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCType.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCType.java
index 5b1372a..f56ccdc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCType.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCType.java
@@ -37,7 +37,12 @@ public enum KDCType {
   /**
    * Indicates a Microsoft Active Directory
    */
-  ACTIVE_DIRECTORY;
+  ACTIVE_DIRECTORY,
+
+  /**
+   * Indicates an IPA KDC
+   */
+  IPA;
 
   /**
    * Translates a String to a KDCType.

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
index 4cd050e..139fd7a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandler.java
@@ -66,6 +66,26 @@ public abstract class KerberosOperationHandler {
   public final static String KERBEROS_ENV_PRINCIPAL_CONTAINER_DN = "container_dn";
 
   /**
+   * Kerberos-env configuration property name: group
+   */
+  public final static String KERBEROS_ENV_USER_PRINCIPAL_GROUP = "group";
+
+  /**
+   * Kerberos-env configuration property name: password_chat_timeout
+   */
+  public final static String KERBEROS_ENV_PASSWORD_CHAT_TIMEOUT = "password_chat_timeout";
+
+  /**
+   * Default timeout for password chat
+   */
+  public final static int DEFAULT_PASSWORD_CHAT_TIMEOUT = 5;
+
+  /**
+   * Kerberos-env configuration property name: set_password_expiry
+   */
+  public final static String KERBEROS_ENV_SET_PASSWORD_EXPIRY = "set_password_expiry";
+
+  /**
    * Kerberos-env configuration property name: ad_create_attributes_template
    */
   public final static String KERBEROS_ENV_AD_CREATE_ATTRIBUTES_TEMPLATE = "ad_create_attributes_template";
@@ -695,20 +715,21 @@ public abstract class KerberosOperationHandler {
   /**
    * Executes a shell command.
    * <p/>
-   * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
+   * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[], Map<String,String>)}
    *
    * @param command an array of String value representing the command and its arguments
+   * @param envp a map of string, string of environment variables
    * @return a ShellCommandUtil.Result declaring the result of the operation
    * @throws KerberosOperationException
    */
-  protected ShellCommandUtil.Result executeCommand(String[] command)
+  protected ShellCommandUtil.Result executeCommand(String[] command, Map<String, String> envp)
       throws KerberosOperationException {
 
     if ((command == null) || (command.length == 0)) {
       return null;
     } else {
       try {
-        return ShellCommandUtil.runCommand(command);
+        return ShellCommandUtil.runCommand(command, envp);
       } catch (IOException e) {
         String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage());
         LOG.error(message, e);
@@ -722,6 +743,20 @@ public abstract class KerberosOperationHandler {
   }
 
   /**
+   * Executes a shell command.
+   * <p/>
+   * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])}
+   *
+   * @param command an array of String value representing the command and its arguments
+   * @return a ShellCommandUtil.Result declaring the result of the operation
+   * @throws KerberosOperationException
+   */
+  protected ShellCommandUtil.Result executeCommand(String[] command)
+          throws KerberosOperationException {
+    return executeCommand(command, null);
+  }
+
+  /**
    * Given a principal, attempt to create a new DeconstructedPrincipal
    *
    * @param principal a String containing the principal to deconstruct

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
index bfd45b7..d8ca38f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosOperationHandlerFactory.java
@@ -51,6 +51,8 @@ public class KerberosOperationHandlerFactory {
         return injector.getInstance(MITKerberosOperationHandler.class);
       case ACTIVE_DIRECTORY:
         return injector.getInstance(ADKerberosOperationHandler.class);
+      case IPA:
+        return injector.getInstance(IPAKerberosOperationHandler.class);
       default:
         throw new IllegalArgumentException(String.format("Unexpected kdcType value: %s", kdcType.name()));
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java
index 42eea14..66be3bf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelper.java
@@ -48,6 +48,7 @@ public class VariableReplacementHelper {
   private static final Map<String, Function> FUNCTIONS = new HashMap<String, Function>() {
     {
       put("each", new EachFunction());
+      put("toLower", new ToLowerFunction());
     }
   };
 
@@ -225,4 +226,18 @@ public class VariableReplacementHelper {
       return "";
     }
   }
+
+  /**
+   * ToLowerFunction is a Function implementation that converts a String to lowercase
+   */
+  private static class ToLowerFunction implements Function {
+    @Override
+    public String perform(String[] args, String data) {
+      if (data != null) {
+        return data.toLowerCase();
+      }
+
+      return "";
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/java/org/apache/ambari/server/utils/ShellCommandUtil.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/ShellCommandUtil.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/ShellCommandUtil.java
index 947b336..b5d2b70 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/utils/ShellCommandUtil.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/ShellCommandUtil.java
@@ -24,6 +24,7 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Map;
 
 /**
  * Logs OpenSsl command exit code with description
@@ -164,9 +165,23 @@ public class ShellCommandUtil {
     }
   }
 
-  public static Result runCommand(String [] args) throws IOException,
+  /**
+   * Runs a command with a given set of environment variables
+   * @param args a String[] of the command and its arguments
+   * @param vars a Map of String,String setting an environment variable to run the command with
+   * @return Result
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  public static Result runCommand(String [] args, Map<String, String> vars) throws IOException,
           InterruptedException {
     ProcessBuilder builder = new ProcessBuilder(args);
+
+    if (vars != null) {
+      Map<String, String> env = builder.environment();
+      env.putAll(vars);
+    }
+
     Process process;
     if (WINDOWS) {
       synchronized (WindowsProcessLaunchLock) {
@@ -189,6 +204,18 @@ public class ShellCommandUtil {
     return new Result(exitCode, stdout, stderr);
   }
 
+  /**
+   * Run a command
+   * @param args A String[] of the command and its arguments
+   * @return Result
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  public static Result runCommand(String [] args) throws IOException,
+          InterruptedException {
+    return runCommand(args, null);
+  }
+
   private static String streamToString(InputStream is) throws IOException {
     InputStreamReader isr = new InputStreamReader(is);
     BufferedReader reader = new BufferedReader(isr);

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/ACCUMULO/1.6.1.2.2.0/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/ACCUMULO/1.6.1.2.2.0/kerberos.json b/ambari-server/src/main/resources/common-services/ACCUMULO/1.6.1.2.2.0/kerberos.json
index e76f809..caef123 100644
--- a/ambari-server/src/main/resources/common-services/ACCUMULO/1.6.1.2.2.0/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/ACCUMULO/1.6.1.2.2.0/kerberos.json
@@ -6,7 +6,7 @@
         {
           "name": "accumulo",
           "principal": {
-            "value": "${accumulo-env/accumulo_user}-${cluster_name}@${realm}",
+            "value": "${accumulo-env/accumulo_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "accumulo-env/accumulo_principal_name",
             "local_username": "${accumulo-env/accumulo_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/kerberos.json b/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/kerberos.json
index dc5ef2e..c9536f8 100644
--- a/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/HBASE/0.96.0.2.0/kerberos.json
@@ -9,7 +9,7 @@
         {
           "name": "hbase",
           "principal": {
-            "value": "${hbase-env/hbase_user}-${cluster_name}@${realm}",
+            "value": "${hbase-env/hbase_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "hbase-env/hbase_principal_name",
             "local_username": "${hbase-env/hbase_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/kerberos.json b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/kerberos.json
index c9c738e..3d6e25c 100644
--- a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/kerberos.json
@@ -43,7 +43,7 @@
             {
               "name": "hdfs",
               "principal": {
-                "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}",
+                "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}",
                 "type" : "user" ,
                 "configuration": "hadoop-env/hdfs_principal_name",
                 "local_username" : "${hadoop-env/hdfs_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
index a03dea6..b56bcbf 100644
--- a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
+++ b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/configuration/kerberos-env.xml
@@ -24,7 +24,7 @@
   <property require-input="true">
     <name>kdc_type</name>
     <description>
-      The type of KDC being used. Either mit-kdc or active-directory
+      The type of KDC being used. Either mit-kdc, ipa, or active-directory
     </description>
     <value>mit-kdc</value>
     <display-name>KDC type</display-name>
@@ -161,7 +161,7 @@
     <name>executable_search_paths</name>
     <display-name>Executable Search Paths</display-name>
     <description>
-      A comma-delimited list of search paths to use to find Kerberos utilities like kadmin and kinit.
+      A comma-delimited list of search paths to use to find Kerberos utilities like kadmin, kinit and ipa.
     </description>
     <value>/usr/bin, /usr/kerberos/bin, /usr/sbin, /usr/lib/mit/bin, /usr/lib/mit/sbin</value>
     <value-attributes>
@@ -253,7 +253,7 @@
     <description>
       The principal name to use when executing the Kerberos service check
     </description>
-    <value>${cluster_name}-${short_date}</value>
+    <value>${cluster_name|toLower()}-${short_date}</value>
     <value-attributes>
       <overridable>false</overridable>
     </value-attributes>
@@ -315,4 +315,50 @@
       <overridable>false</overridable>
     </value-attributes>
   </property>
+
+  <property>
+    <name>group</name>
+    <display-name>IPA Group</display-name>
+    <description>
+      The group in IPA user principals should be member of
+    </description>
+    <value>ambari-managed-principals</value>
+    <value-attributes>
+      <empty-value-valid>true</empty-value-valid>
+      <visible>false</visible>
+    </value-attributes>
+  </property>
+
+  <property>
+    <name>set_password_expiry</name>
+    <display-name>Set IPA principal password expiry</display-name>
+    <description>
+      Indicates whether Ambari should set the password expiry for the principals it creates. By default
+      IPA does not allow this. It requires write permission of the admin principal to the krbPasswordExpiry
+      attribute. If set IPA principal password expiry is not true it is assumed that a suitable password
+      policy is in place for the IPA Group principals are added to.
+    </description>
+    <value>false</value>
+    <value-attributes>
+      <type>boolean</type>
+      <overridable>false</overridable>
+      <visible>false</visible>
+    </value-attributes>
+  </property>
+
+  <property>
+    <name>password_chat_timeout</name>
+    <display-name>Set IPA kinit password chat timeout</display-name>
+    <description>
+      Indicates the timeout in seconds that Ambari should wait for a response during a password chat. This is
+      because it can take some time due to lookups before a response is there.
+    </description>
+    <value>5</value>
+    <value-attributes>
+      <visible>false</visible>
+      <type>int</type>
+      <overridable>false</overridable>
+    </value-attributes>
+  </property>
+
 </configuration>

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/SPARK/1.2.0.2.2/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/SPARK/1.2.0.2.2/kerberos.json b/ambari-server/src/main/resources/common-services/SPARK/1.2.0.2.2/kerberos.json
index 5354f69..fa6af33 100644
--- a/ambari-server/src/main/resources/common-services/SPARK/1.2.0.2.2/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/SPARK/1.2.0.2.2/kerberos.json
@@ -9,7 +9,7 @@
         {
           "name": "sparkuser",
           "principal": {
-            "value": "${spark-env/spark_user}-${cluster_name}@${realm}",
+            "value": "${spark-env/spark_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "spark-defaults/spark.history.kerberos.principal",
             "local_username" : "${spark-env/spark_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/SPARK/1.4.1.2.3/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/SPARK/1.4.1.2.3/kerberos.json b/ambari-server/src/main/resources/common-services/SPARK/1.4.1.2.3/kerberos.json
index 90d9090..21ba259 100644
--- a/ambari-server/src/main/resources/common-services/SPARK/1.4.1.2.3/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/SPARK/1.4.1.2.3/kerberos.json
@@ -9,7 +9,7 @@
         {
           "name": "sparkuser",
           "principal": {
-            "value": "${spark-env/spark_user}-${cluster_name}@${realm}",
+            "value": "${spark-env/spark_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "spark-defaults/spark.history.kerberos.principal",
             "local_username" : "${spark-env/spark_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/kerberos.json b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/kerberos.json
index 5c2133c..fcfe524 100644
--- a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/kerberos.json
+++ b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/kerberos.json
@@ -12,7 +12,7 @@
         {
           "name": "storm_components",
           "principal": {
-            "value": "${storm-env/storm_user}-${cluster_name}@${realm}",
+            "value": "${storm-env/storm_user}-${cluster_name|toLower()}@${realm}",
             "type": "user",
             "configuration": "storm-env/storm_principal_name"
           },

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/stacks/HDP/2.0.6/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.0.6/kerberos.json
index 52e7ee0..7b1888b 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/kerberos.json
@@ -26,7 +26,7 @@
     {
       "name": "smokeuser",
       "principal": {
-        "value": "${cluster-env/smokeuser}-${cluster_name}@${realm}",
+        "value": "${cluster-env/smokeuser}-${cluster_name|toLower()}@${realm}",
         "type" : "user",
         "configuration": "cluster-env/smokeuser_principal_name",
         "local_username" : "${cluster-env/smokeuser}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/ECS/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/ECS/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/ECS/kerberos.json
index 213c964..9668354 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/ECS/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/ECS/kerberos.json
@@ -9,7 +9,7 @@
         {
           "name": "hdfs",
           "principal": {
-            "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}",
+            "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user" ,
             "configuration": "hadoop-env/hdfs_principal_name",
             "local_username" : "${hadoop-env/hdfs_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/HBASE/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/HBASE/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/HBASE/kerberos.json
index 1db82a3..20b10f7 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/HBASE/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3.ECS/services/HBASE/kerberos.json
@@ -12,7 +12,7 @@
         {
           "name": "hbase",
           "principal": {
-            "value": "${hbase-env/hbase_user}-${cluster_name}@${realm}",
+            "value": "${hbase-env/hbase_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "hbase-env/hbase_principal_name",
             "local_username": "${hbase-env/hbase_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/stacks/HDP/2.3.GlusterFS/services/ACCUMULO/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3.GlusterFS/services/ACCUMULO/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.3.GlusterFS/services/ACCUMULO/kerberos.json
index d621e05..678a2b5 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3.GlusterFS/services/ACCUMULO/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3.GlusterFS/services/ACCUMULO/kerberos.json
@@ -6,7 +6,7 @@
         {
           "name": "accumulo",
           "principal": {
-            "value": "${accumulo-env/accumulo_user}-${cluster_name}@${realm}",
+            "value": "${accumulo-env/accumulo_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "accumulo-env/accumulo_principal_name",
             "local_username": "${accumulo-env/accumulo_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/kerberos.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/kerberos.json b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/kerberos.json
index 61fe31e..0fec0ab 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/kerberos.json
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/ACCUMULO/kerberos.json
@@ -6,7 +6,7 @@
         {
           "name": "accumulo",
           "principal": {
-            "value": "${accumulo-env/accumulo_user}-${cluster_name}@${realm}",
+            "value": "${accumulo-env/accumulo_user}-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "accumulo-env/accumulo_principal_name",
             "local_username": "${accumulo-env/accumulo_user}"
@@ -48,7 +48,7 @@
         {
           "name": "accumulo_tracer",
           "principal": {
-            "value": "tracer-${cluster_name}@${realm}",
+            "value": "tracer-${cluster_name|toLower()}@${realm}",
             "type" : "user",
             "configuration": "accumulo-site/trace.user",
             "local_username": "${accumulo-env/accumulo_user}"

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
new file mode 100644
index 0000000..f877e85
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/IPAKerberosOperationHandlerTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+package org.apache.ambari.server.serveraction.kerberos;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.easymock.EasyMock;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+public class IPAKerberosOperationHandlerTest extends KerberosOperationHandlerTest {
+  private static final String DEFAULT_ADMIN_PRINCIPAL = "admin";
+  private static final String DEFAULT_ADMIN_PASSWORD = "Hadoop12345";
+
+  private static final String DEFAULT_REALM = "IPA01.LOCAL";
+
+  private static Injector injector;
+
+  private static boolean hasIpa = false;
+
+  private static final Map<String, String> KERBEROS_ENV_MAP = new HashMap<String, String>() {
+    {
+      put(IPAKerberosOperationHandler.KERBEROS_ENV_ENCRYPTION_TYPES, null);
+      put(IPAKerberosOperationHandler.KERBEROS_ENV_KDC_HOST, "localhost");
+      put(IPAKerberosOperationHandler.KERBEROS_ENV_ADMIN_SERVER_HOST, "localhost");
+      put(IPAKerberosOperationHandler.KERBEROS_ENV_USER_PRINCIPAL_GROUP, "");
+    }
+  };
+
+  @BeforeClass
+  public static void beforeClass() throws AmbariException {
+    injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        Configuration configuration = EasyMock.createNiceMock(Configuration.class);
+        expect(configuration.getServerOsFamily()).andReturn("redhat6").anyTimes();
+        replay(configuration);
+
+        bind(Clusters.class).toInstance(EasyMock.createNiceMock(Clusters.class));
+        bind(Configuration.class).toInstance(configuration);
+        bind(OsFamily.class).toInstance(EasyMock.createNiceMock(OsFamily.class));
+      }
+    });
+    if (System.getenv("HAS_IPA") != null) {
+      hasIpa = true;
+    }
+  }
+
+  @Test
+  public void testSetPrincipalPasswordExceptions() throws Exception {
+    if (!hasIpa) {
+      return;
+    }
+
+    IPAKerberosOperationHandler handler = injector.getInstance(IPAKerberosOperationHandler.class);
+    handler.open(new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD), DEFAULT_REALM, KERBEROS_ENV_MAP);
+    try {
+      handler.setPrincipalPassword(DEFAULT_ADMIN_PRINCIPAL, null);
+      Assert.fail("KerberosOperationException not thrown for null password");
+    } catch (Throwable t) {
+      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    }
+
+    try {
+      handler.setPrincipalPassword(DEFAULT_ADMIN_PRINCIPAL, "");
+      Assert.fail("KerberosOperationException not thrown for empty password");
+      handler.createPrincipal("", "1234", false);
+      Assert.fail("AmbariException not thrown for empty principal");
+    } catch (Throwable t) {
+      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    }
+
+    try {
+      handler.setPrincipalPassword(null, DEFAULT_ADMIN_PASSWORD);
+      Assert.fail("KerberosOperationException not thrown for null principal");
+    } catch (Throwable t) {
+      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    }
+
+    try {
+      handler.setPrincipalPassword("", DEFAULT_ADMIN_PASSWORD);
+      Assert.fail("KerberosOperationException not thrown for empty principal");
+    } catch (Throwable t) {
+      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    }
+  }
+
+  @Test
+  public void testCreateServicePrincipal_Exceptions() throws Exception {
+    if (!hasIpa) {
+      return;
+    }
+
+    IPAKerberosOperationHandler handler = new IPAKerberosOperationHandler();
+    handler.open(new PrincipalKeyCredential(DEFAULT_ADMIN_PRINCIPAL, DEFAULT_ADMIN_PASSWORD), DEFAULT_REALM, KERBEROS_ENV_MAP);
+
+    try {
+      handler.createPrincipal(DEFAULT_ADMIN_PRINCIPAL, null, false);
+      Assert.fail("KerberosOperationException not thrown for null password");
+    } catch (Throwable t) {
+      Assert.fail("KerberosOperationException thrown on null password with IPA");
+    }
+
+    try {
+      handler.createPrincipal(DEFAULT_ADMIN_PRINCIPAL, "", false);
+    } catch (Throwable t) {
+      Assert.fail("KerberosOperationException thrown for empty password");
+    }
+
+    try {
+      handler.createPrincipal(null, DEFAULT_ADMIN_PASSWORD, false);
+      Assert.fail("KerberosOperationException not thrown for null principal");
+    } catch (Throwable t) {
+      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    }
+
+    try {
+      handler.createPrincipal("", DEFAULT_ADMIN_PASSWORD, false);
+      Assert.fail("KerberosOperationException not thrown for empty principal");
+    } catch (Throwable t) {
+      Assert.assertEquals(KerberosOperationException.class, t.getClass());
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java
index cbfa4a3..ee2a671 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/VariableReplacementHelperTest.java
@@ -169,6 +169,8 @@ public class VariableReplacementHelperTest {
 
     Assert.assertEquals("hive.metastore.local=false,hive.metastore.uris=thrift://host1.unit.test:9083\\,thrift://host2.unit.test:9083\\,thrift://host3.unit.test:9083,hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_HOST@UNIT.TEST",
         helper.replaceVariables("hive.metastore.local=false,hive.metastore.uris=${clusterHostInfo/hive_metastore_host | each(thrift://%s:9083, \\\\,, \\s*\\,\\s*)},hive.metastore.sasl.enabled=true,hive.metastore.execute.setugi=true,hive.metastore.warehouse.dir=/apps/hive/warehouse,hive.exec.mode.local.auto=false,hive.metastore.kerberos.principal=hive/_HOST@${realm}", configurations));
+
+    Assert.assertEquals("test=unit.test", helper.replaceVariables("test=${realm|toLower()}", configurations));
   }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_2_1_3.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_2_1_3.json b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_2_1_3.json
index 09d1d0c..f3dbd38 100644
--- a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_2_1_3.json
+++ b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_2_1_3.json
@@ -21,7 +21,7 @@
       "configuration": "cluster-env/smokeuser_principal_name",
       "type": "user",
       "local_username": "${cluster-env/smokeuser}",
-      "value": "${cluster-env/smokeuser}-${cluster_name}@${realm}"
+      "value": "${cluster-env/smokeuser}-${cluster_name|toLower()}@${realm}"
     },
     "name": "smokeuser",
     "keytab": {
@@ -318,7 +318,7 @@
         "configuration": "hadoop-env/hdfs_principal_name",
         "type": "user",
         "local_username": "${hadoop-env/hdfs_user}",
-        "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}"
+        "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}"
       },
       "name": "hdfs",
       "keytab": {
@@ -370,7 +370,7 @@
         "configuration": "spark-defaults/spark.history.kerberos.principal",
         "type": "user",
         "local_username": "${spark-env/spark_user}",
-        "value": "${spark-env/spark_user}-${cluster_name}@${realm}"
+        "value": "${spark-env/spark_user}-${cluster_name|toLower()}@${realm}"
       },
       "name": "sparkuser",
       "keytab": {
@@ -411,7 +411,7 @@
         "configuration": "accumulo-env/accumulo_principal_name",
         "type": "user",
         "local_username": "${accumulo-env/accumulo_user}",
-        "value": "${accumulo-env/accumulo_user}-${cluster_name}@${realm}"
+        "value": "${accumulo-env/accumulo_user}-${cluster_name|toLower()}@${realm}"
       },
       "name": "accumulo",
       "keytab": {
@@ -451,7 +451,7 @@
         "configuration": "accumulo-site/trace.user",
         "type": "user",
         "local_username": "${accumulo-env/accumulo_user}",
-        "value": "tracer-${cluster_name}@${realm}"
+        "value": "tracer-${cluster_name|toLower()}@${realm}"
       },
       "name": "accumulo_tracer",
       "keytab": {
@@ -591,7 +591,7 @@
         "configuration": "hbase-env/hbase_principal_name",
         "type": "user",
         "local_username": "${hbase-env/hbase_user}",
-        "value": "${hbase-env/hbase_user}-${cluster_name}@${realm}"
+        "value": "${hbase-env/hbase_user}-${cluster_name|toLower()}@${realm}"
       },
       "name": "hbase",
       "keytab": {
@@ -940,7 +940,7 @@
       "principal": {
         "configuration": "storm-env/storm_principal_name",
         "type": "user",
-        "value": "${storm-env/storm_user}-${cluster_name}@${realm}"
+        "value": "${storm-env/storm_user}-${cluster_name|toLower()}@${realm}"
       },
       "name": "storm_components",
       "keytab": {

http://git-wip-us.apache.org/repos/asf/ambari/blob/476d87b7/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_no_hdfs.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_no_hdfs.json b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_no_hdfs.json
index 8f1d075..dcf5bbc 100644
--- a/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_no_hdfs.json
+++ b/ambari-server/src/test/resources/kerberos/test_kerberos_descriptor_no_hdfs.json
@@ -25,7 +25,7 @@
     {
       "name": "hdfs",
       "principal": {
-        "value": "${hadoop-env/hdfs_user}-${cluster_name}@${realm}",
+        "value": "${hadoop-env/hdfs_user}-${cluster_name|toLower()}@${realm}",
         "type": "user",
         "configuration": "hadoop-env/hdfs_principal_name",
         "local_username": "${hadoop-env/hdfs_user}"
@@ -46,7 +46,7 @@
     {
       "name": "smokeuser",
       "principal": {
-        "value": "${cluster-env/smokeuser}-${cluster_name}@${realm}",
+        "value": "${cluster-env/smokeuser}-${cluster_name|toLower()}@${realm}",
         "type": "user",
         "configuration": "cluster-env/smokeuser_principal_name",
         "local_username": "${cluster-env/smokeuser}"