Repository: trinodb/trino (Java) — Bug Fix

Issue:
presto select query fails with permission denied for kerberized Hive metastore with hive metastore impersonation enabled.
select query fails when service user and doesn't has read permission to underlaying hdfs directory to hive table. service user can impersonate the actual user who owns the table and directory.
 acutal user is only user who has permissions to the directory.

### stack trace : 
`
presto> select * from hive.actual_user.test;        
        
        Query 20190925_123321_00004_p7gd2 failed: org.apache.hadoop.security.AccessControlException: Permission denied: user=service_user, access=EXECUTE, inode="/hive/userdbs/actual_user.db/test":actual_user:hadoop:drwxr-x---
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:353)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkTraverse(FSPermissionChecker.java:292)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:238)
                at org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer$RangerAccessControlEnforcer.checkDefaultEnforcer(RangerHdfsAuthorizer.java:428)
                at org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer$RangerAccessControlEnforcer.checkPermission(RangerHdfsAuthorizer.java:365)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:190)
                at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1956)
                at org.apache.hadoop.hdfs.server.namenode.FSDirStatAndListingOp.getFileInfo(FSDirStatAndListingOp.java:108)
                at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getFileInfo(FSNamesystem.java:4142)
                at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.getFileInfo(NameNodeRpcServer.java:1137)
                at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.getFileInfo(ClientNamenodeProtocolServerSideTranslatorPB.java:866)
                at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
                at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:640)
                at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
                at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2351)
                at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2347)
                at java.security.AccessController.doPrivileged(Native Method)
                at javax.security.auth.Subject.doAs(Subject.java:422)
                at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1866)
                at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2347)

        io.prestosql.spi.PrestoException: org.apache.hadoop.security.AccessControlException: Permission denied: user=service_user, access=EXECUTE, inode="/hive/userdbs/actual_user.db/test":actual_user:hadoop:drwxr-x---
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:353)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkTraverse(FSPermissionChecker.java:292)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:238)
                at org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer$RangerAccessControlEnforcer.checkDefaultEnforcer(RangerHdfsAuthorizer.java:428)
                at org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer$RangerAccessControlEnforcer.checkPermission(RangerHdfsAuthorizer.java:365)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:190)
                at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1956)
                at org.apache.hadoop.hdfs.server.namenode.FSDirStatAndListingOp.getFileInfo(FSDirStatAndListingOp.java:108)
                at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getFileInfo(FSNamesystem.java:4142)
                at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.getFileInfo(NameNodeRpcServer.java:1137)
                at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.getFileInfo(ClientNamenodeProtocolServerSideTranslatorPB.java:866)
                at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
                at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:640)
                at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
                at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2351)
                at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2347)
                at java.security.AccessController.doPrivileged(Native Method)
                at javax.security.auth.Subject.doAs(Subject.java:422)
                at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1866)
                at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2347)

                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastore.getTable(ThriftHiveMetastore.java:261)
                at io.prestosql.plugin.hive.metastore.thrift.BridgingHiveMetastore.getTable(BridgingHiveMetastore.java:85)
                at io.prestosql.plugin.hive.metastore.cache.CachingHiveMetastore.loadTable(CachingHiveMetastore.java:293)
                at com.google.common.cache.CacheLoader$FunctionToCacheLoader.load(CacheLoader.java:165)
                at com.google.common.cache.CacheLoader$1.load(CacheLoader.java:188)
                at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3528)
                at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2277)
                at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2154)
                at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2044)
                at com.google.common.cache.LocalCache.get(LocalCache.java:3952)
                at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974)
                at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958)
                at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4964)
                at io.prestosql.plugin.hive.metastore.cache.CachingHiveMetastore.get(CachingHiveMetastore.java:236)
                at io.prestosql.plugin.hive.metastore.cache.CachingHiveMetastore.getTable(CachingHiveMetastore.java:282)
                at io.prestosql.plugin.hive.metastore.cache.CachingHiveMetastore.loadTable(CachingHiveMetastore.java:293)
                at com.google.common.cache.CacheLoader$FunctionToCacheLoader.load(CacheLoader.java:165)
                at com.google.common.cache.CacheLoader$1.load(CacheLoader.java:188)
                at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3528)
                at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2277)
                at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2154)
                at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2044)
                at com.google.common.cache.LocalCache.get(LocalCache.java:3952)
                at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974)
                at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958)
                at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4964)
                at io.prestosql.plugin.hive.metastore.cache.CachingHiveMetastore.get(CachingHiveMetastore.java:236)
                at io.prestosql.plugin.hive.metastore.cache.CachingHiveMetastore.getTable(CachingHiveMetastore.java:282)
                at io.prestosql.plugin.hive.metastore.SemiTransactionalHiveMetastore.getTable(SemiTransactionalHiveMetastore.java:153)
                at io.prestosql.plugin.hive.HiveMetadata.getView(HiveMetadata.java:1659)
                at io.prestosql.spi.connector.classloader.ClassLoaderSafeConnectorMetadata.getView(ClassLoaderSafeConnectorMetadata.java:442)
                at io.prestosql.metadata.MetadataManager.getView(MetadataManager.java:950)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitTable(StatementAnalyzer.java:879)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitTable(StatementAnalyzer.java:271)
                at io.prestosql.sql.tree.Table.accept(Table.java:53)
                at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:286)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.analyzeFrom(StatementAnalyzer.java:1998)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:1091)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:271)
                at io.prestosql.sql.tree.QuerySpecification.accept(QuerySpecification.java:144)
                at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:286)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:296)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:787)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:271)
                at io.prestosql.sql.tree.Query.accept(Query.java:107)
                at io.prestosql.sql.tree.AstVisitor.process(AstVisitor.java:27)
                at io.prestosql.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:286)
                at io.prestosql.sql.analyzer.StatementAnalyzer.analyze(StatementAnalyzer.java:263)
                at io.prestosql.sql.analyzer.Analyzer.analyze(Analyzer.java:82)
                at io.prestosql.sql.analyzer.Analyzer.analyze(Analyzer.java:74)
                at io.prestosql.execution.SqlQueryExecution.analyze(SqlQueryExecution.java:218)
                at io.prestosql.execution.SqlQueryExecution.<init>(SqlQueryExecution.java:177)
                at io.prestosql.execution.SqlQueryExecution.<init>(SqlQueryExecution.java:94)
                at io.prestosql.execution.SqlQueryExecution$SqlQueryExecutionFactory.createQueryExecution(SqlQueryExecution.java:713)
                at io.prestosql.dispatcher.LocalDispatchQueryFactory.lambda$createDispatchQuery$0(LocalDispatchQueryFactory.java:118)
                at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:125)
                at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:57)
                at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                at java.lang.Thread.run(Thread.java:748)
        Caused by: org.apache.hadoop.hive.metastore.api.MetaException: org.apache.hadoop.security.AccessControlException: Permission denied: user=service_user, access=EXECUTE, inode="/hive/userdbs/actual_user.db/test":actual_user:hadoop:drwxr-x---
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:353)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkTraverse(FSPermissionChecker.java:292)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:238)
                at org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer$RangerAccessControlEnforcer.checkDefaultEnforcer(RangerHdfsAuthorizer.java:428)
                at org.apache.ranger.authorization.hadoop.RangerHdfsAuthorizer$RangerAccessControlEnforcer.checkPermission(RangerHdfsAuthorizer.java:365)
                at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:190)
                at org.apache.hadoop.hdfs.server.namenode.FSDirectory.checkPermission(FSDirectory.java:1956)
                at org.apache.hadoop.hdfs.server.namenode.FSDirStatAndListingOp.getFileInfo(FSDirStatAndListingOp.java:108)
                at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getFileInfo(FSNamesystem.java:4142)
                at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.getFileInfo(NameNodeRpcServer.java:1137)
                at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.getFileInfo(ClientNamenodeProtocolServerSideTranslatorPB.java:866)
                at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
                at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:640)
                at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
                at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2351)
                at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2347)
                at java.security.AccessController.doPrivileged(Native Method)
                at javax.security.auth.Subject.doAs(Subject.java:422)
                at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1866)
                at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2347)

                at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$get_table_result$get_table_resultStandardScheme.read(ThriftHiveMetastore.java)
                at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$get_table_result$get_table_resultStandardScheme.read(ThriftHiveMetastore.java)
                at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$get_table_result.read(ThriftHiveMetastore.java)
                at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:86)
                at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$Client.recv_get_table(ThriftHiveMetastore.java:1993)
                at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$Client.get_table(ThriftHiveMetastore.java:1979)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastoreClient.getTable(ThriftHiveMetastoreClient.java:159)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastore.lambda$getTableFromMetastore$7(ThriftHiveMetastore.java:275)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastore.alternativeCall(ThriftHiveMetastore.java:1394)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastore.getTableFromMetastore(ThriftHiveMetastore.java:271)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastore.lambda$getTable$4(ThriftHiveMetastore.java:250)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftMetastoreApiStats.lambda$wrap$0(ThriftMetastoreApiStats.java:42)
                at io.prestosql.plugin.hive.util.RetryDriver.run(RetryDriver.java:130)
                at io.prestosql.plugin.hive.metastore.thrift.ThriftHiveMetastore.getTable(ThriftHiveMetastore.java:248)
                ... 62 more

`


Discussion:

Resolving patch:
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/HiveMetastoreAuthentication.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/HiveMetastoreAuthentication.java
index 6c8d6bfdb59b..3d7b3645e63e 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/HiveMetastoreAuthentication.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/HiveMetastoreAuthentication.java
@@ -15,7 +15,9 @@
 
 import org.apache.thrift.transport.TTransport;
 
+import java.util.Optional;
+
 public interface HiveMetastoreAuthentication
 {
-    TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost);
+    TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost, Optional<String> delegationToken);
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/KerberosHiveMetastoreAuthentication.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/KerberosHiveMetastoreAuthentication.java
index 8cb1291cbeda..c8bbb8fec3ea 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/KerberosHiveMetastoreAuthentication.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/KerberosHiveMetastoreAuthentication.java
@@ -15,21 +15,31 @@
 
 import com.google.common.collect.ImmutableMap;
 import io.prestosql.plugin.hive.ForHiveMetastore;
+import org.apache.hadoop.hive.metastore.security.DelegationTokenIdentifier;
 import org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport;
 import org.apache.hadoop.security.SaslRpcServer;
+import org.apache.hadoop.security.token.Token;
 import org.apache.thrift.transport.TSaslClientTransport;
 import org.apache.thrift.transport.TTransport;
 
 import javax.inject.Inject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.sasl.RealmCallback;
 import javax.security.sasl.Sasl;
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.util.Base64;
 import java.util.Map;
+import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 import static org.apache.hadoop.security.SaslRpcServer.AuthMethod.KERBEROS;
+import static org.apache.hadoop.security.SaslRpcServer.AuthMethod.TOKEN;
 import static org.apache.hadoop.security.SecurityUtil.getServerPrincipal;
 
 public class KerberosHiveMetastoreAuthentication
@@ -53,7 +63,7 @@ public KerberosHiveMetastoreAuthentication(String hiveMetastoreServicePrincipal,
     }
 
     @Override
-    public TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost)
+    public TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost, Optional<String> delegationToken)
     {
         try {
             String serverPrincipal = getServerPrincipal(hiveMetastoreServicePrincipal, hiveMetastoreHost);
@@ -65,14 +75,27 @@ public TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost
                     Sasl.QOP, "auth-conf,auth",
                     Sasl.SERVER_AUTH, "true");
 
-            TTransport saslTransport = new TSaslClientTransport(
-                    KERBEROS.getMechanismName(),
-                    null,
-                    names[0],
-                    names[1],
-                    saslProps,
-                    null,
-                    rawTransport);
+            TTransport saslTransport;
+            if (delegationToken.isPresent()) {
+                saslTransport = new TSaslClientTransport(
+                        TOKEN.getMechanismName(),
+                        null,
+                        null,
+                        "default",
+                        saslProps,
+                        new SaslClientCallbackHandler(decodeDelegationToken(delegationToken.get())),
+                        rawTransport);
+            }
+            else {
+                saslTransport = new TSaslClientTransport(
+                        KERBEROS.getMechanismName(),
+                        null,
+                        names[0],
+                        names[1],
+                        saslProps,
+                        null,
+                        rawTransport);
+            }
 
             return new TUGIAssumingTransport(saslTransport, authentication.getUserGroupInformation());
         }
@@ -80,4 +103,42 @@ public TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost
             throw new UncheckedIOException(e);
         }
     }
+
+    private static Token<DelegationTokenIdentifier> decodeDelegationToken(String tokenValue)
+            throws IOException
+    {
+        Token<DelegationTokenIdentifier> token = new Token<>();
+        token.decodeFromUrlString(tokenValue);
+        return token;
+    }
+
+    private static class SaslClientCallbackHandler
+            implements CallbackHandler
+    {
+        private final String username;
+        private final String password;
+
+        SaslClientCallbackHandler(Token<DelegationTokenIdentifier> token)
+        {
+            this.username = Base64.getEncoder().encodeToString(token.getIdentifier());
+            this.password = Base64.getEncoder().encodeToString(token.getPassword());
+        }
+
+        @Override
+        public void handle(Callback[] callbacks)
+        {
+            for (Callback callback : callbacks) {
+                if (callback instanceof NameCallback) {
+                    ((NameCallback) callback).setName(username);
+                }
+                if (callback instanceof PasswordCallback) {
+                    ((PasswordCallback) callback).setPassword(password.toCharArray());
+                }
+                if (callback instanceof RealmCallback) {
+                    RealmCallback realmCallback = (RealmCallback) callback;
+                    realmCallback.setText(realmCallback.getDefaultText());
+                }
+            }
+        }
+    }
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/NoHiveMetastoreAuthentication.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/NoHiveMetastoreAuthentication.java
index f0b991b23bde..116d4ed83752 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/NoHiveMetastoreAuthentication.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/authentication/NoHiveMetastoreAuthentication.java
@@ -15,12 +15,17 @@
 
 import org.apache.thrift.transport.TTransport;
 
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
 public class NoHiveMetastoreAuthentication
         implements HiveMetastoreAuthentication
 {
     @Override
-    public TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost)
+    public TTransport authenticate(TTransport rawTransport, String hiveMetastoreHost, Optional<String> delegationToken)
     {
+        checkArgument(!delegationToken.isPresent(), "delegation token is not supported");
         return rawTransport;
     }
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/MetastoreLocator.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/MetastoreLocator.java
index 6e091c787335..8f1d48ebc60a 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/MetastoreLocator.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/MetastoreLocator.java
@@ -15,11 +15,13 @@
 
 import org.apache.thrift.TException;
 
+import java.util.Optional;
+
 public interface MetastoreLocator
 {
     /**
      * Create a connected {@link ThriftMetastoreClient}
      */
-    ThriftMetastoreClient createMetastoreClient()
+    ThriftMetastoreClient createMetastoreClient(Optional<String> delegationToken)
             throws TException;
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/StaticMetastoreLocator.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/StaticMetastoreLocator.java
index f5e385891a1a..df0f84386348 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/StaticMetastoreLocator.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/StaticMetastoreLocator.java
@@ -22,6 +22,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Strings.isNullOrEmpty;
@@ -62,7 +63,7 @@ public StaticMetastoreLocator(List<URI> metastoreUris, String metastoreUsername,
      * connection succeeds or there are no more fallback metastores.
      */
     @Override
-    public ThriftMetastoreClient createMetastoreClient()
+    public ThriftMetastoreClient createMetastoreClient(Optional<String> delegationToken)
             throws TException
     {
         List<HostAndPort> metastores = new ArrayList<>(addresses);
@@ -71,7 +72,7 @@ public ThriftMetastoreClient createMetastoreClient()
         TException lastException = null;
         for (HostAndPort metastore : metastores) {
             try {
-                ThriftMetastoreClient client = clientFactory.create(metastore);
+                ThriftMetastoreClient client = clientFactory.create(metastore, delegationToken);
                 if (!isNullOrEmpty(metastoreUsername)) {
                     client.setUGI(metastoreUsername);
                 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastore.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastore.java
index 34083c4fae25..c4b797a0c2a9 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastore.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastore.java
@@ -25,6 +25,8 @@
 import io.prestosql.plugin.hive.PartitionStatistics;
 import io.prestosql.plugin.hive.SchemaAlreadyExistsException;
 import io.prestosql.plugin.hive.TableAlreadyExistsException;
+import io.prestosql.plugin.hive.authentication.HiveAuthenticationConfig;
+import io.prestosql.plugin.hive.authentication.HiveAuthenticationConfig.HiveMetastoreAuthenticationType;
 import io.prestosql.plugin.hive.authentication.HiveIdentity;
 import io.prestosql.plugin.hive.metastore.Column;
 import io.prestosql.plugin.hive.metastore.HiveColumnStatistics;
@@ -123,6 +125,7 @@ public class ThriftHiveMetastore
     private final Duration maxRetryTime;
     private final int maxRetries;
     private final boolean impersonationEnabled;
+    private final HiveMetastoreAuthenticationType authenticationType;
 
     private final AtomicInteger chosenGetTableAlternative = new AtomicInteger(Integer.MAX_VALUE);
     private final AtomicInteger chosenTableParamAlternative = new AtomicInteger(Integer.MAX_VALUE);
@@ -131,7 +134,7 @@ public class ThriftHiveMetastore
     private static final Pattern TABLE_PARAMETER_SAFE_VALUE_PATTERN = Pattern.compile("^[a-zA-Z0-9]*$");
 
     @Inject
-    public ThriftHiveMetastore(MetastoreLocator metastoreLocator, ThriftHiveMetastoreConfig thriftConfig)
+    public ThriftHiveMetastore(MetastoreLocator metastoreLocator, ThriftHiveMetastoreConfig thriftConfig, HiveAuthenticationConfig authenticationConfig)
     {
         this.clientProvider = requireNonNull(metastoreLocator, "metastoreLocator is null");
         this.backoffScaleFactor = thriftConfig.getBackoffScaleFactor();
@@ -140,6 +143,7 @@ public ThriftHiveMetastore(MetastoreLocator metastoreLocator, ThriftHiveMetastor
         this.maxRetryTime = thriftConfig.getMaxRetryTime();
         this.maxRetries = thriftConfig.getMaxRetries();
         this.impersonationEnabled = thriftConfig.isImpersonationEnabled();
+        this.authenticationType = authenticationConfig.getHiveMetastoreAuthenticationType();
     }
 
     @Managed
@@ -1417,7 +1421,7 @@ else if (firstException != exception) {
     private ThriftMetastoreClient createMetastoreClient()
             throws TException
     {
-        return clientProvider.createMetastoreClient();
+        return clientProvider.createMetastoreClient(Optional.empty());
     }
 
     private ThriftMetastoreClient createMetastoreClient(HiveIdentity identity)
@@ -1427,12 +1431,23 @@ private ThriftMetastoreClient createMetastoreClient(HiveIdentity identity)
             return createMetastoreClient();
         }
 
-        String username = identity.getUsername()
-                .orElseThrow(() -> new IllegalStateException("End-user name should exist when metastore impersonation is enabled"));
+        String username = identity.getUsername().orElseThrow(() -> new IllegalStateException("End-user name should exist when metastore impersonation is enabled"));
+        switch (authenticationType) {
+            case KERBEROS:
+                String delegationToken;
+                try (ThriftMetastoreClient client = createMetastoreClient()) {
+                    delegationToken = client.getDelegationToken(username);
+                }
+                return clientProvider.createMetastoreClient(Optional.of(delegationToken));
+
+            case NONE:
+                ThriftMetastoreClient client = createMetastoreClient();
+                setMetastoreUserOrClose(client, username);
+                return client;
 
-        ThriftMetastoreClient client = createMetastoreClient();
-        setMetastoreUserOrClose(client, username);
-        return client;
+            default:
+                throw new IllegalStateException("Unsupported authentication type: " + authenticationType);
+        }
     }
 
     private static void setMetastoreUserOrClose(ThriftMetastoreClient client, String username)
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastoreClient.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastoreClient.java
index e5c291189127..c37fc1ce8022 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastoreClient.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftHiveMetastoreClient.java
@@ -415,4 +415,11 @@ public void setUGI(String userName)
     {
         client.set_ugi(userName, new ArrayList<>());
     }
+
+    @Override
+    public String getDelegationToken(String userName)
+            throws TException
+    {
+        return client.get_delegation_token(userName, userName);
+    }
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClient.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClient.java
index a3867ed88142..c979069e08b3 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClient.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClient.java
@@ -146,4 +146,7 @@ List<RolePrincipalGrant> listRoleGrants(String name, PrincipalType principalType
 
     void setUGI(String userName)
             throws TException;
+
+    String getDelegationToken(String userName)
+            throws TException;
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClientFactory.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClientFactory.java
index b96d030b65d8..89e08c247399 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClientFactory.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/ThriftMetastoreClientFactory.java
@@ -51,9 +51,9 @@ public ThriftMetastoreClientFactory(ThriftHiveMetastoreConfig config, HiveMetast
         this(Optional.empty(), Optional.ofNullable(config.getSocksProxy()), config.getMetastoreTimeout(), metastoreAuthentication);
     }
 
-    public ThriftMetastoreClient create(HostAndPort address)
+    public ThriftMetastoreClient create(HostAndPort address, Optional<String> delegationToken)
             throws TTransportException
     {
-        return new ThriftHiveMetastoreClient(Transport.create(address, sslContext, socksProxy, timeoutMillis, metastoreAuthentication));
+        return new ThriftHiveMetastoreClient(Transport.create(address, sslContext, socksProxy, timeoutMillis, metastoreAuthentication, delegationToken));
     }
 }
diff --git a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/Transport.java b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/Transport.java
index ca4eece0404c..f46daa69b373 100644
--- a/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/Transport.java
+++ b/presto-hive/src/main/java/io/prestosql/plugin/hive/metastore/thrift/Transport.java
@@ -38,13 +38,14 @@ public static TTransport create(
             Optional<SSLContext> sslContext,
             Optional<HostAndPort> socksProxy,
             int timeoutMillis,
-            HiveMetastoreAuthentication authentication)
+            HiveMetastoreAuthentication authentication,
+            Optional<String> delegationToken)
             throws TTransportException
     {
         requireNonNull(address, "address is null");
         try {
             TTransport rawTransport = createRaw(address, sslContext, socksProxy, timeoutMillis);
-            TTransport authenticatedTransport = authentication.authenticate(rawTransport, address.getHost());
+            TTransport authenticatedTransport = authentication.authenticate(rawTransport, address.getHost(), delegationToken);
             if (!authenticatedTransport.isOpen()) {
                 authenticatedTransport.open();
             }


Test patch:
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHive.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHive.java
index b88efee5f5c3..4c43ca7ae5fa 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHive.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHive.java
@@ -27,6 +27,7 @@
 import io.prestosql.GroupByHashPageIndexerFactory;
 import io.prestosql.plugin.hive.HdfsEnvironment.HdfsContext;
 import io.prestosql.plugin.hive.LocationService.WriteInfo;
+import io.prestosql.plugin.hive.authentication.HiveAuthenticationConfig;
 import io.prestosql.plugin.hive.authentication.HiveIdentity;
 import io.prestosql.plugin.hive.metastore.Column;
 import io.prestosql.plugin.hive.metastore.HiveColumnStatistics;
@@ -702,7 +703,7 @@ protected final void setup(String host, int port, String databaseName, String ti
         MetastoreLocator metastoreLocator = new TestingMetastoreLocator(proxy, HostAndPort.fromParts(host, port));
 
         HiveMetastore metastore = new CachingHiveMetastore(
-                new BridgingHiveMetastore(new ThriftHiveMetastore(metastoreLocator, new ThriftHiveMetastoreConfig())),
+                new BridgingHiveMetastore(new ThriftHiveMetastore(metastoreLocator, new ThriftHiveMetastoreConfig(), new HiveAuthenticationConfig())),
                 executor,
                 Duration.valueOf("1m"),
                 Duration.valueOf("15s"),
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHiveFileSystem.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHiveFileSystem.java
index 30b89dbff796..e4492441eeec 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHiveFileSystem.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/AbstractTestHiveFileSystem.java
@@ -25,6 +25,7 @@
 import io.prestosql.plugin.hive.AbstractTestHive.HiveTransaction;
 import io.prestosql.plugin.hive.AbstractTestHive.Transaction;
 import io.prestosql.plugin.hive.HdfsEnvironment.HdfsContext;
+import io.prestosql.plugin.hive.authentication.HiveAuthenticationConfig;
 import io.prestosql.plugin.hive.authentication.HiveIdentity;
 import io.prestosql.plugin.hive.authentication.NoHdfsAuthentication;
 import io.prestosql.plugin.hive.metastore.Database;
@@ -162,7 +163,7 @@ protected void setup(String host, int port, String databaseName, boolean s3Selec
 
         hdfsEnvironment = new HdfsEnvironment(hdfsConfiguration, new HdfsConfig(), new NoHdfsAuthentication());
         metastoreClient = new TestingHiveMetastore(
-                new BridgingHiveMetastore(new ThriftHiveMetastore(metastoreLocator, new ThriftHiveMetastoreConfig())),
+                new BridgingHiveMetastore(new ThriftHiveMetastore(metastoreLocator, new ThriftHiveMetastoreConfig(), new HiveAuthenticationConfig())),
                 executor,
                 getBasePath(),
                 hdfsEnvironment);
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/cache/TestCachingHiveMetastore.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/cache/TestCachingHiveMetastore.java
index 98b70faeaada..f5ca65cb1745 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/cache/TestCachingHiveMetastore.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/cache/TestCachingHiveMetastore.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import io.airlift.units.Duration;
+import io.prestosql.plugin.hive.authentication.HiveAuthenticationConfig;
 import io.prestosql.plugin.hive.authentication.HiveIdentity;
 import io.prestosql.plugin.hive.metastore.Partition;
 import io.prestosql.plugin.hive.metastore.thrift.BridgingHiveMetastore;
@@ -77,7 +78,7 @@ public void setUp()
     private ThriftHiveMetastore createThriftHiveMetastore()
     {
         MetastoreLocator metastoreLocator = new MockMetastoreLocator(mockClient);
-        return new ThriftHiveMetastore(metastoreLocator, new ThriftHiveMetastoreConfig());
+        return new ThriftHiveMetastore(metastoreLocator, new ThriftHiveMetastoreConfig(), new HiveAuthenticationConfig());
     }
 
     @Test
@@ -304,7 +305,7 @@ private MockMetastoreLocator(ThriftMetastoreClient client)
         }
 
         @Override
-        public ThriftMetastoreClient createMetastoreClient()
+        public ThriftMetastoreClient createMetastoreClient(Optional<String> delegationToken)
         {
             return client;
         }
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClient.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClient.java
index 413bf27a15b0..63d568aa84d8 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClient.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClient.java
@@ -392,4 +392,10 @@ public void setUGI(String userName)
     {
         // No-op
     }
+
+    @Override
+    public String getDelegationToken(String userName)
+    {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClientFactory.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClientFactory.java
index ca711427c22c..2487a921141f 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClientFactory.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/MockThriftMetastoreClientFactory.java
@@ -22,6 +22,7 @@
 import java.util.List;
 import java.util.Optional;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
@@ -37,9 +38,10 @@ public MockThriftMetastoreClientFactory(Optional<HostAndPort> socksProxy, Durati
     }
 
     @Override
-    public ThriftMetastoreClient create(HostAndPort address)
+    public ThriftMetastoreClient create(HostAndPort address, Optional<String> delegationToken)
             throws TTransportException
     {
+        checkArgument(!delegationToken.isPresent(), "delegation token is not supported");
         checkState(!clients.isEmpty(), "mock not given enough clients");
         ThriftMetastoreClient client = clients.remove(0);
         if (client == null) {
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestStaticMetastoreLocator.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestStaticMetastoreLocator.java
index 8b506eed5de7..571462b4f9a4 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestStaticMetastoreLocator.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestStaticMetastoreLocator.java
@@ -50,7 +50,7 @@ public void testDefaultHiveMetastore()
             throws TException
     {
         MetastoreLocator locator = createMetastoreLocator(CONFIG_WITH_FALLBACK, singletonList(DEFAULT_CLIENT));
-        assertEquals(locator.createMetastoreClient(), DEFAULT_CLIENT);
+        assertEquals(locator.createMetastoreClient(Optional.empty()), DEFAULT_CLIENT);
     }
 
     @Test
@@ -58,7 +58,7 @@ public void testFallbackHiveMetastore()
             throws TException
     {
         MetastoreLocator locator = createMetastoreLocator(CONFIG_WITH_FALLBACK, asList(null, null, FALLBACK_CLIENT));
-        assertEquals(locator.createMetastoreClient(), FALLBACK_CLIENT);
+        assertEquals(locator.createMetastoreClient(Optional.empty()), FALLBACK_CLIENT);
     }
 
     @Test
@@ -80,7 +80,7 @@ public void testFallbackHiveMetastoreWithHiveUser()
             throws TException
     {
         MetastoreLocator locator = createMetastoreLocator(CONFIG_WITH_FALLBACK_WITH_USER, asList(null, null, FALLBACK_CLIENT));
-        assertEquals(locator.createMetastoreClient(), FALLBACK_CLIENT);
+        assertEquals(locator.createMetastoreClient(Optional.empty()), FALLBACK_CLIENT);
     }
 
     @Test
@@ -92,7 +92,7 @@ public void testMetastoreFailedWithoutFallbackWithHiveUser()
 
     private static void assertCreateClientFails(MetastoreLocator locator, String message)
     {
-        assertThatThrownBy(locator::createMetastoreClient)
+        assertThatThrownBy(() -> locator.createMetastoreClient(Optional.empty()))
                 .hasCauseInstanceOf(TException.class)
                 .hasMessage(message);
     }
diff --git a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestingMetastoreLocator.java b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestingMetastoreLocator.java
index 16620ad22f3d..523c74164ac6 100644
--- a/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestingMetastoreLocator.java
+++ b/presto-hive/src/test/java/io/prestosql/plugin/hive/metastore/thrift/TestingMetastoreLocator.java
@@ -40,9 +40,9 @@ public TestingMetastoreLocator(Optional<HostAndPort> socksProxy, HostAndPort add
     }
 
     @Override
-    public ThriftMetastoreClient createMetastoreClient()
+    public ThriftMetastoreClient createMetastoreClient(Optional<String> delegationToken)
             throws TException
     {
-        return factory.create(address);
+        return factory.create(address, delegationToken);
     }
 }