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 2018/08/30 20:19:44 UTC

[ambari] branch branch-2.7 updated: [AMBARI-24522] Cannot connect to MIT KDC admin server when port is specified in kerberos-env/admin_server_host

This is an automated email from the ASF dual-hosted git repository.

rlevas pushed a commit to branch branch-2.7
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/branch-2.7 by this push:
     new 50d771e  [AMBARI-24522] Cannot connect to MIT KDC admin server when port is specified in kerberos-env/admin_server_host
50d771e is described below

commit 50d771e30216e3a4b48cf9081bc79c8c86de7e69
Author: Robert Levas <rl...@hortonworks.com>
AuthorDate: Tue Aug 21 17:29:41 2018 -0400

    [AMBARI-24522] Cannot connect to MIT KDC admin server when port is specified in kerberos-env/admin_server_host
---
 .../kerberos/IPAKerberosOperationHandler.java      |  4 +-
 .../kerberos/KDCKerberosOperationHandler.java      | 35 ++++++++++++++--
 .../kerberos/MITKerberosOperationHandler.java      |  4 +-
 .../kerberos/IPAKerberosOperationHandlerTest.java  | 45 +++++++++++++++++++++
 .../kerberos/MITKerberosOperationHandlerTest.java  | 46 ++++++++++++++++++++++
 5 files changed, 127 insertions(+), 7 deletions(-)

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
index 64a1bb8..be7b96d 100644
--- 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
@@ -279,8 +279,8 @@ public class IPAKerberosOperationHandler extends KDCKerberosOperationHandler {
     }
 
     String[] createKeytabFileCommand = (StringUtils.isEmpty(encryptionTypeSpec))
-        ? new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(), "-p", principal, "-k", keytabFileDestinationPath}
-        : new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(), "-e", encryptionTypeSpec, "-p", principal, "-k", keytabFileDestinationPath};
+        ? new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(true), "-p", principal, "-k", keytabFileDestinationPath}
+        : new String[]{executableIpaGetKeytab, "-s", getAdminServerHost(true), "-e", encryptionTypeSpec, "-p", principal, "-k", keytabFileDestinationPath};
 
     ShellCommandUtil.Result result = executeCommand(createKeytabFileCommand);
     if (!result.isSuccessful()) {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
index bf3ac22..9936f43 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KDCKerberosOperationHandler.java
@@ -28,6 +28,8 @@ import java.util.Set;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
+import org.apache.ambari.server.utils.HTTPUtils;
+import org.apache.ambari.server.utils.HostAndPort;
 import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.apache.commons.collections.MapUtils;
 import org.apache.directory.server.kerberos.shared.keytab.Keytab;
@@ -50,6 +52,11 @@ abstract class KDCKerberosOperationHandler extends KerberosOperationHandler {
   private String adminServerHost = null;
 
   /**
+   * The FQDN and port where KDC administration server is
+   */
+  private String adminServerHostAndPort = null;
+
+  /**
    * A map of principal names to {@link Keytab} entries to ensure a Keyab file is not created/exported
    * for the same principal more than once.
    */
@@ -83,7 +90,22 @@ abstract class KDCKerberosOperationHandler extends KerberosOperationHandler {
     super.open(administratorCredentials, realm, kerberosConfiguration);
 
     if (kerberosConfiguration != null) {
-      adminServerHost = kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST);
+      // Spit the host and port from the the admin_server_host value
+      String value = kerberosConfiguration.get(KERBEROS_ENV_ADMIN_SERVER_HOST);
+      HostAndPort hostAndPort = HTTPUtils.getHostAndPortFromProperty(value);
+
+      // hostAndPort will be null if the value is not in the form of host:port
+      if (hostAndPort == null) {
+        // host-only and host and port values are the same since there is no port
+        // both are equal to the value from the property
+        adminServerHost = value;
+        adminServerHostAndPort = value;
+      } else {
+        // host-only is the split value;
+        // host and port value is the value from the property
+        adminServerHost = hostAndPort.host;
+        adminServerHostAndPort = value;
+      }
     }
 
     // Pre-determine the paths to relevant Kerberos executables
@@ -106,6 +128,7 @@ abstract class KDCKerberosOperationHandler extends KerberosOperationHandler {
     executableKinit = null;
     cachedKeytabs = null;
     adminServerHost = null;
+    adminServerHostAndPort = null;
 
     super.close();
   }
@@ -225,8 +248,14 @@ abstract class KDCKerberosOperationHandler extends KerberosOperationHandler {
     return super.executeCommand(command, _envp, interactiveHandler);
   }
 
-  String getAdminServerHost() {
-    return adminServerHost;
+  /**
+   * Returns the KDC administration server host value (with or without the port)
+   *
+   * @param includePort <code>true</code> to include the port (if available); <code>false</code> to exclude the port
+   * @return the KDC administration server host value (with or without the port)
+   */
+  String getAdminServerHost(boolean includePort) {
+    return (includePort) ? adminServerHostAndPort : adminServerHost;
   }
 
   String getCredentialCacheFilePath() {
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
index bbcd6e8..254f705 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandler.java
@@ -241,7 +241,7 @@ public class MITKerberosOperationHandler extends KDCKerberosOperationHandler {
     }
 
     // Add explicit KDC admin host, if available
-    String adminSeverHost = getAdminServerHost();
+    String adminSeverHost = getAdminServerHost(true);
     if (!StringUtils.isEmpty(adminSeverHost)) {
       command.add("-s");
       command.add(adminSeverHost);
@@ -340,7 +340,7 @@ public class MITKerberosOperationHandler extends KDCKerberosOperationHandler {
         "-c",
         credentialsCache,
         "-S",
-        String.format("kadmin/%s", getAdminServerHost()),
+        String.format("kadmin/%s", getAdminServerHost(false)),
         credentials.getPrincipal()
     };
   }
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
index f9ee5b7..44c7a36 100644
--- 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
@@ -19,25 +19,33 @@
 package org.apache.ambari.server.serveraction.kerberos;
 
 import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.newCapture;
 import static org.easymock.EasyMock.replay;
 
 import java.lang.reflect.Method;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
 import org.easymock.EasyMock;
 import org.junit.BeforeClass;
+import org.junit.Test;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
+import junit.framework.Assert;
+
 public class IPAKerberosOperationHandlerTest extends KDCKerberosOperationHandlerTest {
 
   private static Injector injector;
@@ -67,6 +75,43 @@ public class IPAKerberosOperationHandlerTest extends KDCKerberosOperationHandler
     });
   }
 
+  @Test
+  public void testGetAdminServerHost() throws KerberosOperationException {
+    ShellCommandUtil.Result kinitResult = createMock(ShellCommandUtil.Result.class);
+    expect(kinitResult.isSuccessful()).andReturn(true).anyTimes();
+
+    Capture<String[]> capturedKinitCommand = newCapture(CaptureType.ALL);
+
+    IPAKerberosOperationHandler handler = createMockedHandler(methodExecuteCommand);
+    expect(handler.executeCommand(capture(capturedKinitCommand), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(kinitResult)
+        .anyTimes();
+
+
+    Map<String,String> config = new HashMap<>();
+    config.put("encryption_types", "aes des3-cbc-sha1 rc4 des-cbc-md5");
+
+    replayAll();
+
+    config.put("admin_server_host", "kdc.example.com");
+    handler.open(getAdminCredentials(), DEFAULT_REALM, config);
+    Assert.assertEquals("kdc.example.com", handler.getAdminServerHost(false));
+    Assert.assertEquals("kdc.example.com", handler.getAdminServerHost(true));
+    handler.close();
+
+    config.put("admin_server_host", "kdc.example.com:749");
+    handler.open(getAdminCredentials(), DEFAULT_REALM, config);
+    Assert.assertEquals("kdc.example.com", handler.getAdminServerHost(false));
+    Assert.assertEquals("kdc.example.com:749", handler.getAdminServerHost(true));
+    handler.close();
+
+    verifyAll();
+
+    Assert.assertTrue(capturedKinitCommand.hasCaptured());
+    List<String[]> capturedValues = capturedKinitCommand.getValues();
+    Assert.assertEquals(2, capturedValues.size());
+  }
+
   @Override
   protected IPAKerberosOperationHandler createMockedHandler(Method... mockedMethods) {
     IPAKerberosOperationHandler handler = createMockBuilder(IPAKerberosOperationHandler.class)
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandlerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandlerTest.java
index c7c26c3..dd3a3c3 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandlerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/MITKerberosOperationHandlerTest.java
@@ -26,6 +26,7 @@ import static org.easymock.EasyMock.newCapture;
 import java.lang.reflect.Method;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.ambari.server.configuration.Configuration;
@@ -34,6 +35,7 @@ import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.utils.ShellCommandUtil;
 import org.easymock.Capture;
+import org.easymock.CaptureType;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -248,6 +250,50 @@ public class MITKerberosOperationHandlerTest extends KDCKerberosOperationHandler
     verifyAll();
   }
 
+  @Test
+  public void testGetAdminServerHost() throws KerberosOperationException {
+    ShellCommandUtil.Result kinitResult = createMock(ShellCommandUtil.Result.class);
+    expect(kinitResult.isSuccessful()).andReturn(true).anyTimes();
+
+    Capture<String[]> capturedKinitCommand = newCapture(CaptureType.ALL);
+
+    MITKerberosOperationHandler handler = createMockedHandler(methodExecuteCommand);
+    expect(handler.executeCommand(capture(capturedKinitCommand), anyObject(Map.class), anyObject(KDCKerberosOperationHandler.InteractivePasswordHandler.class)))
+        .andReturn(kinitResult)
+        .anyTimes();
+
+
+    Map<String,String> config = new HashMap<>();
+    config.put("encryption_types", "aes des3-cbc-sha1 rc4 des-cbc-md5");
+
+    replayAll();
+
+    config.put("admin_server_host", "kdc.example.com");
+    handler.open(getAdminCredentials(), DEFAULT_REALM, config);
+    Assert.assertEquals("kdc.example.com", handler.getAdminServerHost(false));
+    Assert.assertEquals("kdc.example.com", handler.getAdminServerHost(true));
+    handler.close();
+
+    config.put("admin_server_host", "kdc.example.com:749");
+    handler.open(getAdminCredentials(), DEFAULT_REALM, config);
+    Assert.assertEquals("kdc.example.com", handler.getAdminServerHost(false));
+    Assert.assertEquals("kdc.example.com:749", handler.getAdminServerHost(true));
+    handler.close();
+
+    verifyAll();
+
+    Assert.assertTrue(capturedKinitCommand.hasCaptured());
+    List<String[]> capturedValues = capturedKinitCommand.getValues();
+    Assert.assertEquals(2, capturedValues.size());
+
+    // The capture values will be an array of strings used to build the command:
+    //   ["/usr/bin/kinit", "-c", "SOME_FILE_PATH", "-S", "SERVER_PRINCIPAL", "CLIENT_PRINCIPAL"]
+    // We are interested in the 4th item in the array - the service's principal.
+    // It must not contain the port else authentication will fail
+    Assert.assertEquals("kadmin/kdc.example.com", capturedValues.get(0)[4]);
+    Assert.assertEquals("kadmin/kdc.example.com", capturedValues.get(1)[4]);
+  }
+
   @Override
   protected MITKerberosOperationHandler createMockedHandler(Method... mockedMethods) {
     MITKerberosOperationHandler handler = createMockBuilder(MITKerberosOperationHandler.class)