This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new f320323ee0e branch-4.1: [fix](auth) Mask credentials in authentication 
and Stream Load logs (#66917)
f320323ee0e is described below

commit f320323ee0e879c4a22b4a0ca0477f021543abc6
Author: bobhan1 <[email protected]>
AuthorDate: Fri Aug 21 10:16:40 2026 +0800

    branch-4.1: [fix](auth) Mask credentials in authentication and Stream Load 
logs (#66917)
    
    ## What problem does this PR solve?
    
    Backport #66618 to `branch-4.1`.
    
    Authentication credentials could be exposed by HTTP authentication and
    Stream Load diagnostic logs. Several FE and BE paths formatted complete
    requests containing `passwd`, `token`, `auth_code`, or `auth_code_uuid`;
    the deprecated `auth_code` header was also missing from the
    sensitive-header filter, and invalid-token errors included the token
    value.
    
    ## What is changed?
    
    - Log sanitized copies of authentication and Stream Load requests.
    - Mask `passwd`, `token`, and `auth_code_uuid`, and omit numeric
    `auth_code` from log-only copies.
    - Treat the `auth_code` HTTP header as sensitive in FE and BE.
    - Remove invalid token values from authentication errors.
    - Preserve the `branch-4.1` JUnit4/JMockit test structure while porting
    the new FE log assertion.
    
    User impact: authentication failures and Stream Load diagnostics retain
    non-sensitive request context without emitting these credential values.
    
    ## Validation
    
    - `./run-fe-ut.sh --run
    
org.apache.doris.common.util.ThriftLogHelperTest,org.apache.doris.service.FrontendServiceImplTest,org.apache.doris.load.StreamLoadHandlerTest`
    — 25 tests passed, 0 failures/errors.
    - `clang-format --dry-run --Werror
    be/src/load/stream_load/stream_load_executor.cpp
    be/src/service/http/http_handler_with_auth.cpp
    be/src/service/http/http_request.cpp
    be/test/service/http/http_auth_test.cpp`
    - `git diff --check upstream/branch-4.1...HEAD`
    - BE UT was not rerun locally for this backport; upstream #66618
    reported its targeted BE tests passing on master.
---
 be/src/load/stream_load/stream_load_executor.cpp   | 22 ++++++-
 be/src/service/http/http_handler_with_auth.cpp     |  8 ++-
 be/src/service/http/http_request.cpp               |  2 +-
 be/test/service/http/http_auth_test.cpp            | 60 +++++++++++++++++-
 .../apache/doris/common/util/ThriftLogHelper.java  | 57 +++++++++++++++++
 .../org/apache/doris/httpv2/rest/LoadAction.java   |  3 +-
 .../org/apache/doris/load/StreamLoadHandler.java   |  3 +-
 .../apache/doris/service/FrontendServiceImpl.java  | 25 +++++---
 .../doris/common/util/ThriftLogHelperTest.java     | 73 ++++++++++++++++++++++
 .../doris/service/FrontendServiceImplTest.java     | 33 ++++++++++
 10 files changed, 268 insertions(+), 18 deletions(-)

diff --git a/be/src/load/stream_load/stream_load_executor.cpp 
b/be/src/load/stream_load/stream_load_executor.cpp
index dd23f034e73..c7594917847 100644
--- a/be/src/load/stream_load/stream_load_executor.cpp
+++ b/be/src/load/stream_load/stream_load_executor.cpp
@@ -54,6 +54,25 @@
 namespace doris {
 using namespace ErrorCode;
 
+namespace {
+
+constexpr const char* MASKED_CREDENTIAL = "***MASKED***";
+
+TLoadTxnCommitRequest request_for_log(const TLoadTxnCommitRequest& request) {
+    TLoadTxnCommitRequest sanitized_request(request);
+    sanitized_request.__set_passwd(MASKED_CREDENTIAL);
+    if (sanitized_request.__isset.token) {
+        sanitized_request.__set_token(MASKED_CREDENTIAL);
+    }
+    sanitized_request.__isset.auth_code = false;
+    if (sanitized_request.__isset.auth_code_uuid) {
+        sanitized_request.__set_auth_code_uuid(MASKED_CREDENTIAL);
+    }
+    return sanitized_request;
+}
+
+} // namespace
+
 #ifdef BE_TEST
 TLoadTxnBeginResult k_stream_load_begin_result;
 TLoadTxnCommitResult k_stream_load_commit_result;
@@ -307,7 +326,8 @@ void 
StreamLoadExecutor::get_commit_request(StreamLoadContext* ctx,
     request.__set_thrift_rpc_timeout_ms(config::txn_commit_rpc_timeout_ms);
     request.__set_tbls(ctx->table_list);
 
-    VLOG_DEBUG << "commit txn request:" << 
apache::thrift::ThriftDebugString(request);
+    VLOG_DEBUG << "commit txn request:"
+               << apache::thrift::ThriftDebugString(request_for_log(request));
 
     // set attachment if has
     TTxnCommitAttachment attachment;
diff --git a/be/src/service/http/http_handler_with_auth.cpp 
b/be/src/service/http/http_handler_with_auth.cpp
index 4a30b5640b8..87b0a51fd0a 100644
--- a/be/src/service/http/http_handler_with_auth.cpp
+++ b/be/src/service/http/http_handler_with_auth.cpp
@@ -112,13 +112,15 @@ int HttpHandlerWithAuth::on_header(HttpRequest* req) {
         auth_result.status.status_code = TStatusCode::type::OK;
         auth_result.status.error_msgs.clear();
     } else {
-        HttpChannel::send_reply(req, HttpStatus::FORBIDDEN);
-        return -1;
+        auth_result.status.status_code = TStatusCode::type::ANALYSIS_ERROR;
+        auth_result.status.error_msgs.clear();
     }
 #endif
     Status status(Status::create(auth_result.status));
     if (!status.ok()) {
-        LOG(WARNING) << "permission verification failed, request: " << 
auth_request;
+        TCheckAuthRequest request_for_log(auth_request);
+        request_for_log.__set_passwd("***MASKED***");
+        LOG(WARNING) << "permission verification failed, request: " << 
request_for_log;
         HttpChannel::send_reply(req, HttpStatus::FORBIDDEN);
         return -1;
     }
diff --git a/be/src/service/http/http_request.cpp 
b/be/src/service/http/http_request.cpp
index 4ae3c7c7f3e..36d5a87a77a 100644
--- a/be/src/service/http/http_request.cpp
+++ b/be/src/service/http/http_request.cpp
@@ -40,7 +40,7 @@ static std::string s_empty = "";
 static bool is_sensitive_header(const std::string& header_name) {
     return iequal(header_name, HttpHeaders::AUTHORIZATION) ||
            iequal(header_name, HttpHeaders::PROXY_AUTHORIZATION) || 
iequal(header_name, "token") ||
-           iequal(header_name, HttpHeaders::AUTH_TOKEN);
+           iequal(header_name, HttpHeaders::AUTH_TOKEN) || iequal(header_name, 
"auth_code");
 }
 
 HttpRequest::HttpRequest(evhttp_request* evhttp_request) : 
_ev_req(evhttp_request) {}
diff --git a/be/test/service/http/http_auth_test.cpp 
b/be/test/service/http/http_auth_test.cpp
index a738dd7922c..d84de03bd06 100644
--- a/be/test/service/http/http_auth_test.cpp
+++ b/be/test/service/http/http_auth_test.cpp
@@ -15,8 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
+#include <glog/logging.h>
 #include <gtest/gtest.h>
 
+#include <string>
+
 #include "common/config.h"
 #include "service/http/ev_http_server.h"
 #include "service/http/http_channel.h"
@@ -40,7 +43,10 @@ public:
 
 private:
     bool on_privilege(const HttpRequest& req, TCheckAuthRequest& auth_request) 
override {
-        return !req.param("table").empty();
+        if (req.param("table").empty()) {
+            return false;
+        }
+        return HttpHandlerWithAuth::on_privilege(req, auth_request);
     };
 };
 
@@ -49,6 +55,17 @@ static HttpAuthTestHandler s_auth_handler =
 
 class HttpAuthTest : public testing::Test {};
 
+class AuthLogSink : public google::LogSink {
+public:
+    void send(google::LogSeverity /*severity*/, const char* /*full_filename*/,
+              const char* /*base_filename*/, int /*line*/, const 
google::LogMessageTime& /*time*/,
+              const char* message, std::size_t message_len) override {
+        messages.append(message, message_len);
+    }
+
+    std::string messages;
+};
+
 TEST_F(HttpAuthTest, disable_auth) {
     EXPECT_FALSE(config::enable_all_http_auth);
 
@@ -90,6 +107,47 @@ TEST_F(HttpAuthTest, enable_all_http_auth) {
     }
 }
 
+TEST_F(HttpAuthTest, failed_auth_does_not_log_password) {
+    Defer restore_auth_config {[]() { config::enable_all_http_auth = false; }};
+    config::enable_all_http_auth = true;
+
+    AuthLogSink log_sink;
+    google::AddLogSink(&log_sink);
+    Defer remove_log_sink {[&log_sink]() { google::RemoveLogSink(&log_sink); 
}};
+
+    auto evhttp_req = evhttp_request_new(nullptr, nullptr);
+    HttpRequest req(evhttp_req);
+    req._headers.emplace(HttpHeaders::AUTHORIZATION, "Basic 
cm9vdDpwbGFpbl90ZXh0X3NlY3JldA==");
+    req._params.emplace("table", "T");
+
+    EXPECT_EQ(s_auth_handler.on_header(&req), -1);
+    EXPECT_NE(log_sink.messages.find("permission verification failed, request: 
TCheckAuthRequest"),
+              std::string::npos);
+    EXPECT_NE(log_sink.messages.find("user=root"), std::string::npos);
+    EXPECT_NE(log_sink.messages.find("passwd=***MASKED***"), 
std::string::npos);
+    EXPECT_NE(log_sink.messages.find("priv_hier=GLOBAL"), std::string::npos);
+    EXPECT_EQ(log_sink.messages.find("plain_text_secret"), std::string::npos);
+    EXPECT_EQ(log_sink.messages.find("cm9vdDpwbGFpbl90ZXh0X3NlY3JldA=="), 
std::string::npos);
+}
+
+TEST_F(HttpAuthTest, invalid_token_does_not_log_token) {
+    Defer restore_auth_config {[]() { config::enable_all_http_auth = false; }};
+    config::enable_all_http_auth = true;
+
+    AuthLogSink log_sink;
+    google::AddLogSink(&log_sink);
+    Defer remove_log_sink {[&log_sink]() { google::RemoveLogSink(&log_sink); 
}};
+
+    auto evhttp_req = evhttp_request_new(nullptr, nullptr);
+    HttpRequest req(evhttp_req);
+    req._headers.emplace(HttpHeaders::AUTH_TOKEN, "plain_text_token");
+
+    EXPECT_EQ(s_auth_handler.on_header(&req), -1);
+    EXPECT_NE(log_sink.messages.find("invalid auth token"), std::string::npos);
+    EXPECT_NE(log_sink.messages.find("value=***MASKED***"), std::string::npos);
+    EXPECT_EQ(log_sink.messages.find("plain_text_token"), std::string::npos);
+}
+
 // Test NONE privilege type - when enable_all_http_auth=true, even NONE type 
requires auth
 TEST_F(HttpAuthTest, privilege_type_none) {
     Defer defer {[]() { config::enable_all_http_auth = false; }};
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/util/ThriftLogHelper.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/ThriftLogHelper.java
new file mode 100644
index 00000000000..45faa64c89b
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/ThriftLogHelper.java
@@ -0,0 +1,57 @@
+// 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.doris.common.util;
+
+import org.apache.thrift.TBase;
+import org.apache.thrift.TFieldIdEnum;
+import org.apache.thrift.meta_data.FieldMetaData;
+
+import java.util.Map;
+
+/** Creates log-only copies of Thrift requests with credential fields masked. 
*/
+public final class ThriftLogHelper {
+    private static final String MASKED_CREDENTIAL = "***MASKED***";
+
+    private ThriftLogHelper() {
+    }
+
+    // auth_code is omitted because its numeric field cannot hold the string 
mask.
+    public static <T extends TBase<T, F>, F extends TFieldIdEnum> T 
requestForLog(T request) {
+        T requestForLog = request.deepCopy();
+        for (Map.Entry<F, FieldMetaData> entry : 
fieldMetadata(request).entrySet()) {
+            F field = entry.getKey();
+            if (!requestForLog.isSet(field)) {
+                continue;
+            }
+
+            String fieldName = entry.getValue().fieldName;
+            if ("auth_code".equals(fieldName)) {
+                requestForLog.setFieldValue(field, null);
+            } else if ("passwd".equals(fieldName) || "token".equals(fieldName)
+                    || "auth_code_uuid".equals(fieldName)) {
+                requestForLog.setFieldValue(field, MASKED_CREDENTIAL);
+            }
+        }
+        return requestForLog;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends TBase<T, F>, F extends TFieldIdEnum> Map<F, 
FieldMetaData> fieldMetadata(T request) {
+        return (Map<F, FieldMetaData>) 
FieldMetaData.getStructMetaDataMap(request.getClass());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java
index 336898c0949..b9ec4025d39 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java
@@ -752,7 +752,8 @@ public class LoadAction extends RestBaseController {
                 || "Cookie".equalsIgnoreCase(headerName)
                 || "Set-Cookie".equalsIgnoreCase(headerName)
                 || "token".equalsIgnoreCase(headerName)
-                || "Auth-Token".equalsIgnoreCase(headerName);
+                || "Auth-Token".equalsIgnoreCase(headerName)
+                || "auth_code".equalsIgnoreCase(headerName);
     }
 
     private Backend selectBackendForGroupCommit(String clusterName, 
HttpServletRequest req, long tableId)
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java 
b/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java
index 1d9c7c660f9..99f516f022e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/load/StreamLoadHandler.java
@@ -36,6 +36,7 @@ import org.apache.doris.common.Config;
 import org.apache.doris.common.LoadException;
 import org.apache.doris.common.MetaNotFoundException;
 import org.apache.doris.common.UserException;
+import org.apache.doris.common.util.ThriftLogHelper;
 import org.apache.doris.load.routineload.RoutineLoadJob;
 import org.apache.doris.nereids.load.NereidsCloudStreamLoadPlanner;
 import org.apache.doris.nereids.load.NereidsStreamLoadPlanner;
@@ -119,7 +120,7 @@ public class StreamLoadHandler {
         }
 
         if (LOG.isDebugEnabled()) {
-            LOG.debug("stream load put request: {}", request);
+            LOG.debug("stream load put request: {}", 
ThriftLogHelper.requestForLog(request));
         }
         // create connect context
         ConnectContext ctx = new ConnectContext();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java 
b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
index 19e8376386a..e6470e2074f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
@@ -85,6 +85,7 @@ import org.apache.doris.common.io.Text;
 import org.apache.doris.common.util.DebugPointUtil;
 import org.apache.doris.common.util.DebugPointUtil.DebugPoint;
 import org.apache.doris.common.util.PropertyAnalyzer;
+import org.apache.doris.common.util.ThriftLogHelper;
 import org.apache.doris.common.util.Util;
 import org.apache.doris.cooldown.CooldownDelete;
 import org.apache.doris.datasource.CatalogIf;
@@ -1339,7 +1340,7 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     public TLoadTxnBeginResult loadTxnBegin(TLoadTxnBeginRequest request) 
throws TException {
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive txn begin request: {}, backend: {}", request, 
clientAddr);
+            LOG.debug("receive txn begin request: {}, backend: {}", 
ThriftLogHelper.requestForLog(request), clientAddr);
         }
         if (request.isSetCertBasedAuth()) {
             TCertBasedAuth certAuth = request.getCertBasedAuth();
@@ -1402,7 +1403,7 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
                     toForwardedCertificateInfo(request.getCertBasedAuth()));
         } else {
             if (!checkToken(request.getToken())) {
-                throw new AuthenticationException("Invalid token: " + 
request.getToken());
+                throw new AuthenticationException("Invalid token");
             }
         }
 
@@ -1568,7 +1569,8 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     public TLoadTxnCommitResult loadTxnPreCommit(TLoadTxnCommitRequest 
request) throws TException {
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive txn pre-commit request: {}, backend: {}", 
request, clientAddr);
+            LOG.debug("receive txn pre-commit request: {}, backend: {}",
+                    ThriftLogHelper.requestForLog(request), clientAddr);
         }
 
         TLoadTxnCommitResult result = new TLoadTxnCommitResult();
@@ -1668,7 +1670,7 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
             // TODO: deprecated, removed in 3.1, use token instead.
         } else if (request.isSetToken()) {
             if (!checkToken(request.getToken())) {
-                throw new AuthenticationException("Invalid token: " + 
request.getToken());
+                throw new AuthenticationException("Invalid token");
             }
         } else {
             if (CollectionUtils.isNotEmpty(request.getTbls())) {
@@ -1711,7 +1713,7 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     public TLoadTxn2PCResult loadTxn2PC(TLoadTxn2PCRequest request) throws 
TException {
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive txn 2PC request: {}, backend: {}", request, 
clientAddr);
+            LOG.debug("receive txn 2PC request: {}, backend: {}", 
ThriftLogHelper.requestForLog(request), clientAddr);
         }
 
         TLoadTxn2PCResult result = new TLoadTxn2PCResult();
@@ -1803,7 +1805,8 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
         deleteMultiTableStreamLoadJobIndex(request.getTxnId());
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive txn commit request: {}, backend: {}", request, 
clientAddr);
+            LOG.debug("receive txn commit request: {}, backend: {}",
+                    ThriftLogHelper.requestForLog(request), clientAddr);
         }
 
         TLoadTxnCommitResult result = new TLoadTxnCommitResult();
@@ -2045,7 +2048,8 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     public TLoadTxnRollbackResult loadTxnRollback(TLoadTxnRollbackRequest 
request) throws TException {
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive txn rollback request: {}, backend: {}", 
request, clientAddr);
+            LOG.debug("receive txn rollback request: {}, backend: {}",
+                    ThriftLogHelper.requestForLog(request), clientAddr);
         }
         TLoadTxnRollbackResult result = new TLoadTxnRollbackResult();
         TStatus status = checkMaster();
@@ -2286,7 +2290,8 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     public TStreamLoadPutResult streamLoadPut(TStreamLoadPutRequest request) {
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive stream load put request: {}, backend: {}", 
request, clientAddr);
+            LOG.debug("receive stream load put request: {}, backend: {}",
+                    ThriftLogHelper.requestForLog(request), clientAddr);
         }
 
         String groupCommitMode = request.getGroupCommitMode();
@@ -2439,7 +2444,7 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     private void httpStreamPutImpl(TStreamLoadPutRequest request, 
TStreamLoadPutResult result)
             throws UserException {
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive http stream put request: {}", request);
+            LOG.debug("receive http stream put request: {}", 
ThriftLogHelper.requestForLog(request));
         }
 
         ConnectContext ctx = ConnectContext.get();
@@ -2762,7 +2767,7 @@ public class FrontendServiceImpl implements 
FrontendService.Iface {
     public TCheckAuthResult checkAuth(TCheckAuthRequest request) throws 
TException {
         String clientAddr = getClientAddrAsString();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("receive auth request: {}, backend: {}", request, 
clientAddr);
+            LOG.debug("receive auth request: {}, backend: {}", 
ThriftLogHelper.requestForLog(request), clientAddr);
         }
 
         TCheckAuthResult result = new TCheckAuthResult();
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/util/ThriftLogHelperTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/common/util/ThriftLogHelperTest.java
new file mode 100644
index 00000000000..388fe64cd40
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/common/util/ThriftLogHelperTest.java
@@ -0,0 +1,73 @@
+// 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.doris.common.util;
+
+import org.apache.doris.thrift.TLoadTxnBeginRequest;
+import org.apache.doris.thrift.TStreamLoadPutRequest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ThriftLogHelperTest {
+    private static final String MASKED_CREDENTIAL = "***MASKED***";
+
+    @Test
+    public void testRequestForLogMasksCredentialsByFieldName() {
+        TLoadTxnBeginRequest beginRequest = new TLoadTxnBeginRequest()
+                .setUser("user")
+                .setPasswd("password")
+                .setDb("db")
+                .setTbl("table")
+                .setLabel("label")
+                .setToken("token")
+                .setAuthCode(123)
+                .setAuthCodeUuid("auth-code-uuid");
+
+        TLoadTxnBeginRequest beginRequestForLog = 
ThriftLogHelper.requestForLog(beginRequest);
+
+        Assertions.assertEquals(MASKED_CREDENTIAL, 
beginRequestForLog.getPasswd());
+        Assertions.assertEquals(MASKED_CREDENTIAL, 
beginRequestForLog.getToken());
+        Assertions.assertEquals(MASKED_CREDENTIAL, 
beginRequestForLog.getAuthCodeUuid());
+        Assertions.assertFalse(beginRequestForLog.isSetAuthCode());
+        Assertions.assertEquals("user", beginRequestForLog.getUser());
+        Assertions.assertEquals("label", beginRequestForLog.getLabel());
+        Assertions.assertEquals("password", beginRequest.getPasswd());
+        Assertions.assertEquals("token", beginRequest.getToken());
+        Assertions.assertEquals(123, beginRequest.getAuthCode());
+        Assertions.assertEquals("auth-code-uuid", 
beginRequest.getAuthCodeUuid());
+
+        TStreamLoadPutRequest putRequest = new TStreamLoadPutRequest()
+                .setUser("load-user")
+                .setPasswd("load-password")
+                .setDb("load-db")
+                .setTbl("load-table")
+                .setToken("load-token")
+                .setAuthCode(456);
+
+        TStreamLoadPutRequest putRequestForLog = 
ThriftLogHelper.requestForLog(putRequest);
+
+        Assertions.assertEquals(MASKED_CREDENTIAL, 
putRequestForLog.getPasswd());
+        Assertions.assertEquals(MASKED_CREDENTIAL, 
putRequestForLog.getToken());
+        Assertions.assertFalse(putRequestForLog.isSetAuthCode());
+        Assertions.assertEquals("load-user", putRequestForLog.getUser());
+        Assertions.assertEquals("load-table", putRequestForLog.getTbl());
+        Assertions.assertEquals("load-password", putRequest.getPasswd());
+        Assertions.assertEquals("load-token", putRequest.getToken());
+        Assertions.assertEquals(456, putRequest.getAuthCode());
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
index eef4db1a7a6..e45bed95a47 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
@@ -33,6 +33,7 @@ import org.apache.doris.common.util.PrintableMap;
 import org.apache.doris.datasource.InternalCatalog;
 import org.apache.doris.datasource.maxcompute.MCTransaction;
 import org.apache.doris.datasource.maxcompute.MaxComputeExternalCatalog;
+import org.apache.doris.mysql.authenticate.TestLogAppender;
 import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.trees.plans.commands.Command;
 import org.apache.doris.nereids.trees.plans.commands.CreateDatabaseCommand;
@@ -42,6 +43,8 @@ import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.StmtExecutor;
 import org.apache.doris.tablefunction.BackendsTableValuedFunction;
 import org.apache.doris.thrift.TBackendsMetadataParams;
+import org.apache.doris.thrift.TCheckAuthRequest;
+import org.apache.doris.thrift.TCheckAuthResult;
 import org.apache.doris.thrift.TCommitTxnRequest;
 import org.apache.doris.thrift.TCreatePartitionRequest;
 import org.apache.doris.thrift.TCreatePartitionResult;
@@ -61,6 +64,9 @@ import org.apache.doris.thrift.TMaxComputeBlockIdResult;
 import org.apache.doris.thrift.TMetadataTableRequestParams;
 import org.apache.doris.thrift.TMetadataType;
 import org.apache.doris.thrift.TNullableStringLiteral;
+import org.apache.doris.thrift.TPrivilegeCtrl;
+import org.apache.doris.thrift.TPrivilegeHier;
+import org.apache.doris.thrift.TPrivilegeType;
 import org.apache.doris.thrift.TRollbackTxnRequest;
 import org.apache.doris.thrift.TSchemaTableName;
 import org.apache.doris.thrift.TSchemaTableRequestParams;
@@ -74,6 +80,7 @@ import org.apache.doris.utframe.UtFrameUtils;
 
 import com.google.common.collect.Sets;
 import mockit.Mocked;
+import org.apache.logging.log4j.Level;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -154,6 +161,32 @@ public class FrontendServiceImplTest {
         field.set(target, value);
     }
 
+    @Test
+    public void testCheckAuthDoesNotLogPassword() throws Exception {
+        FrontendServiceImpl impl = new FrontendServiceImpl(exeEnv);
+        TPrivilegeCtrl privilegeCtrl = new TPrivilegeCtrl();
+        privilegeCtrl.setPrivHier(TPrivilegeHier.GLOBAL);
+        TCheckAuthRequest request = new TCheckAuthRequest();
+        request.setUser("root");
+        request.setPasswd("plain_text_secret");
+        request.setUserIp("127.0.0.1");
+        request.setPrivCtrl(privilegeCtrl);
+        request.setPrivType(TPrivilegeType.LOAD);
+
+        try (TestLogAppender appender = 
TestLogAppender.attach(FrontendServiceImpl.class)) {
+            TCheckAuthResult result = impl.checkAuth(request);
+
+            Assert.assertEquals(TStatusCode.ANALYSIS_ERROR, 
result.getStatus().getStatusCode());
+            Assert.assertTrue(appender.contains(Level.DEBUG,
+                    "receive auth request: TCheckAuthRequest"));
+            Assert.assertTrue(appender.contains(Level.DEBUG, "user:root"));
+            Assert.assertTrue(appender.contains(Level.DEBUG, 
"passwd:***MASKED***"));
+            Assert.assertTrue(appender.contains(Level.DEBUG, 
"user_ip:127.0.0.1"));
+            Assert.assertTrue(appender.contains(Level.DEBUG, 
"priv_hier:GLOBAL"));
+            Assert.assertFalse(appender.contains(Level.DEBUG, 
"plain_text_secret"));
+        }
+    }
+
     @Test
     public void testGetTableNamesWithSysTablePattern() throws Exception {
         FrontendServiceImpl impl = new FrontendServiceImpl(exeEnv);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to