HBASE-22116 Added keytab and principal support for HttpDoAsClient.

Signed-off-by: Toshihiro Suzuki <brfrn169@gmail.com>
This commit is contained in:
subrat.mishra 2019-06-10 14:05:56 +05:30 committed by Toshihiro Suzuki
parent e948402840
commit c9da465101
1 changed files with 77 additions and 26 deletions

View File

@ -18,20 +18,25 @@
*/ */
package org.apache.hadoop.hbase.thrift; package org.apache.hadoop.hbase.thrift;
import java.io.File;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException; import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetDecoder;
import java.security.Principal;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64; import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import javax.security.auth.Subject; import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.login.AppConfigurationEntry; import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration; import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginContext;
@ -66,11 +71,13 @@ public class HttpDoAsClient {
private static boolean secure = false; private static boolean secure = false;
static protected String doAsUser = null; static protected String doAsUser = null;
static protected String principal = null; static protected String principal = null;
static protected String keyTab = null;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (args.length < 3 || args.length > 4) { if (args.length < 3 || args.length > 6) {
System.out.println("Invalid arguments!"); System.out.println("Invalid arguments!");
System.out.println("Usage: HttpDoAsClient host port doAsUserName [security=true]"); System.out.println(
"Usage: HttpDoAsClient host port doAsUserName [security=true] [principal] [keytab]");
System.exit(-1); System.exit(-1);
} }
@ -79,7 +86,16 @@ public class HttpDoAsClient {
doAsUser = args[2]; doAsUser = args[2];
if (args.length > 3) { if (args.length > 3) {
secure = Boolean.parseBoolean(args[3]); secure = Boolean.parseBoolean(args[3]);
principal = getSubject().getPrincipals().iterator().next().getName(); if (args.length > 4) {
principal = args[4];
keyTab = args[5];
if (!new File(keyTab).exists()) {
System.err.printf("ERROR: KeyTab File %s not found %n", keyTab);
System.exit(-1);
}
} else {
principal = getSubject().getPrincipals().iterator().next().getName();
}
} }
final HttpDoAsClient client = new HttpDoAsClient(); final HttpDoAsClient client = new HttpDoAsClient();
@ -255,31 +271,66 @@ public class HttpDoAsClient {
* To authenticate the DemoClient, kinit should be invoked ahead. * To authenticate the DemoClient, kinit should be invoked ahead.
* Here we try to get the Kerberos credential from the ticket cache. * Here we try to get the Kerberos credential from the ticket cache.
*/ */
LoginContext context = new LoginContext("", new Subject(), null, LoginContext context;
new Configuration() {
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
Map<String, String> options = new HashMap<>();
options.put("useKeyTab", "false");
options.put("storeKey", "false");
options.put("doNotPrompt", "true");
options.put("useTicketCache", "true");
options.put("renewTGT", "true");
options.put("refreshKrb5Config", "true");
options.put("isInitiator", "true");
String ticketCache = System.getenv("KRB5CCNAME");
if (ticketCache != null) {
options.put("ticketCache", ticketCache);
}
options.put("debug", "true");
return new AppConfigurationEntry[]{ if (keyTab != null) {
new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", // To authenticate the HttpDoAsClient using principal and keyTab
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, Set<Principal> principals = new HashSet<>();
options)}; principals.add(new KerberosPrincipal(principal));
} Subject subject =
}); new Subject(false, principals, new HashSet<>(), new HashSet<>());
context = new LoginContext("", subject, null, new KerberosConfiguration(principal, keyTab));
} else {
/*
* To authenticate the HttpDoAsClient, kinit should be invoked ahead. Here we try to
* get the Kerberos credential from the ticket cache.
*/
context = new LoginContext("", new Subject(), null, new KerberosConfiguration());
}
context.login(); context.login();
return context.getSubject(); return context.getSubject();
} }
private static class KerberosConfiguration extends Configuration {
private String principal;
private String keyTab;
public KerberosConfiguration() {
// Empty constructor will have no principal or keyTab values
}
public KerberosConfiguration(String principal, String keyTab) {
this.principal = principal;
this.keyTab = keyTab;
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
Map<String, String> options = new HashMap<>();
if (principal != null && keyTab != null) {
options.put("principal", principal);
options.put("keyTab", keyTab);
options.put("useKeyTab", "true");
options.put("storeKey", "true");
} else {
options.put("useKeyTab", "false");
options.put("storeKey", "false");
}
options.put("doNotPrompt", "true");
options.put("useTicketCache", "true");
options.put("renewTGT", "true");
options.put("refreshKrb5Config", "true");
options.put("isInitiator", "true");
String ticketCache = System.getenv("KRB5CCNAME");
if (ticketCache != null) {
options.put("ticketCache", ticketCache);
}
options.put("debug", "true");
return new AppConfigurationEntry[] {
new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options) };
}
}
} }