[KYUUBI #4479] Restore JDBC Kerberos authentication behavior for UGI.doAs
### _Why are the changes needed?_
A typical use case of Hadoop UGI w/ Kyuubi Hive JDBC is
```
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
ugi.doAs(() -> {
Connection conn = DriverManager.getConnection(
"jdbc:kyuubi://host:10009/default;principal=kyuubi_HOST/ABC.ORG");
...
});
```
After https://github.com/apache/kyuubi/pull/3023, Kyuubi Hive JDBC implements the Kerberos authentication by using JDK directly instead of Hadoop `UserGroupInformation`, but it also introduce a breaking change for Hadoop users, including the above case. As workaround, user should add `kerberosAuthType=fromSubject` alongside w/ `principal=kyuubi_HOST/ABC.ORG` to make it work.
This PR propose to restore the behavior before https://github.com/apache/kyuubi/pull/3023 by handling UGI.doAs explicitly.
And this PR makes the `clientPrincipal` `clientKeytab` as the highest priority, so in below cases, `clientPrincipal` `clientKeytab` take effects instead of UGI.
```
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
ugi.doAs(() -> {
Connection conn = DriverManager.getConnection(
"jdbc:kyuubi://host:10009/default;principal=kyuubi_HOST/ABC.ORG;" +
"clientPrincipal=tom_HOST/ABC.ORG;clientKeytab=/path/xxx.keytab");
...
});
```
### _How was this patch tested?_
- [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible
- [ ] Add screenshots for manual tests if appropriate
- [ ] [Run test](https://kyuubi.readthedocs.io/en/master/develop_tools/testing.html#running-tests) locally before make a pull request
Closes #4479 from pan3793/detect-ugi.
Closes #4479
0e169abc6 [Cheng Pan] nit
19036e3d7 [Cheng Pan] reorder
e8faf9c56 [Cheng Pan] Restore JDBC kerberos authentication behavior for UGI.doAs
Authored-by: Cheng Pan <chengpan@apache.org>
Signed-off-by: fwang12 <fwang12@ebay.com>
This commit is contained in:
parent
68b34be492
commit
17466ea41a
@ -30,10 +30,7 @@ import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.*;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
@ -43,6 +40,7 @@ import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.sasl.Sasl;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hive.service.rpc.thrift.*;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
@ -813,11 +811,16 @@ public class KyuubiConnection implements SQLConnection, KyuubiLoggable {
|
||||
return !AUTH_SIMPLE.equalsIgnoreCase(sessConfMap.get(AUTH_TYPE));
|
||||
}
|
||||
|
||||
private boolean isFromSubjectAuthMode() {
|
||||
return isSaslAuthMode()
|
||||
&& hasSessionValue(AUTH_PRINCIPAL)
|
||||
&& AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT.equalsIgnoreCase(
|
||||
sessConfMap.get(AUTH_KERBEROS_AUTH_TYPE));
|
||||
private boolean isHadoopUserGroupInformationDoAs() {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Principal> HadoopUserClz =
|
||||
(Class<? extends Principal>) ClassUtils.getClass("org.apache.hadoop.security.User");
|
||||
Subject subject = Subject.getSubject(AccessController.getContext());
|
||||
return subject != null && !subject.getPrincipals(HadoopUserClz).isEmpty();
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isKeytabAuthMode() {
|
||||
@ -827,6 +830,16 @@ public class KyuubiConnection implements SQLConnection, KyuubiLoggable {
|
||||
&& hasSessionValue(AUTH_KYUUBI_CLIENT_KEYTAB);
|
||||
}
|
||||
|
||||
private boolean isFromSubjectAuthMode() {
|
||||
return isSaslAuthMode()
|
||||
&& hasSessionValue(AUTH_PRINCIPAL)
|
||||
&& !hasSessionValue(AUTH_KYUUBI_CLIENT_PRINCIPAL)
|
||||
&& !hasSessionValue(AUTH_KYUUBI_CLIENT_KEYTAB)
|
||||
&& (AUTH_KERBEROS_AUTH_TYPE_FROM_SUBJECT.equalsIgnoreCase(
|
||||
sessConfMap.get(AUTH_KERBEROS_AUTH_TYPE))
|
||||
|| isHadoopUserGroupInformationDoAs());
|
||||
}
|
||||
|
||||
private boolean isTgtCacheAuthMode() {
|
||||
return isSaslAuthMode()
|
||||
&& hasSessionValue(AUTH_PRINCIPAL)
|
||||
@ -843,15 +856,15 @@ public class KyuubiConnection implements SQLConnection, KyuubiLoggable {
|
||||
}
|
||||
|
||||
private Subject createSubject() {
|
||||
if (isFromSubjectAuthMode()) {
|
||||
if (isKeytabAuthMode()) {
|
||||
String principal = sessConfMap.get(AUTH_KYUUBI_CLIENT_PRINCIPAL);
|
||||
String keytab = sessConfMap.get(AUTH_KYUUBI_CLIENT_KEYTAB);
|
||||
return KerberosAuthenticationManager.getKeytabAuthentication(principal, keytab).getSubject();
|
||||
} else if (isFromSubjectAuthMode()) {
|
||||
AccessControlContext context = AccessController.getContext();
|
||||
return Subject.getSubject(context);
|
||||
} else if (isTgtCacheAuthMode()) {
|
||||
return KerberosAuthenticationManager.getTgtCacheAuthentication().getSubject();
|
||||
} else if (isKeytabAuthMode()) {
|
||||
String principal = sessConfMap.get(AUTH_KYUUBI_CLIENT_PRINCIPAL);
|
||||
String keytab = sessConfMap.get(AUTH_KYUUBI_CLIENT_KEYTAB);
|
||||
return KerberosAuthenticationManager.getKeytabAuthentication(principal, keytab).getSubject();
|
||||
} else {
|
||||
// This should never happen
|
||||
throw new IllegalArgumentException("Unsupported auth mode");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user