hive0.11 hiveserver custom認証バグ
13228 ワード
最近hive 0をテストしています.11 hiveserverで出会った認証に関するバグです.具体的には、構成でcustomの認証方式を指定した場合、beelineでhiveserver 2に接続し、接続hang住を発見します.hive構成:
hiveserverのログを表示すると、次のエラーが表示されます.
注釈を外すserver2.authenticationの構成(つまりデフォルトのnoneを使用)は正常です.これは実はhive 0です.11.0のバグ、hive 0.13.0のfix,bug id:
https://issues.apache.org/jira/browse/HIVE-4778次に具体的なクラスを分析する:org.apache.hive.service.auth.HiveAuthFactoryにおけるAuthTypesは、複数の認証方法(NONE,LDAP,KERBEROS,CUSTOM,PAM(hive 0.11ではサポートされていない)を定義するここではCUSTOM、userおよびpasswordに基づく認証方式を用い、P a s s s s s w d AuthenticationProviderおよびCustomAuthenticationProviderImplクラス1)orgに関する.apache.hive.service.auth.PasswdAuthenticationProviderはユーザー名とパスワードの検証に基づくインタフェースで、主に抽象的な方法Authenticate(パラメータはユーザー名とパスワード)2)orgを定義している.apache.hive.service.auth.A n o n y m o u s A u t h e n t i c a tionProviderImplクラスはPasswdAuthenticationProviderインタフェースを実現し、空のAuthenticateメソッド(直接return)3)orgを提供する.apache.hive.service.auth.AuthenticationProviderFactoryはAuthMethodsのenumクラスを定義し、有効な認証方法(hive 0.13:LDAP/PAM/USTOM/ONE、hive 0.11:LDAP/USTOM/ONE)を定義し、対応するパッケージを提供するとともに、対応するAuthMethodsの具体的な実装クラスを返すgetAuthenticationProviderメソッドを定義した.
4)org.apache.hive.service.auth.I s t o m A u t h e n t i c a t i o n P r o v i d e r I m p l P a s s s s w dAuthenticationProviderインタフェースの具体的な実装クラスはhive 0にある.13の実装:
hive0.11の実装:
違いはcustomHandlerClassの取得方法です.ここでは手動でテストします.
HiveConfが使用することがわかる.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.varnameの場合customHandlerClassの結果は、class comのような具体的な実装クラス(hive.server 2.custom.authentication.classが設定クラス)である.vipshop.hive.service.AuthWithPasswdは、HiveConfを使用する.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.name()の場合、インタフェース、すなわちinterface orgが戻る.apache.hive.service.auth.P a s s s w dAuthenticationProviderもう一度ReflectionUtilsを見てみましょう.新Instanceメソッド:
hive 0.11時ここではapache.hive.service.auth.PasswdAuthenticationProvider,org.apache.hive.service.auth.PasswdAuthenticationProviderはインタフェースであり、コンストラクション関数を定義していないため、例外が放出されます.認証の構成はいつロードされますか?エラー・スタックをエラー・スタックとして表示するには、次のコマンドを使用してhiveserverのdebug logを開きます.
hiveserver 2が正常に起動すると、ThriftBinaryCLIServiceサービスがデフォルトで開始されます.ThriftBinaryCLIServiceクラスのrunメソッド:
一方、HiveAuthFactoryのコンストラクション関数では、hiveの構成が解析され、対応するhiveserverの認証設定が取得されます.
getAuthTransFactoryメソッドはauthType-Strが有効値であるかどうかを判断します.そうしないと異常を投げ出して起動を終了します.
hive.server2.authentication a
CUSTOM
hive.server2.custom.authentication.class
com.vipshop.hive.service.AuthWithPasswd
hiveserverのログを表示すると、次のエラーが表示されます.
15/01/08 17:54:59 ERROR server.TThreadPoolServer: Error occurred during processing of message.
java.lang.RuntimeException: java.lang.NoSuchMethodException: org.apache.hive.service.auth.PasswdAuthenticationProvider.()
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:131)
at org.apache.hive.service.auth.CustomAuthenticationProviderImpl.(CustomAuthenticationProviderImpl.java:52)
at org.apache.hive.service.auth.AuthenticationProviderFactory.getAuthenticationProvider(AuthenticationProviderFactory.java:62)
at org.apache.hive.service.auth.PlainSaslHelper$PlainServerCallbackHandler.handle(PlainSaslHelper.java:73)
at org.apache.hive.service.auth.PlainSaslServer.evaluateResponse(PlainSaslServer.java:102)
at org.apache.thrift.transport.TSaslTransport$SaslParticipant.evaluateChallengeOrResponse(TSaslTransport.java:509)
at org.apache.thrift.transport.TSaslTransport.open(TSaslTransport.java:264)
at org.apache.thrift.transport.TSaslServerTransport.open(TSaslServerTransport.java:41)
at org.apache.thrift.transport.TSaslServerTransport$Factory.getTransport(TSaslServerTransport.java:216)
at org.apache.thrift.server.TThreadPoolServer$WorkerProcess.run(TThreadPoolServer.java:189)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NoSuchMethodException: org.apache.hive.service.auth.PasswdAuthenticationProvider.()
at java.lang.Class.getConstructor0(Class.java:2706)
at java.lang.Class.getDeclaredConstructor(Class.java:1985)
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:125)
... 12 more
注釈を外すserver2.authenticationの構成(つまりデフォルトのnoneを使用)は正常です.これは実はhive 0です.11.0のバグ、hive 0.13.0のfix,bug id:
https://issues.apache.org/jira/browse/HIVE-4778次に具体的なクラスを分析する:org.apache.hive.service.auth.HiveAuthFactoryにおけるAuthTypesは、複数の認証方法(NONE,LDAP,KERBEROS,CUSTOM,PAM(hive 0.11ではサポートされていない)を定義するここではCUSTOM、userおよびpasswordに基づく認証方式を用い、P a s s s s s w d AuthenticationProviderおよびCustomAuthenticationProviderImplクラス1)orgに関する.apache.hive.service.auth.PasswdAuthenticationProviderはユーザー名とパスワードの検証に基づくインタフェースで、主に抽象的な方法Authenticate(パラメータはユーザー名とパスワード)2)orgを定義している.apache.hive.service.auth.A n o n y m o u s A u t h e n t i c a tionProviderImplクラスはPasswdAuthenticationProviderインタフェースを実現し、空のAuthenticateメソッド(直接return)3)orgを提供する.apache.hive.service.auth.AuthenticationProviderFactoryはAuthMethodsのenumクラスを定義し、有効な認証方法(hive 0.13:LDAP/PAM/USTOM/ONE、hive 0.11:LDAP/USTOM/ONE)を定義し、対応するパッケージを提供するとともに、対応するAuthMethodsの具体的な実装クラスを返すgetAuthenticationProviderメソッドを定義した.
public static PasswdAuthenticationProvider getAuthenticationProvider(AuthMethods authMethod)
throws AuthenticationException {
if (authMethod.equals(AuthMethods.LDAP)) {
return new LdapAuthenticationProviderImpl();
}
else if (authMethod.equals(AuthMethods.PAM)) {
return new PamAuthenticationProviderImpl();
}
else if (authMethod.equals(AuthMethods.CUSTOM)) {
return new CustomAuthenticationProviderImpl();
}
else if (authMethod.equals(AuthMethods.NONE)) {
return new AnonymousAuthenticationProviderImpl();
}
else {
throw new AuthenticationException("Unsupported authentication method");
}
}
4)org.apache.hive.service.auth.I s t o m A u t h e n t i c a t i o n P r o v i d e r I m p l P a s s s s w dAuthenticationProviderインタフェースの具体的な実装クラスはhive 0にある.13の実装:
public class CustomAuthenticationProviderImpl implements PasswdAuthenticationProvider {
Class extends PasswdAuthenticationProvider> customHandlerClass;
PasswdAuthenticationProvider customProvider;
@SuppressWarnings("unchecked")
CustomAuthenticationProviderImpl () {
HiveConf conf = new HiveConf();
this.customHandlerClass = (Class extends PasswdAuthenticationProvider>)
conf.getClass(
HiveConf.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.varname, // hive.server2.custom.authentication.class
PasswdAuthenticationProvider.class);
//HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS("hive.server2.custom.authentication.class", null),
this.customProvider =
ReflectionUtils.newInstance(this.customHandlerClass, conf); // , class
}
@Override
public void Authenticate(String user, String password) // Authenticate ,
throws AuthenticationException {
this.customProvider.Authenticate(user, password);
}
}
hive0.11の実装:
public class CustomAuthenticationProviderImpl
implements PasswdAuthenticationProvider {
Class extends PasswdAuthenticationProvider> customHandlerClass;
PasswdAuthenticationProvider customProvider;
@SuppressWarnings("unchecked")
CustomAuthenticationProviderImpl () {
HiveConf conf = new HiveConf();
this.customHandlerClass = (Class extends PasswdAuthenticationProvider>)
conf.getClass(
HiveConf.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.name(), // HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS
PasswdAuthenticationProvider.class);
this.customProvider =
ReflectionUtils.newInstance(this.customHandlerClass, conf);
}
@Override
public void Authenticate(String user, String password)
throws AuthenticationException {
this.customProvider.Authenticate(user, password);
}
}
違いはcustomHandlerClassの取得方法です.ここでは手動でテストします.
import java.lang.*;
public class HiveConf{
public static enum ConfVars {
PLAN_SERIALIZATION("hive.plan.serialization.format","kryo"),
HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS("hive.server2.custom.authentication.class", null),
;
public final String varname;
public final String defaultVal;
ConfVars(String varname, String defaultVal) {
this.varname = varname;
this.defaultVal = defaultVal;
}
public String toString() {
return varname;
}
}
public static void main(String args[]) {
System.out.println("ConfVars List:");
for(ConfVars c:ConfVars.values()){ //ConfVars.values() enum
System.out.println(c + " is: " + c);
//hive.server2.custom.authentication.class is: hive.server2.custom.authentication.class
System.out.println(c + " varname: " + c.varname); // varname enum , name() enum
//hive.server2.custom.authentication.class varname: hive.server2.custom.authentication.class
System.out.println(c + " name(): " + c.name());
//hive.server2.custom.authentication.class name(): HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS
}
System.out.println(HiveConf.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.name()); //HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS
System.out.println(HiveConf.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.varname); //hive.server2.custom.authentication.class
}
}
HiveConfが使用することがわかる.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.varnameの場合customHandlerClassの結果は、class comのような具体的な実装クラス(hive.server 2.custom.authentication.classが設定クラス)である.vipshop.hive.service.AuthWithPasswdは、HiveConfを使用する.ConfVars.HIVE_SERVER2_CUSTOM_AUTHENTICATION_CLASS.name()の場合、インタフェース、すなわちinterface orgが戻る.apache.hive.service.auth.P a s s s w dAuthenticationProviderもう一度ReflectionUtilsを見てみましょう.新Instanceメソッド:
private static final Class>[] EMPTY_ARRAY = new Class[]{};
....
public static T newInstance(Class theClass, Configuration conf) {
T result;
try {
Constructor meth = (Constructor) CONSTRUCTOR_CACHE.get(theClass);
if (meth == null) {
meth = theClass.getDeclaredConstructor(EMPTY_ARRAY); //
meth.setAccessible(true);
CONSTRUCTOR_CACHE.put(theClass, meth);
}
result = meth.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
setConf(result, conf);
return result;
}
hive 0.11時ここではapache.hive.service.auth.PasswdAuthenticationProvider,org.apache.hive.service.auth.PasswdAuthenticationProviderはインタフェースであり、コンストラクション関数を定義していないため、例外が放出されます.認証の構成はいつロードされますか?エラー・スタックをエラー・スタックとして表示するには、次のコマンドを使用してhiveserverのdebug logを開きます.
bin/hiveserver2 -hiveconf hive.root.logger=DEBUG,console start
15/01/08 17:56:55 INFO service.AbstractService: Service:ThriftBinaryCLIService is started.
15/01/08 17:56:55 INFO service.AbstractService: Service:HiveServer2 is started.
15/01/08 17:56:55 ERROR thrift.ThriftCLIService: Error:
javax.security.auth.login.LoginException: Unsupported authentication type CUSTEM
at org.apache.hive.service.auth.HiveAuthFactory.getAuthTransFactory(HiveAuthFactory.java:148)
at org.apache.hive.service.cli.thrift.ThriftBinaryCLIService.run(ThriftBinaryCLIService.java:43)
at java.lang.Thread.run(Thread.java:662)
hiveserver 2が正常に起動すると、ThriftBinaryCLIServiceサービスがデフォルトで開始されます.ThriftBinaryCLIServiceクラスのrunメソッド:
public void run() {
try {
hiveAuthFactory = new HiveAuthFactory(); //run HiveAuthFactory
TTransportFactory transportFactory = hiveAuthFactory.getAuthTransFactory(); // HiveAuthFactory getAuthTransFactory
TTransportFactory
TProcessorFactory processorFactory = hiveAuthFactory.getAuthProcFactory(this);
.....
一方、HiveAuthFactoryのコンストラクション関数では、hiveの構成が解析され、対応するhiveserverの認証設定が取得されます.
public HiveAuthFactory() throws TTransportException {
conf = new HiveConf();
transportMode = conf.getVar(HiveConf.ConfVars.HIVE_SERVER2_TRANSPORT_MODE);
//HIVE_SERVER2_TRANSPORT_MODE("hive.server2.transport.mode", "binary",new StringsValidator("binary", "http")),
authTypeStr = conf.getVar(HiveConf.ConfVars.HIVE_SERVER2_AUTHENTICATION);
//HIVE_SERVER2_AUTHENTICATION("hive.server2.authentication", "NONE", new StringsValidator("NOSASL", "NONE", "LDAP", "KERBEROS", "PAM", "CUSTOM")),
null, "NOSASL", "NONE", "LDAP", "KERBEROS", "PAM", "CUSTOM"
// In http mode we use NOSASL as the default auth type
if (transportMode.equalsIgnoreCase("http")) {
if (authTypeStr == null) {
authTypeStr = AuthTypes.NOSASL.getAuthName();
}
}
else {
if (authTypeStr == null) {
authTypeStr = AuthTypes.NONE.getAuthName();
}
if (authTypeStr.equalsIgnoreCase(AuthTypes.KERBEROS.getAuthName())
&& ShimLoader.getHadoopShims().isSecureShimImpl()) {
saslServer = ShimLoader.getHadoopThriftAuthBridge().createServer(
conf.getVar(ConfVars.HIVE_SERVER2_KERBEROS_KEYTAB),
conf.getVar(ConfVars.HIVE_SERVER2_KERBEROS_PRINCIPAL)
);
// start delegation token manager
try {
saslServer.startDelegationTokenSecretManager(conf, null);
} catch (IOException e) {
throw new TTransportException("Failed to start token manager", e);
}
}
}
}
getAuthTransFactoryメソッドはauthType-Strが有効値であるかどうかを判断します.そうしないと異常を投げ出して起動を終了します.
public TTransportFactory getAuthTransFactory() throws LoginException {
TTransportFactory transportFactory;
if (authTypeStr.equalsIgnoreCase(AuthTypes.KERBEROS.getAuthName())) {
try {
transportFactory = saslServer.createTransportFactory(getSaslProperties());
} catch (TTransportException e) {
throw new LoginException(e.getMessage());
}
} else if (authTypeStr.equalsIgnoreCase(AuthTypes.NONE.getAuthName())) {
transportFactory = PlainSaslHelper.getPlainTransportFactory(authTypeStr);
} else if (authTypeStr.equalsIgnoreCase(AuthTypes.LDAP.getAuthName())) {
transportFactory = PlainSaslHelper.getPlainTransportFactory(authTypeStr);
} else if (authTypeStr.equalsIgnoreCase(AuthTypes.PAM.getAuthName())) {
transportFactory = PlainSaslHelper.getPlainTransportFactory(authTypeStr);
} else if (authTypeStr.equalsIgnoreCase(AuthTypes.NOSASL.getAuthName())) {
transportFactory = new TTransportFactory();
} else if (authTypeStr.equalsIgnoreCase(AuthTypes.CUSTOM.getAuthName())) {
transportFactory = PlainSaslHelper.getPlainTransportFactory(authTypeStr);
} else {
throw new LoginException("Unsupported authentication type " + authTypeStr);
}
return transportFactory;
}