上次说到hive cli和kerberos集成的问题,而访问hive的另一种方法就是使用hiveserver,hive 0.11之后为hiveserver2。hiveserver的可用性可以用beeline进行测试。
比如Connection con = DriverManager.getConnection("jdbc:hive2://host:10000/cdnlog;principal=hdfs/host@KERBEROS_HADOOP", "user1", "");
hiveserver有一个user impersonation的功能,可以把运行job的用户设置为提交job的用户,在hive0.11之前,这个参数是由hive.server2.enable.impersonation控制,hive0.11开始改成了hive.server2.enable.doAs(默认为true)。
hive 集成kerberos传入用户名的问题,在之前的博客已经提过。
由于线上使用jdbc连接hiveserver,在hiveserver2集成了kerberos之后需要做jdbc可用性的测试。
在使用jdbc+kerberos时,主要注意几个问题
1.链接字符串格式,其中user,password并不生效
jdbc:hive2://<host>:<port>/<db>;principal=<Server_Principal_of_HiveServer2>比如Connection con = DriverManager.getConnection("jdbc:hive2://host:10000/cdnlog;principal=hdfs/host@KERBEROS_HADOOP", "user1", "");
在传入hiveserver2时,用户并不是user1
2.在有tgt cache时,传入的用户为当前tgt的用户(可以通过klist查看)
3.principal的名称和hiveserver2的主机名需要一致
其中主要注意第一点。
可用下面的代码进行测试:
import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.DriverManager;
public class HiveJdbcClient {
private static String driverName = "org.apache.hive.jdbc.HiveDriver";
public static void main(String[] args) throws SQLException {
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(1);
}
Connection con = DriverManager.getConnection("jdbc:hive2://host:10000/cdnlog;principal=hdfs/host@KERBEROS_HADOOP", "ericni", "1234");
Statement stmt = con.createStatement();
String tableName = "dd_log";
stmt.execute("drop table if exists " + tableName);
String createSql = "create table " + tableName + " (tt string) LOCATION 'hdfs://bipcluster/tmp/dd_log' ";
stmt.execute(createSql);
System.out.println("create table sql is" + createSql);
}
}
通过上面的sql,发现最终hdfs文件系统中对应文件夹的属组并不是ericni(由于开启了doas,页不会是hdfs),而是tgt的用户。
查看执行的调用结果:
在建立连接时,调用了DriverManager类的getConnection的方法。
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
// Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
if (user != null) {
info.put("user", user); //调用java.util.Properties类的put方法,生成user的value
}
if (password != null) {
info.put("password", password); //生成password的value
}
return (getConnection(url, info, callerCL));
}
然后调用org.apache.hive.jdbc.HiveConnection类
首先HiveConnection类的构造函数会解析传入的url参数和传入的设置。
并调用openTransport方法,传入参数为(uri, connParams.getHost(), connParams.getPort(), connParams.getSessionVars());
并调用openTransport方法,传入参数为(uri, connParams.getHost(), connParams.getPort(), connParams.getSessionVars());
其中openTransport方法会判断是否是secure的方式
if (!sessConf.containsKey(HIVE_AUTH_TYPE)
|| !sessConf.get(HIVE_AUTH_TYPE).equals(HIVE_AUTH_SIMPLE)){
try {
if (sessConf.containsKey(HIVE_AUTH_PRINCIPAL)) {
transport = KerberosSaslHelper.getKerberosTransport(
sessConf.get(HIVE_AUTH_PRINCIPAL), host, transport);
} else {
String userName = sessConf.get(HIVE_AUTH_USER);
if ((userName == null) || userName.isEmpty()) {
userName = HIVE_ANONYMOUS_USER;
}
String passwd = sessConf.get(HIVE_AUTH_PASSWD);
if ((passwd == null) || passwd.isEmpty()) {
passwd = HIVE_ANONYMOUS_PASSWD;
}
transport = PlainSaslHelper.getPlainTransport(userName, passwd, transport);
}
} catch (SaslException e) {
throw new SQLException("Could not establish secure connection to "
+ uri + ": " + e.getMessage(), " 08S01");
}
}
在上面的代码中,可以看到当sessConf中含有HIVE_AUTH_PRINCIPAL(即principal)关键字时,会调用KerberosSaslHelper类的getKerberosTransport方法,返回一个TTransport 对象,此时用户名和密码并不会传入,相反,传入的依次是principal,host和TTransport类。
关于在jdbc中怎么使用kerberos做用户的验证放在后面的文章中讲解。
转载于:https://blog.51cto.com/caiguangguang/1382877