This is an automated email from the ASF dual-hosted git repository.
dengzhhu653 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new 08bce2a2f93 HIVE-29796: HS2 in Kerberos mode should obfuscate details
in error lo… (#6694)
08bce2a2f93 is described below
commit 08bce2a2f930660bde11d1daabb858085135ffe1
Author: Sai Hemanth Gantasala
<[email protected]>
AuthorDate: Fri Aug 21 02:26:08 2026 -0700
HIVE-29796: HS2 in Kerberos mode should obfuscate details in error lo…
(#6694)
---
service-rpc/pom.xml | 17 ++++
.../rpc/thrift/TCancelDelegationTokenReq.java | 6 +-
.../rpc/thrift/TRenewDelegationTokenReq.java | 6 +-
.../TestDelegationTokenRequestRedaction.java | 49 +++++++++
.../apache/hive/service/auth/HiveAuthFactory.java | 15 +--
.../hive/service/cli/thrift/ThriftCLIService.java | 4 +-
.../auth/TestDelegationTokenLeakPrevention.java | 109 +++++++++++++++++++++
7 files changed, 187 insertions(+), 19 deletions(-)
diff --git a/service-rpc/pom.xml b/service-rpc/pom.xml
index e7f1205894c..f47063c6367 100644
--- a/service-rpc/pom.xml
+++ b/service-rpc/pom.xml
@@ -162,6 +162,23 @@
</replacements>
</configuration>
</execution>
+ <execution>
+ <id>mask-delegation-token</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>replace</goal>
+ </goals>
+ <configuration>
+
<basedir>${basedir}/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/</basedir>
+
<filesToInclude>TCancelDelegationTokenReq.java,TRenewDelegationTokenReq.java</filesToInclude>
+ <replacements>
+ <replacement>
+ <token> if \(this.delegationToken \=\= null\) \{\n
sb.append\(\"null"\)\;\n \} else \{\n
sb.append\(this.delegationToken\)\;\n \}</token>
+ <value> sb.append("*** REDACTED ***");</value>
+ </replacement>
+ </replacements>
+ </configuration>
+ </execution>
</executions>
</plugin>
</plugins>
diff --git
a/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TCancelDelegationTokenReq.java
b/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TCancelDelegationTokenReq.java
index 396b1fa23cb..1f2941b0ef9 100644
---
a/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TCancelDelegationTokenReq.java
+++
b/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TCancelDelegationTokenReq.java
@@ -333,11 +333,7 @@ public java.lang.String toString() {
first = false;
if (!first) sb.append(", ");
sb.append("delegationToken:");
- if (this.delegationToken == null) {
- sb.append("null");
- } else {
- sb.append(this.delegationToken);
- }
+ sb.append("*** REDACTED ***");
first = false;
sb.append(")");
return sb.toString();
diff --git
a/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TRenewDelegationTokenReq.java
b/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TRenewDelegationTokenReq.java
index 57ab7481b3f..7457b2d170d 100644
---
a/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TRenewDelegationTokenReq.java
+++
b/service-rpc/src/gen/thrift/gen-javabean/org/apache/hive/service/rpc/thrift/TRenewDelegationTokenReq.java
@@ -333,11 +333,7 @@ public java.lang.String toString() {
first = false;
if (!first) sb.append(", ");
sb.append("delegationToken:");
- if (this.delegationToken == null) {
- sb.append("null");
- } else {
- sb.append(this.delegationToken);
- }
+ sb.append("*** REDACTED ***");
first = false;
sb.append(")");
return sb.toString();
diff --git
a/service-rpc/src/test/org/apache/hive/service/rpc/thrift/TestDelegationTokenRequestRedaction.java
b/service-rpc/src/test/org/apache/hive/service/rpc/thrift/TestDelegationTokenRequestRedaction.java
new file mode 100644
index 00000000000..9d3f48c6ca5
--- /dev/null
+++
b/service-rpc/src/test/org/apache/hive/service/rpc/thrift/TestDelegationTokenRequestRedaction.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hive.service.rpc.thrift;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TestDelegationTokenRequestRedaction {
+ private static final String LIVE_TOKEN = "LIVE_DELEGATION_TOKEN_ABC123";
+
+ @Test
+ public void testCancelReqToStringRedactsDelegationToken() {
+ TCancelDelegationTokenReq req = new TCancelDelegationTokenReq();
+ req.setDelegationToken(LIVE_TOKEN);
+
+ String reqString = req.toString();
+ assertTrue(reqString.contains("delegationToken:"));
+ assertTrue(reqString.toLowerCase().contains("redacted"));
+ assertFalse(reqString.contains(LIVE_TOKEN));
+ }
+
+ @Test
+ public void testRenewReqToStringRedactsDelegationToken() {
+ TRenewDelegationTokenReq req = new TRenewDelegationTokenReq();
+ req.setDelegationToken(LIVE_TOKEN);
+
+ String reqString = req.toString();
+ assertTrue(reqString.contains("delegationToken:"));
+ assertTrue(reqString.toLowerCase().contains("redacted"));
+ assertFalse(reqString.contains(LIVE_TOKEN));
+ }
+}
diff --git a/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java
b/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java
index c7e8165717f..bfa9831ed37 100644
--- a/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java
+++ b/service/src/java/org/apache/hive/service/auth/HiveAuthFactory.java
@@ -258,8 +258,7 @@ public void cancelDelegationToken(String delegationToken)
throws HiveSQLExceptio
try {
delegationTokenManager.cancelDelegationToken(delegationToken);
} catch (IOException e) {
- throw new HiveSQLException(
- "Error canceling delegation token " + delegationToken, "08S01", e);
+ throw new HiveSQLException(delegationTokenErrorMessage("canceling"),
"08S01", e);
}
}
@@ -271,8 +270,7 @@ public void renewDelegationToken(String delegationToken)
throws HiveSQLException
try {
delegationTokenManager.renewDelegationToken(delegationToken);
} catch (IOException e) {
- throw new HiveSQLException(
- "Error renewing delegation token " + delegationToken, "08S01", e);
+ throw new HiveSQLException(delegationTokenErrorMessage("renewing"),
"08S01", e);
}
}
@@ -284,7 +282,7 @@ public String verifyDelegationToken(String delegationToken)
throws HiveSQLExcept
try {
return delegationTokenManager.verifyDelegationToken(delegationToken);
} catch (IOException e) {
- String msg = "Error verifying delegation token " + delegationToken;
+ String msg = delegationTokenErrorMessage("verifying");
LOG.error(msg, e);
throw new HiveSQLException(msg, "08S01", e);
}
@@ -298,11 +296,14 @@ public String getUserFromToken(String delegationToken)
throws HiveSQLException {
try {
return delegationTokenManager.getUserFromToken(delegationToken);
} catch (IOException e) {
- throw new HiveSQLException(
- "Error extracting user from delegation token " + delegationToken,
"08S01", e);
+ throw new HiveSQLException(delegationTokenErrorMessage("extracting user
from"), "08S01", e);
}
}
+ private static String delegationTokenErrorMessage(String operation) {
+ return "Error " + operation + " delegation token";
+ }
+
public static void verifyProxyAccess(String realUser, String proxyUser,
String ipAddress,
HiveConf hiveConf) throws HiveSQLException {
try {
diff --git
a/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java
b/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java
index a901edecc0f..e6053cb92e8 100644
--- a/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java
+++ b/service/src/java/org/apache/hive/service/cli/thrift/ThriftCLIService.java
@@ -363,7 +363,7 @@ public TCancelDelegationTokenResp
CancelDelegationToken(TCancelDelegationTokenRe
hiveAuthFactory, req.getDelegationToken());
resp.setStatus(OK_STATUS);
} catch (HiveSQLException e) {
- LOG.error("Failed to cancel delegation token [request: {}]", req, e);
+ LOG.error("Failed to cancel delegation token for session {}",
req.getSessionHandle(), e);
resp.setStatus(HiveSQLException.toTStatus(e));
}
}
@@ -382,7 +382,7 @@ public TRenewDelegationTokenResp
RenewDelegationToken(TRenewDelegationTokenReq r
hiveAuthFactory, req.getDelegationToken());
resp.setStatus(OK_STATUS);
} catch (HiveSQLException e) {
- LOG.error("Failed to renew delegation token [request: {}]", e);
+ LOG.error("Failed to renew delegation token for session {}",
req.getSessionHandle(), e);
resp.setStatus(HiveSQLException.toTStatus(e));
}
}
diff --git
a/service/src/test/org/apache/hive/service/auth/TestDelegationTokenLeakPrevention.java
b/service/src/test/org/apache/hive/service/auth/TestDelegationTokenLeakPrevention.java
new file mode 100644
index 00000000000..aa4c92d55e9
--- /dev/null
+++
b/service/src/test/org/apache/hive/service/auth/TestDelegationTokenLeakPrevention.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.hive.service.auth;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import
org.apache.hadoop.hive.metastore.security.MetastoreDelegationTokenManager;
+import org.apache.hive.service.cli.HiveSQLException;
+import org.apache.hive.service.rpc.thrift.TStatus;
+import org.junit.Test;
+import org.apache.thrift.transport.TTransportException;
+
+public class TestDelegationTokenLeakPrevention {
+ private static final String LIVE_TOKEN = "LIVE_DELEGATION_TOKEN_ABC123";
+
+ @Test
+ public void testCancelDelegationTokenExceptionDoesNotContainToken() throws
Exception {
+ MetastoreDelegationTokenManager tokenManager =
mock(MetastoreDelegationTokenManager.class);
+ doThrow(new
IOException("boom")).when(tokenManager).cancelDelegationToken(LIVE_TOKEN);
+
+ HiveAuthFactory authFactory =
createAuthFactoryWithTokenManager(tokenManager);
+ assertTokenIsNotExposed(() ->
authFactory.cancelDelegationToken(LIVE_TOKEN),
+ "Error canceling delegation token");
+ }
+
+ @Test
+ public void testRenewDelegationTokenExceptionDoesNotContainToken() throws
Exception {
+ MetastoreDelegationTokenManager tokenManager =
mock(MetastoreDelegationTokenManager.class);
+ doThrow(new
IOException("boom")).when(tokenManager).renewDelegationToken(LIVE_TOKEN);
+
+ HiveAuthFactory authFactory =
createAuthFactoryWithTokenManager(tokenManager);
+ assertTokenIsNotExposed(() -> authFactory.renewDelegationToken(LIVE_TOKEN),
+ "Error renewing delegation token");
+ }
+
+ @Test
+ public void testVerifyDelegationTokenExceptionDoesNotContainToken() throws
Exception {
+ MetastoreDelegationTokenManager tokenManager =
mock(MetastoreDelegationTokenManager.class);
+ doThrow(new
IOException("boom")).when(tokenManager).verifyDelegationToken(LIVE_TOKEN);
+
+ HiveAuthFactory authFactory =
createAuthFactoryWithTokenManager(tokenManager);
+ assertTokenIsNotExposed(() ->
authFactory.verifyDelegationToken(LIVE_TOKEN),
+ "Error verifying delegation token");
+ }
+
+ @Test
+ public void testGetUserFromTokenExceptionDoesNotContainToken() throws
Exception {
+ MetastoreDelegationTokenManager tokenManager =
mock(MetastoreDelegationTokenManager.class);
+ doThrow(new
IOException("boom")).when(tokenManager).getUserFromToken(LIVE_TOKEN);
+
+ HiveAuthFactory authFactory =
createAuthFactoryWithTokenManager(tokenManager);
+ assertTokenIsNotExposed(() -> authFactory.getUserFromToken(LIVE_TOKEN),
+ "Error extracting user from delegation token");
+ }
+
+ private HiveAuthFactory
createAuthFactoryWithTokenManager(MetastoreDelegationTokenManager tokenManager)
+ throws NoSuchFieldException, IllegalAccessException, TTransportException
{
+ HiveAuthFactory authFactory = new HiveAuthFactory(new HiveConf(), false);
+ Field delegationTokenManagerField =
HiveAuthFactory.class.getDeclaredField("delegationTokenManager");
+ delegationTokenManagerField.setAccessible(true);
+ delegationTokenManagerField.set(authFactory, tokenManager);
+ return authFactory;
+ }
+
+ private void assertTokenIsNotExposed(ThrowingRunnable callback, String
expectedMessagePrefix)
+ throws Exception {
+ try {
+ callback.run();
+ fail("Expected HiveSQLException to be thrown");
+ } catch (HiveSQLException e) {
+ assertMessageIsSanitized(e.getMessage(), expectedMessagePrefix);
+ TStatus status = HiveSQLException.toTStatus(e);
+ assertMessageIsSanitized(status.getErrorMessage(),
expectedMessagePrefix);
+ }
+ }
+
+ private void assertMessageIsSanitized(String message, String
expectedMessagePrefix) {
+ assertTrue(message.contains(expectedMessagePrefix));
+ assertFalse(message.contains(LIVE_TOKEN));
+ }
+
+ @FunctionalInterface
+ private interface ThrowingRunnable {
+ void run() throws Exception;
+ }
+}