Skip to content

Commit

Permalink
AMBARI-24879. kAdmin principal name is set on the GUI when enabling K…
Browse files Browse the repository at this point in the history
…erberos with MIT KDC using a new variable replacement function (#2593)
  • Loading branch information
smolnar82 committed Nov 12, 2018
1 parent 4eee0f5 commit c17ecd1
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 14 deletions.
Expand Up @@ -254,7 +254,7 @@ public boolean removePrincipal(String principal, boolean service) throws Kerbero
}

@Override
protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache) {
protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache, Map<String, String> kerberosConfiguration) {
return new String[]{
executableKinit,
"-c",
Expand Down
Expand Up @@ -111,7 +111,7 @@ public void open(PrincipalKeyCredential administratorCredentials, String realm,
// Pre-determine the paths to relevant Kerberos executables
executableKinit = getExecutable("kinit");

setOpen(init());
setOpen(init(kerberosConfiguration));
}

@Override
Expand Down Expand Up @@ -269,9 +269,11 @@ String getCredentialCacheFilePath() {
* @param executableKinit the absolute path to the kinit executable
* @param credentials the KDC adminisrator's credentials
* @param credentialsCache the absolute path to the expected location of the Kerberos ticket/credential cache file
* @param kerberosConfigurations a Map of key/value pairs containing data from the kerberos-env configuration set
* @throws KerberosOperationException in case there was any error during kinit command creation
* @return an array of Strings containing the command to execute
*/
protected abstract String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache);
protected abstract String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache, Map<String, String> kerberosConfigurations) throws KerberosOperationException;

/**
* Export the requested keytab entries for a given principal into the specified file.
Expand All @@ -294,7 +296,7 @@ String getCredentialCacheFilePath() {
* @return
* @throws KerberosOperationException
*/
protected boolean init() throws KerberosOperationException {
protected boolean init(Map<String, String> kerberosConfiguration) throws KerberosOperationException {
if (credentialsCacheFile != null) {
if (!credentialsCacheFile.delete()) {
LOG.debug("Failed to remove the orphaned cache file, {}", credentialsCacheFile.getAbsolutePath());
Expand All @@ -317,7 +319,7 @@ protected boolean init() throws KerberosOperationException {

PrincipalKeyCredential credentials = getAdministratorCredential();

ShellCommandUtil.Result result = executeCommand(getKinitCommand(executableKinit, credentials, credentialsCache),
ShellCommandUtil.Result result = executeCommand(getKinitCommand(executableKinit, credentials, credentialsCache, kerberosConfiguration),
environmentMap,
new InteractivePasswordHandler(String.valueOf(credentials.getKey()), null));

Expand Down
Expand Up @@ -94,6 +94,11 @@ public abstract class KerberosOperationHandler {
*/
public final static String KERBEROS_ENV_ADMIN_SERVER_HOST = "admin_server_host";

/**
* Kerberos-env configuration property name: kadmin_principal_name
*/
public final static String KERBEROS_ENV_KADMIN_PRINCIPAL_NAME = "kadmin_principal_name";

/**
* Kerberos-env configuration property name: executable_search_paths
*/
Expand Down
Expand Up @@ -19,12 +19,15 @@
package org.apache.ambari.server.serveraction.kerberos;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

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.kerberos.VariableReplacementHelper;
import org.apache.ambari.server.utils.ShellCommandUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
Expand All @@ -47,6 +50,9 @@ public class MITKerberosOperationHandler extends KDCKerberosOperationHandler {

@Inject
private Configuration configuration;

@Inject
private VariableReplacementHelper variableReplacementHelper;

/**
* A String containing user-specified attributes used when creating principals
Expand Down Expand Up @@ -333,16 +339,27 @@ else if (stdErr.contains("Missing parameters in krb5.conf required for kadmin cl
}

@Override
protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache) {
protected String[] getKinitCommand(String executableKinit, PrincipalKeyCredential credentials, String credentialsCache, Map<String, String> kerberosConfiguration) throws KerberosOperationException {
// kinit -c <path> -S kadmin/`hostname -f` <principal>
return new String[]{
executableKinit,
"-c",
credentialsCache,
"-S",
String.format("kadmin/%s", getAdminServerHost(false)),
credentials.getPrincipal()
};
try {
final String kadminPrincipalName = variableReplacementHelper.replaceVariables(kerberosConfiguration.get(KERBEROS_ENV_KADMIN_PRINCIPAL_NAME), buildReplacementsMap(kerberosConfiguration));
return new String[]{
executableKinit,
"-c",
credentialsCache,
"-S",
kadminPrincipalName,
credentials.getPrincipal()
};
} catch (AmbariException e) {
throw new KerberosOperationException("Error while getting 'kinit' command", e);
}
}

private Map<String, Map<String, String>> buildReplacementsMap(Map<String, String> kerberosConfiguration) {
final Map<String, Map<String, String>> replacementsMap = new HashMap<>();
replacementsMap.put("", kerberosConfiguration);
return replacementsMap;
}

@Override
Expand Down
Expand Up @@ -60,6 +60,7 @@ public class VariableReplacementHelper {
put("replace", new ReplaceValue());
put("append", new AppendFunction());
put("principalPrimary", new PrincipalPrimary());
put("stripPort", new StripPort());
}
};

Expand Down Expand Up @@ -432,4 +433,19 @@ public String perform(String[] args, String data, Map<String, Map<String, String
}
}
}

/**
* Strips out the port (if any) from a URL assuming the following input data layout
* <code>host[:port]</code>
*/
private static class StripPort implements Function {
@Override
public String perform(String[] args, String data, Map<String, Map<String, String>> replacementsMap) {
if (data == null) {
return null;
}
final int semicolonIndex = data.indexOf(":");
return semicolonIndex == -1 ? data : data.substring(0, semicolonIndex);
}
}
}
Expand Up @@ -265,6 +265,7 @@ public void testGetAdminServerHost() throws KerberosOperationException {

Map<String,String> config = new HashMap<>();
config.put("encryption_types", "aes des3-cbc-sha1 rc4 des-cbc-md5");
config.put(MITKerberosOperationHandler.KERBEROS_ENV_KADMIN_PRINCIPAL_NAME, "kadmin/kdc.example.com");

replayAll();

Expand Down
Expand Up @@ -196,6 +196,8 @@ public void testReplaceVariablesWithFunctions() throws AmbariException {
put("", new HashMap<String, String>() {{
put("delimited.data", "one,two,three,four");
put("realm", "UNIT.TEST");
put("admin_server_host", "c7401.ambari.apache.org");
put("admin_server_host_port", "c7401.ambari.apache.org:8080");
}});

put("kafka-broker", new HashMap<String, String>() {{
Expand Down Expand Up @@ -259,6 +261,9 @@ public void testReplaceVariablesWithFunctions() throws AmbariException {
assertEquals("test=unit.test", helper.replaceVariables("test=${realm|toLower()}", configurations));

assertEquals("PLAINTEXTSASL://localhost:6667", helper.replaceVariables("${kafka-broker/listeners|replace(\\bPLAINTEXT\\b,PLAINTEXTSASL)}", configurations));

assertEquals("kadmin/c7401.ambari.apache.org", helper.replaceVariables("kadmin/${admin_server_host|stripPort()}", configurations));
assertEquals("kadmin/c7401.ambari.apache.org", helper.replaceVariables("kadmin/${admin_server_host_port|stripPort()}", configurations));
}

@Test
Expand Down

0 comments on commit c17ecd1

Please sign in to comment.