package com.thinkbiganalytics.kerberos;
/*-
* #%L
* thinkbig-kerberos-test-client
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed 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.
* #L%
*/
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hive.jdbc.HiveConnection;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
/**
*/
public class TestKerberosKinit {
private static final String ENVIRONMENT_HDP = "HDP";
private static final String ENVIRONMENT_CLOUDERA = "CLOUDERA";
private static final String DRIVER_NAME = "org.apache.hive.jdbc.HiveDriver";
public static void main(String[] args) throws Exception {
final TestKerberosKinit testKerberosKinit = new TestKerberosKinit();
Scanner scanner = new Scanner(System.in);
System.out.println(" ");
System.out.print("Which environment are you in? Enter 1 for HDP or 2 for Cloudera: ");
String environmentCode = scanner.nextLine();
if (StringUtils.isEmpty(environmentCode)) {
environmentCode = "1";
}
String environment;
switch (environmentCode) {
case "1":
environment = ENVIRONMENT_HDP;
break;
case "2":
environment = ENVIRONMENT_CLOUDERA;
break;
default:
throw new Exception("Invalid environment code");
}
System.out.println(" ");
System.out.println("Hit enter to default to: /etc/hadoop/conf/core-site.xml,/etc/hadoop/conf/hdfs-site.xml,/usr/hdp/current/hive-client/conf/hive-site.xml");
System.out.print("Please enter the list of configuration resources: ");
String configResources = scanner.nextLine();
if (StringUtils.isEmpty(configResources)) {
configResources = "/etc/hadoop/conf/core-site.xml,/etc/hadoop/conf/hdfs-site.xml,/usr/hdp/current/hive-client/conf/hive-site.xml";
}
System.out.println(" ");
System.out.println("Hit enter to default to: /etc/security/keytabs/hive-thinkbig.headless.keytab");
System.out.print("Please enter the keytab file location: ");
String keytab = scanner.nextLine();
if (StringUtils.isEmpty(keytab)) {
keytab = "/etc/security/keytabs/hive-thinkbig.headless.keytab";
}
System.out.println(" ");
System.out.println("Hit enter to default to: hive/sandbox.hortonworks.com@sandbox.hortonworks.com");
System.out.print("Please enter the real user principal name: ");
String realUserPrincipal = scanner.nextLine();
if (StringUtils.isEmpty(realUserPrincipal)) {
realUserPrincipal = "hive/sandbox.hortonworks.com@sandbox.hortonworks.com";
}
System.out.println(" ");
System.out.println("Please enter Y/N (default is N)");
System.out.print("Do you want to test with a proxy user: ");
String proxyUser = scanner.nextLine();
if (StringUtils.isEmpty(realUserPrincipal)) {
proxyUser = "N";
}
System.out.println(" ");
System.out.println("Hit enter to default to: hdfs://sandbox.hortonworks.com:8020");
System.out.print("Please enter the HDFS URL: ");
String hdfsUrl = scanner.nextLine();
if (StringUtils.isEmpty(hdfsUrl)) {
hdfsUrl = "hdfs://sandbox.hortonworks.com:8020";
}
System.out.println(" ");
System.out.println("Hit enter to default to: jdbc:hive2://localhost:10000/default");
System.out.print("Please enter the Hive base connection string: ");
String hiveHost = scanner.nextLine();
if (StringUtils.isEmpty(hiveHost)) {
hiveHost = "jdbc:hive2://localhost:10000/default";
}
String proxyUserName = null;
if ("Y".equalsIgnoreCase(proxyUser)) {
System.out.println(" ");
System.out.print("Please enter the proxy user: ");
proxyUserName = scanner.next();
}
System.out.println(" ");
System.out.println("Executing Kinit to generate a kerberos ticket");
if ("Y".equalsIgnoreCase(proxyUser)) {
System.out.println("Testing with the proxy user: " + proxyUserName);
testKerberosKinit.testHdfsWithUserImpersonation(configResources, keytab, realUserPrincipal, proxyUserName, environment, hdfsUrl);
//testKerberosKinit.testHiveJdbcConnectionWithUserImpersonation(configResources, keytab, realUserPrincipal, proxyUserName);
testKerberosKinit.testHiveJdbcConnection(configResources, keytab, realUserPrincipal, proxyUserName, hiveHost);
} else {
System.out.println("No Proxy User");
testKerberosKinit.testHdfsAsKerberosUser(configResources, keytab, realUserPrincipal, environment, hdfsUrl);
testKerberosKinit.testHiveJdbcConnection(configResources, keytab, realUserPrincipal, null, hiveHost);
}
}
private static Configuration createConfigurationFromList(String configurationFiles) {
Configuration config = new Configuration();
String[] resources = configurationFiles.split(",");
for (String resource : resources) {
config.addResource(new Path(resource));
}
return config;
}
private static UserGroupInformation generateKerberosTicket(Configuration configuration, String keytabLocation, String principal) throws IOException {
System.setProperty("sun.security.krb5.debug", "false");
configuration.set("hadoop.security.authentication", "Kerberos");
UserGroupInformation.setConfiguration(configuration);
System.out.println("Generating Kerberos ticket for principal: " + principal + " at key tab location: " + keytabLocation);
return UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, keytabLocation);
}
private void testHdfsWithUserImpersonation(final String configResources, final String keytab, final String principal, String proxyUser, final String environment, final String hdfsUrl) {
final String path = "/user";
try {
final Configuration configuration = TestKerberosKinit.createConfigurationFromList(configResources);
UserGroupInformation realugi = TestKerberosKinit.generateKerberosTicket(configuration, keytab, principal);
System.out.println(" ");
System.out.println("Sucessfully got a kerberos ticket in the JVM");
System.out.println("current user is: " + realugi.getUserName());
UserGroupInformation ugiProxy = UserGroupInformation.createProxyUser(proxyUser, realugi);
System.out.println("proxy user is: " + ugiProxy.getUserName());
ugiProxy.doAs(new PrivilegedExceptionAction<Object>() {
public Object run() {
try {
searchHDFS(configuration, environment, path, hdfsUrl);
} catch (Exception e) {
throw new RuntimeException("Error testing HDFS with Kerberos Hive Impersonation", e);
}
return null;
}
});
} catch (Exception e) {
System.out.println("Error testing HDFS\n\n");
e.printStackTrace();
}
}
private void testHdfsAsKerberosUser(final String configResources, final String keytab, final String principal, final String environment, final String hdfsUrl) {
final String path = "/user";
try {
final Configuration configuration = TestKerberosKinit.createConfigurationFromList(configResources);
UserGroupInformation realugi = TestKerberosKinit.generateKerberosTicket(configuration, keytab, principal);
System.out.println(" ");
System.out.println("Sucessfully got a kerberos ticket in the JVM");
System.out.println("current user is: " + realugi.getUserName());
realugi.doAs(new PrivilegedExceptionAction<Object>() {
public Object run() {
try {
searchHDFS(configuration, environment, path, hdfsUrl);
} catch (Exception e) {
throw new RuntimeException("Error testing HDFS with Kerberos", e);
}
return null;
}
});
} catch (Exception e) {
System.out.println("Error testing HDFS\n\n");
e.printStackTrace();
}
}
private void searchHDFS(Configuration configuration, final String environment, String hdfsPath, String hdfsUrl) throws Exception {
configuration.set("fs.file.impl", org.apache.hadoop.fs.LocalFileSystem.class.getName());
configuration.set("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class.getName());
FileSystem fs = FileSystem.get(configuration);
if (environment.equalsIgnoreCase(ENVIRONMENT_CLOUDERA)) {
FileStatus[] status = fs.listStatus(new Path(hdfsUrl + hdfsPath));
System.out.println("File Count: " + status.length);
} else {
if (environment.equalsIgnoreCase(ENVIRONMENT_HDP)) {
FileStatus[] status = fs.listStatus(new Path(hdfsUrl + hdfsPath));
System.out.println("File Count: " + status.length);
}
}
}
private void testHiveJdbcConnection(final String configResources, final String keytab, final String realUserPrincipal, final String proxyUser, final String hiveHostName) throws Exception {
final Configuration configuration = TestKerberosKinit.createConfigurationFromList(configResources);
UserGroupInformation realugi = TestKerberosKinit.generateKerberosTicket(configuration, keytab, realUserPrincipal);
System.out.println(" ");
System.out.println("Sucessfully got a kerberos ticket in the JVM");
HiveConnection realUserConnection = (HiveConnection) realugi.doAs(new PrivilegedExceptionAction<Connection>() {
public Connection run() {
Connection connection;
try {
Class.forName(DRIVER_NAME);
String url = hiveHostName;
if (proxyUser != null) {
url = url + ";hive.server2.proxy.user=" + proxyUser;
}
System.out.println("Hive URL: " + url);
connection = DriverManager.getConnection(url);
Class.forName(DRIVER_NAME);
System.out.println("creating statement");
Statement stmt = connection.createStatement();
String sql = "show databases";
ResultSet res = stmt.executeQuery(sql);
System.out.println(" \n");
System.out.println("Executing the Hive Query:");
System.out.println(" ");
System.out.println("List of Databases");
while (res.next()) {
System.out.println(res.getString(1));
}
} catch (Exception e) {
throw new RuntimeException("Error creating connection with proxy user", e);
}
return connection;
}
});
}
}