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

kirs pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 2edc65c694d  [feat](auth) support querying authentication integrations 
from system table (#61246)
2edc65c694d is described below

commit 2edc65c694df31ad63832bc9ff4f959865af9571
Author: Calvin Kirs <[email protected]>
AuthorDate: Tue Mar 17 12:34:56 2026 +0800

     [feat](auth) support querying authentication integrations from system 
table (#61246)
    
    ### What problem does this PR solve?
    
    #60361
    
    `AUTHENTICATION INTEGRATION` currently has no system-table query entry,
    so users cannot inspect existing integrations through SQL in a
    consistent way with other metadata objects.
    
    At the same time, upstream has already introduced unified audit metadata
    for `AuthenticationIntegrationMeta`, including:
      - `createUser`
      - `createTime`
      - `alterUser`
      - `modifyTime`
    
    But these fields are not exposed through a queryable metadata path yet.
    
    This PR adds a system table for querying authentication integrations and
    synchronizes the query result with the new audit metadata.
    
      ### What is changed
    
      - Add `information_schema.authentication_integrations`
      - Wire the schema table through FE/BE/Thrift
      - Expose the following columns:
        - `NAME`
        - `TYPE`
        - `PROPERTIES`
        - `COMMENT`
        - `CREATE_USER`
        - `CREATE_TIME`
        - `ALTER_USER`
        - `MODIFY_TIME`
      - Mask sensitive properties in query results
        - existing password/secret/token/keytab-style keys remain masked
        - keys with prefix `secret.` are also masked
    - Add FE unit tests and regression coverage for querying this system
    table
    
      ### Example
    
      ```sql
      SELECT *
      FROM information_schema.authentication_integrations;
    
      SELECT
          name,
          type,
          comment,
          create_user,
          create_time,
          alter_user,
          modify_time,
          properties
      FROM information_schema.authentication_integrations
      ORDER BY name;
    
      ### Why is this safe?
    
      - This change only adds metadata query capability
    - It does not change existing CREATE/ALTER/DROP AUTHENTICATION
    INTEGRATION semantics
    - Sensitive properties are masked only in display/query results, not
    modified in persisted metadata
    
      ### Test
    
      - FE unit test:
          - org.apache.doris.service.FrontendServiceImplTest
          - org.apache.doris.catalog.SchemaTableTest
      - Regression test:
    -
    regression-test/suites/auth_p0/test_authentication_integration_auth.groovy
---
 .../schema_authentication_integrations_scanner.cpp | 148 +++++++++++++++++++++
 .../schema_authentication_integrations_scanner.h   |  53 ++++++++
 be/src/information_schema/schema_scanner.cpp       |   3 +
 .../org/apache/doris/analysis/SchemaTableType.java |   4 +-
 .../java/org/apache/doris/catalog/SchemaTable.java |  11 ++
 .../doris/tablefunction/MetadataGenerator.java     |  96 +++++++++++++
 .../org/apache/doris/catalog/SchemaTableTest.java  |  10 ++
 .../doris/service/FrontendServiceImplTest.java     |  56 ++++++++
 gensrc/thrift/Descriptors.thrift                   |   1 +
 gensrc/thrift/FrontendService.thrift               |   1 +
 .../test_authentication_integration_auth.groovy    |  35 ++++-
 11 files changed, 415 insertions(+), 3 deletions(-)

diff --git 
a/be/src/information_schema/schema_authentication_integrations_scanner.cpp 
b/be/src/information_schema/schema_authentication_integrations_scanner.cpp
new file mode 100644
index 00000000000..c1edd00aa7c
--- /dev/null
+++ b/be/src/information_schema/schema_authentication_integrations_scanner.cpp
@@ -0,0 +1,148 @@
+// 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.
+
+#include "information_schema/schema_authentication_integrations_scanner.h"
+
+#include <utility>
+
+#include "core/block/block.h"
+#include "core/data_type/data_type_factory.hpp"
+#include "core/string_ref.h"
+#include "information_schema/schema_helper.h"
+#include "runtime/exec_env.h"
+#include "runtime/runtime_state.h"
+#include "util/client_cache.h"
+#include "util/thrift_rpc_helper.h"
+
+namespace doris {
+#include "common/compile_check_begin.h"
+
+std::vector<SchemaScanner::ColumnDesc> 
SchemaAuthenticationIntegrationsScanner::_s_tbls_columns = {
+        {"NAME", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"TYPE", TYPE_VARCHAR, sizeof(StringRef), true},
+        {"PROPERTIES", TYPE_STRING, sizeof(StringRef), true},
+        {"COMMENT", TYPE_STRING, sizeof(StringRef), true},
+        {"CREATE_USER", TYPE_STRING, sizeof(StringRef), true},
+        {"CREATE_TIME", TYPE_STRING, sizeof(StringRef), true},
+        {"ALTER_USER", TYPE_STRING, sizeof(StringRef), true},
+        {"MODIFY_TIME", TYPE_STRING, sizeof(StringRef), true},
+};
+
+SchemaAuthenticationIntegrationsScanner::SchemaAuthenticationIntegrationsScanner()
+        : SchemaScanner(_s_tbls_columns, 
TSchemaTableType::SCH_AUTHENTICATION_INTEGRATIONS) {}
+
+Status SchemaAuthenticationIntegrationsScanner::start(RuntimeState* state) {
+    if (!_is_init) {
+        return Status::InternalError("used before initialized.");
+    }
+    _block_rows_limit = state->batch_size();
+    _rpc_timeout_ms = state->execution_timeout() * 1000;
+    return Status::OK();
+}
+
+Status 
SchemaAuthenticationIntegrationsScanner::_get_authentication_integrations_block_from_fe()
 {
+    TNetworkAddress master_addr = 
ExecEnv::GetInstance()->cluster_info()->master_fe_addr;
+
+    TSchemaTableRequestParams schema_table_request_params;
+    for (int i = 0; i < _s_tbls_columns.size(); i++) {
+        schema_table_request_params.__isset.columns_name = true;
+        
schema_table_request_params.columns_name.emplace_back(_s_tbls_columns[i].name);
+    }
+    
schema_table_request_params.__set_current_user_ident(*_param->common_param->current_user_ident);
+    if (_param->common_param->frontend_conjuncts) {
+        schema_table_request_params.__set_frontend_conjuncts(
+                *_param->common_param->frontend_conjuncts);
+    }
+
+    TFetchSchemaTableDataRequest request;
+    
request.__set_schema_table_name(TSchemaTableName::AUTHENTICATION_INTEGRATIONS);
+    request.__set_schema_table_params(schema_table_request_params);
+
+    TFetchSchemaTableDataResult result;
+    RETURN_IF_ERROR(ThriftRpcHelper::rpc<FrontendServiceClient>(
+            master_addr.hostname, master_addr.port,
+            [&request, &result](FrontendServiceConnection& client) {
+                client->fetchSchemaTableData(result, request);
+            },
+            _rpc_timeout_ms));
+
+    Status status(Status::create(result.status));
+    if (!status.ok()) {
+        LOG(WARNING) << "fetch authentication integrations from FE failed, 
errmsg=" << status;
+        return status;
+    }
+
+    _authentication_integrations_block = Block::create_unique();
+    for (int i = 0; i < _s_tbls_columns.size(); ++i) {
+        auto data_type =
+                
DataTypeFactory::instance().create_data_type(_s_tbls_columns[i].type, true);
+        _authentication_integrations_block->insert(ColumnWithTypeAndName(
+                data_type->create_column(), data_type, 
_s_tbls_columns[i].name));
+    }
+    _authentication_integrations_block->reserve(_block_rows_limit);
+
+    std::vector<TRow> result_data = std::move(result.data_batch);
+    if (!result_data.empty()) {
+        auto col_size = result_data[0].column_value.size();
+        if (col_size != _s_tbls_columns.size()) {
+            return Status::InternalError<false>(
+                    "authentication integrations schema is not match for FE 
and BE");
+        }
+    }
+
+    for (int i = 0; i < result_data.size(); i++) {
+        const TRow& row = result_data[i];
+        for (int j = 0; j < _s_tbls_columns.size(); j++) {
+            RETURN_IF_ERROR(insert_block_column(row.column_value[j], j,
+                                                
_authentication_integrations_block.get(),
+                                                _s_tbls_columns[j].type));
+        }
+    }
+    return Status::OK();
+}
+
+Status SchemaAuthenticationIntegrationsScanner::get_next_block_internal(Block* 
block, bool* eos) {
+    if (!_is_init) {
+        return Status::InternalError("Used before initialized.");
+    }
+
+    if (nullptr == block || nullptr == eos) {
+        return Status::InternalError("input pointer is nullptr.");
+    }
+
+    if (_authentication_integrations_block == nullptr) {
+        RETURN_IF_ERROR(_get_authentication_integrations_block_from_fe());
+        _total_rows = 
static_cast<int>(_authentication_integrations_block->rows());
+    }
+
+    if (_row_idx == _total_rows) {
+        *eos = true;
+        return Status::OK();
+    }
+
+    int current_batch_rows = std::min(_block_rows_limit, _total_rows - 
_row_idx);
+    MutableBlock mblock = MutableBlock::build_mutable_block(block);
+    RETURN_IF_ERROR(mblock.add_rows(_authentication_integrations_block.get(), 
_row_idx,
+                                    current_batch_rows));
+    _row_idx += current_batch_rows;
+
+    *eos = _row_idx == _total_rows;
+    return Status::OK();
+}
+
+#include "common/compile_check_end.h"
+} // namespace doris
diff --git 
a/be/src/information_schema/schema_authentication_integrations_scanner.h 
b/be/src/information_schema/schema_authentication_integrations_scanner.h
new file mode 100644
index 00000000000..285a6a1a24a
--- /dev/null
+++ b/be/src/information_schema/schema_authentication_integrations_scanner.h
@@ -0,0 +1,53 @@
+// 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.
+
+#pragma once
+
+#include <gen_cpp/FrontendService_types.h>
+
+#include <vector>
+
+#include "common/status.h"
+#include "information_schema/schema_scanner.h"
+
+namespace doris {
+class RuntimeState;
+class Block;
+
+class SchemaAuthenticationIntegrationsScanner : public SchemaScanner {
+    ENABLE_FACTORY_CREATOR(SchemaAuthenticationIntegrationsScanner);
+
+public:
+    SchemaAuthenticationIntegrationsScanner();
+    ~SchemaAuthenticationIntegrationsScanner() override = default;
+
+    Status start(RuntimeState* state) override;
+    Status get_next_block_internal(Block* block, bool* eos) override;
+
+    static std::vector<SchemaScanner::ColumnDesc> _s_tbls_columns;
+
+private:
+    Status _get_authentication_integrations_block_from_fe();
+
+    int _block_rows_limit = 4096;
+    int _row_idx = 0;
+    int _total_rows = 0;
+    int _rpc_timeout_ms = 3000;
+    std::unique_ptr<Block> _authentication_integrations_block = nullptr;
+};
+
+} // namespace doris
diff --git a/be/src/information_schema/schema_scanner.cpp 
b/be/src/information_schema/schema_scanner.cpp
index a03c40b28c1..a4f0b5e2103 100644
--- a/be/src/information_schema/schema_scanner.cpp
+++ b/be/src/information_schema/schema_scanner.cpp
@@ -43,6 +43,7 @@
 #include "core/value/hll.h"
 #include "exec/pipeline/dependency.h"
 #include "information_schema/schema_active_queries_scanner.h"
+#include "information_schema/schema_authentication_integrations_scanner.h"
 #include "information_schema/schema_backend_active_tasks.h"
 #include "information_schema/schema_backend_configuration_scanner.h"
 #include "information_schema/schema_backend_kerberos_ticket_cache.h"
@@ -261,6 +262,8 @@ std::unique_ptr<SchemaScanner> 
SchemaScanner::create(TSchemaTableType::type type
         return SchemaColumnDataSizesScanner::create_unique();
     case TSchemaTableType::SCH_FILE_CACHE_INFO:
         return SchemaFileCacheInfoScanner::create_unique();
+    case TSchemaTableType::SCH_AUTHENTICATION_INTEGRATIONS:
+        return SchemaAuthenticationIntegrationsScanner::create_unique();
     default:
         return SchemaDummyScanner::create_unique();
         break;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
index 02ea8a610a4..ad3d2655dcb 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java
@@ -114,7 +114,9 @@ public enum SchemaTableType {
     SCH_COLUMN_DATA_SIZES("COLUMN_DATA_SIZES", "COLUMN_DATA_SIZES",
             TSchemaTableType.SCH_COLUMN_DATA_SIZES),
     SCH_DATABASE_PROPERTIES("DATABASE_PROPERTIES", "DATABASE_PROPERTIES",
-            TSchemaTableType.SCH_DATABASE_PROPERTIES);
+            TSchemaTableType.SCH_DATABASE_PROPERTIES),
+    SCH_AUTHENTICATION_INTEGRATIONS("AUTHENTICATION_INTEGRATIONS", 
"AUTHENTICATION_INTEGRATIONS",
+            TSchemaTableType.SCH_AUTHENTICATION_INTEGRATIONS);
 
     private static final String dbName = "INFORMATION_SCHEMA";
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
index d2f11508db2..d3da150b3fa 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/SchemaTable.java
@@ -816,6 +816,17 @@ public class SchemaTable extends Table {
                             .column("MAX_RESERVED_SNAPSHOTS", 
ScalarType.createType(PrimitiveType.BIGINT))
                             .column("SNAPSHOT_INTERVAL_SECONDS", 
ScalarType.createType(PrimitiveType.BIGINT))
                             .build()))
+            .put("authentication_integrations",
+                    new SchemaTable(SystemIdGenerator.getNextId(), 
"authentication_integrations", TableType.SCHEMA,
+                        builder().column("NAME", ScalarType.createVarchar(256))
+                            .column("TYPE", ScalarType.createVarchar(64))
+                            .column("PROPERTIES", 
ScalarType.createStringType())
+                            .column("COMMENT", ScalarType.createStringType())
+                            .column("CREATE_USER", 
ScalarType.createStringType())
+                            .column("CREATE_TIME", 
ScalarType.createStringType())
+                            .column("ALTER_USER", 
ScalarType.createStringType())
+                            .column("MODIFY_TIME", 
ScalarType.createStringType())
+                            .build()))
             .build();
 
     private boolean fetchAllFe = false;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
index fd70373fbdb..97af4edbafc 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java
@@ -18,6 +18,7 @@
 package org.apache.doris.tablefunction;
 
 import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.authentication.AuthenticationIntegrationMeta;
 import org.apache.doris.blockrule.SqlBlockRule;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.DataProperty;
@@ -47,6 +48,7 @@ import org.apache.doris.common.Pair;
 import org.apache.doris.common.proc.FrontendsProcNode;
 import org.apache.doris.common.proc.PartitionsProcDir;
 import org.apache.doris.common.profile.RuntimeProfile;
+import org.apache.doris.common.util.DatasourcePrintableMap;
 import org.apache.doris.common.util.DebugUtil;
 import org.apache.doris.common.util.NetUtils;
 import org.apache.doris.common.util.TimeUtils;
@@ -128,7 +130,9 @@ import org.jetbrains.annotations.NotNull;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
@@ -158,6 +162,8 @@ public class MetadataGenerator {
 
     private static final ImmutableMap<String, Integer> 
SQL_BLOCK_RULE_STATUS_COLUMN_TO_INDEX;
 
+    private static final ImmutableMap<String, Integer> 
AUTHENTICATION_INTEGRATIONS_COLUMN_TO_INDEX;
+
     static {
         ImmutableMap.Builder<String, Integer> activeQueriesbuilder = new 
ImmutableMap.Builder();
         List<Column> activeQueriesColList = 
SchemaTable.TABLE_MAP.get("active_queries").getFullSchema();
@@ -235,6 +241,15 @@ public class MetadataGenerator {
             
sqlBlockRuleStatusBuilder.put(sqlBlockRuleStatusBuilderColList.get(i).getName().toLowerCase(),
 i);
         }
         SQL_BLOCK_RULE_STATUS_COLUMN_TO_INDEX = 
sqlBlockRuleStatusBuilder.build();
+
+        ImmutableMap.Builder<String, Integer> 
authenticationIntegrationsBuilder = new ImmutableMap.Builder();
+        List<Column> authenticationIntegrationsColList = 
SchemaTable.TABLE_MAP.get("authentication_integrations")
+                .getFullSchema();
+        for (int i = 0; i < authenticationIntegrationsColList.size(); i++) {
+            authenticationIntegrationsBuilder.put(
+                    
authenticationIntegrationsColList.get(i).getName().toLowerCase(), i);
+        }
+        AUTHENTICATION_INTEGRATIONS_COLUMN_TO_INDEX = 
authenticationIntegrationsBuilder.build();
     }
 
     public static TFetchSchemaTableDataResult 
getMetadataTable(TFetchSchemaTableDataRequest request) throws TException {
@@ -349,6 +364,10 @@ public class MetadataGenerator {
                 result = sqlBlockRuleStatusMetadataResult(schemaTableParams);
                 columnIndex = SQL_BLOCK_RULE_STATUS_COLUMN_TO_INDEX;
                 break;
+            case AUTHENTICATION_INTEGRATIONS:
+                result = 
authenticationIntegrationsMetadataResult(schemaTableParams);
+                columnIndex = AUTHENTICATION_INTEGRATIONS_COLUMN_TO_INDEX;
+                break;
             default:
                 return errorResult("invalid schema table name.");
         }
@@ -689,6 +708,83 @@ public class MetadataGenerator {
         return result;
     }
 
+    private static TFetchSchemaTableDataResult 
authenticationIntegrationsMetadataResult(
+            TSchemaTableRequestParams params) {
+        if (!params.isSetCurrentUserIdent()) {
+            return errorResult("current user ident is not set.");
+        }
+        UserIdentity currentUserIdentity = 
UserIdentity.fromThrift(params.getCurrentUserIdent());
+        TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult();
+        List<TRow> dataBatch = Lists.newArrayList();
+        result.setDataBatch(dataBatch);
+        result.setStatus(new TStatus(TStatusCode.OK));
+        if 
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(currentUserIdentity, 
PrivPredicate.ADMIN)) {
+            return result;
+        }
+
+        List<Expression> conjuncts = Collections.EMPTY_LIST;
+        if (params.isSetFrontendConjuncts()) {
+            conjuncts = 
FrontendConjunctsUtils.convertToExpression(params.getFrontendConjuncts());
+        }
+        List<Expression> nameConjuncts = 
FrontendConjunctsUtils.filterBySlotName(conjuncts, "NAME");
+        List<Expression> typeConjuncts = 
FrontendConjunctsUtils.filterBySlotName(conjuncts, "TYPE");
+
+        for (AuthenticationIntegrationMeta meta : 
Env.getCurrentEnv().getAuthenticationIntegrationMgr()
+                .getAuthenticationIntegrations().values()) {
+            if (FrontendConjunctsUtils.isFiltered(nameConjuncts, "NAME", 
meta.getName())
+                    || FrontendConjunctsUtils.isFiltered(typeConjuncts, 
"TYPE", meta.getType())) {
+                continue;
+            }
+            TRow row = new TRow();
+            row.addToColumnValue(new TCell().setStringVal(meta.getName()));
+            row.addToColumnValue(new TCell().setStringVal(meta.getType()));
+            row.addToColumnValue(new 
TCell().setStringVal(maskAuthenticationProperties(meta.getProperties())));
+            if (meta.getComment() == null) {
+                row.addToColumnValue(new TCell());
+            } else {
+                row.addToColumnValue(new 
TCell().setStringVal(meta.getComment()));
+            }
+            row.addToColumnValue(new 
TCell().setStringVal(meta.getCreateUser()));
+            row.addToColumnValue(new 
TCell().setStringVal(meta.getCreateTimeString()));
+            row.addToColumnValue(new 
TCell().setStringVal(meta.getAlterUser()));
+            row.addToColumnValue(new 
TCell().setStringVal(meta.getModifyTimeString()));
+            dataBatch.add(row);
+        }
+        return result;
+    }
+
+    private static String maskAuthenticationProperties(Map<String, String> 
properties) {
+        Map<String, String> maskedProperties = new LinkedHashMap<>();
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+            if (shouldMaskAuthenticationProperty(entry.getKey())) {
+                maskedProperties.put(entry.getKey(), 
DatasourcePrintableMap.PASSWORD_MASK);
+            } else {
+                maskedProperties.put(entry.getKey(), entry.getValue());
+            }
+        }
+        return new DatasourcePrintableMap<>(maskedProperties, "=", true, 
false).toString();
+    }
+
+    private static boolean shouldMaskAuthenticationProperty(String key) {
+        String lowerCaseKey = key.toLowerCase(Locale.ROOT);
+        return DatasourcePrintableMap.SENSITIVE_KEY.contains(key)
+                || lowerCaseKey.startsWith("secret.")
+                || lowerCaseKey.endsWith(".password")
+                || lowerCaseKey.endsWith("_password")
+                || lowerCaseKey.equals("secret")
+                || lowerCaseKey.endsWith(".secret")
+                || lowerCaseKey.endsWith("_secret")
+                || lowerCaseKey.endsWith(".secret_key")
+                || lowerCaseKey.endsWith("_secret_key")
+                || lowerCaseKey.endsWith(".token")
+                || lowerCaseKey.endsWith("_token")
+                || lowerCaseKey.endsWith(".credential")
+                || lowerCaseKey.endsWith("_credential")
+                || lowerCaseKey.endsWith(".keytab")
+                || lowerCaseKey.endsWith("_keytab")
+                || lowerCaseKey.endsWith("keytab_content");
+    }
+
     private static TFetchSchemaTableDataResult 
viewDependencyMetadataResult(TSchemaTableRequestParams params) {
         if (!params.isSetCurrentUserIdent()) {
             return errorResult("current user ident is not set.");
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/catalog/SchemaTableTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/catalog/SchemaTableTest.java
index 03c6d092eab..9970d50a37a 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/SchemaTableTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/SchemaTableTest.java
@@ -92,5 +92,15 @@ public class SchemaTableTest {
         SchemaTable viewDependency = (SchemaTable) 
SchemaTable.TABLE_MAP.get("view_dependency");
         Assertions.assertFalse(viewDependency.shouldFetchAllFe());
         Assertions.assertFalse(viewDependency.shouldAddAgg());
+
+        SchemaTable authenticationIntegrations =
+                (SchemaTable) 
SchemaTable.TABLE_MAP.get("authentication_integrations");
+        Assertions.assertFalse(authenticationIntegrations.shouldFetchAllFe());
+        Assertions.assertFalse(authenticationIntegrations.shouldAddAgg());
+        Assertions.assertEquals(8, 
authenticationIntegrations.getFullSchema().size());
+        Assertions.assertEquals("CREATE_USER", 
authenticationIntegrations.getFullSchema().get(4).getName());
+        Assertions.assertEquals("CREATE_TIME", 
authenticationIntegrations.getFullSchema().get(5).getName());
+        Assertions.assertEquals("ALTER_USER", 
authenticationIntegrations.getFullSchema().get(6).getName());
+        Assertions.assertEquals("MODIFY_TIME", 
authenticationIntegrations.getFullSchema().get(7).getName());
     }
 }
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 f78d1bdf6e7..00903892b23 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
@@ -23,6 +23,7 @@ import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.Partition;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.FeConstants;
+import org.apache.doris.common.util.DatasourcePrintableMap;
 import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.trees.plans.commands.CreateDatabaseCommand;
 import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand;
@@ -41,6 +42,7 @@ import org.apache.doris.thrift.TMetadataTableRequestParams;
 import org.apache.doris.thrift.TMetadataType;
 import org.apache.doris.thrift.TNullableStringLiteral;
 import org.apache.doris.thrift.TSchemaTableName;
+import org.apache.doris.thrift.TSchemaTableRequestParams;
 import org.apache.doris.thrift.TShowUserRequest;
 import org.apache.doris.thrift.TShowUserResult;
 import org.apache.doris.thrift.TStatusCode;
@@ -57,6 +59,7 @@ import org.junit.rules.ExpectedException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.UUID;
 import java.util.stream.Collectors;
@@ -247,4 +250,57 @@ public class FrontendServiceImplTest {
         TShowUserResult result = impl.showUser(request);
         System.out.println(result);
     }
+
+    @Test
+    public void testFetchAuthenticationIntegrationsSchemaTableData() throws 
Exception {
+        String integrationName = "test_authentication_integration";
+        
Env.getCurrentEnv().getAuthenticationIntegrationMgr().dropAuthenticationIntegration(integrationName,
 true);
+
+        LinkedHashMap<String, String> properties = new LinkedHashMap<>();
+        properties.put("type", "ldap");
+        properties.put("server", "ldap://127.0.0.1:389";);
+        properties.put("bind_password", "plain_secret");
+        properties.put("secret.endpoint", "masked_by_prefix");
+        Env.getCurrentEnv().getAuthenticationIntegrationMgr()
+                .createAuthenticationIntegration(
+                        integrationName, false, properties, "ldap comment", 
connectContext.getQualifiedUser());
+
+        try {
+            FrontendServiceImpl impl = new FrontendServiceImpl(exeEnv);
+            TFetchSchemaTableDataRequest request = new 
TFetchSchemaTableDataRequest();
+            
request.setSchemaTableName(TSchemaTableName.AUTHENTICATION_INTEGRATIONS);
+            TSchemaTableRequestParams params = new TSchemaTableRequestParams();
+            
params.setCurrentUserIdent(connectContext.getCurrentUserIdentity().toThrift());
+            request.setSchemaTableParams(params);
+
+            TFetchSchemaTableDataResult result = 
impl.fetchSchemaTableData(request);
+            Assert.assertEquals(TStatusCode.OK, 
result.getStatus().getStatusCode());
+
+            List<String> rowValues = result.getDataBatch().stream()
+                    .filter(row -> 
integrationName.equals(row.getColumnValue().get(0).getStringVal()))
+                    .map(row -> row.getColumnValue().stream()
+                            .map(cell -> cell.isSetStringVal() ? 
cell.getStringVal() : null)
+                            .collect(Collectors.toList()))
+                    .findFirst()
+                    .orElseThrow(() -> new 
java.lang.AssertionError("authentication integration row not found"));
+
+            Assert.assertEquals(integrationName, rowValues.get(0));
+            Assert.assertEquals("ldap", rowValues.get(1));
+            Assert.assertTrue(rowValues.get(2).contains("\"server\" = 
\"ldap://127.0.0.1:389\"";));
+            Assert.assertTrue(rowValues.get(2).contains(
+                    "\"bind_password\" = \"" + 
DatasourcePrintableMap.PASSWORD_MASK + "\""));
+            Assert.assertTrue(rowValues.get(2).contains(
+                    "\"secret.endpoint\" = \"" + 
DatasourcePrintableMap.PASSWORD_MASK + "\""));
+            Assert.assertFalse(rowValues.get(2).contains("plain_secret"));
+            Assert.assertFalse(rowValues.get(2).contains("masked_by_prefix"));
+            Assert.assertEquals("ldap comment", rowValues.get(3));
+            Assert.assertEquals(connectContext.getQualifiedUser(), 
rowValues.get(4));
+            Assert.assertNotNull(rowValues.get(5));
+            Assert.assertFalse(rowValues.get(5).isEmpty());
+            Assert.assertEquals(connectContext.getQualifiedUser(), 
rowValues.get(6));
+            Assert.assertEquals(rowValues.get(5), rowValues.get(7));
+        } finally {
+            
Env.getCurrentEnv().getAuthenticationIntegrationMgr().dropAuthenticationIntegration(integrationName,
 true);
+        }
+    }
 }
diff --git a/gensrc/thrift/Descriptors.thrift b/gensrc/thrift/Descriptors.thrift
index 730a74ae6f3..7d3883c9f9b 100644
--- a/gensrc/thrift/Descriptors.thrift
+++ b/gensrc/thrift/Descriptors.thrift
@@ -214,6 +214,7 @@ enum TSchemaTableType {
     SCH_LOAD_JOBS = 64;
     SCH_FILE_CACHE_INFO = 65;
     SCH_DATABASE_PROPERTIES = 66;
+    SCH_AUTHENTICATION_INTEGRATIONS = 67;
 }
 
 enum THdfsCompression {
diff --git a/gensrc/thrift/FrontendService.thrift 
b/gensrc/thrift/FrontendService.thrift
index ccd082e7f52..aeb5b06efb6 100644
--- a/gensrc/thrift/FrontendService.thrift
+++ b/gensrc/thrift/FrontendService.thrift
@@ -870,6 +870,7 @@ enum TSchemaTableName {
   VIEW_DEPENDENCY = 11,
   SQL_BLOCK_RULE_STATUS = 12,
   DATABASE_PROPERTIES = 13,
+  AUTHENTICATION_INTEGRATIONS = 14,
 }
 
 struct TMetadataTableRequestParams {
diff --git 
a/regression-test/suites/auth_p0/test_authentication_integration_auth.groovy 
b/regression-test/suites/auth_p0/test_authentication_integration_auth.groovy
index c65ac577574..caec26467d2 100644
--- a/regression-test/suites/auth_p0/test_authentication_integration_auth.groovy
+++ b/regression-test/suites/auth_p0/test_authentication_integration_auth.groovy
@@ -35,7 +35,8 @@ suite("test_authentication_integration_auth", "p0,auth") {
              PROPERTIES (
                 'type'='ldap',
                 'ldap.server'='ldap://127.0.0.1:389',
-                'ldap.admin_password'='123456'
+                'ldap.admin_password'='123456',
+                'secret.endpoint'='secret_create_value'
             )
             COMMENT 'for regression test'
         """
@@ -60,12 +61,42 @@ suite("test_authentication_integration_auth", "p0,auth") {
             ALTER AUTHENTICATION INTEGRATION ${integrationName}
             SET PROPERTIES (
                 'ldap.server'='ldap://127.0.0.1:1389',
-                'ldap.admin_password'='abcdef'
+                'ldap.admin_password'='abcdef',
+                'secret.endpoint'='secret_alter_value'
             )
         """
 
         sql """ALTER AUTHENTICATION INTEGRATION ${integrationName} SET COMMENT 
'updated comment'"""
 
+        def result = sql """
+            SELECT
+                NAME,
+                TYPE,
+                PROPERTIES,
+                COMMENT,
+                CREATE_USER,
+                CREATE_TIME,
+                ALTER_USER,
+                MODIFY_TIME
+            FROM information_schema.authentication_integrations
+            WHERE NAME = '${integrationName}'
+            ORDER BY NAME
+        """
+        assertEquals(1, result.size())
+        assertEquals(8, result[0].size())
+        assertEquals(integrationName, result[0][0])
+        assertEquals("ldap", result[0][1])
+        assertTrue(result[0][2].contains("\"ldap.server\" = 
\"ldap://127.0.0.1:1389\"";))
+        assertTrue(result[0][2].contains("\"ldap.admin_password\" = \"*XXX\""))
+        assertTrue(result[0][2].contains("\"secret.endpoint\" = \"*XXX\""))
+        assertTrue(!result[0][2].contains("abcdef"))
+        assertTrue(!result[0][2].contains("secret_alter_value"))
+        assertEquals("updated comment", result[0][3])
+        assertTrue(result[0][4] != null && result[0][4].length() > 0)
+        assertTrue(result[0][5] != null && result[0][5].length() > 0)
+        assertTrue(result[0][6] != null && result[0][6].length() > 0)
+        assertTrue(result[0][7] != null && result[0][7].length() > 0)
+
         test {
             sql """DROP AUTHENTICATION INTEGRATION 
${integrationName}_not_exist"""
             exception "does not exist"


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

Reply via email to