This is an automated email from the ASF dual-hosted git repository. morningman 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 8e3db001f21 [Enhancement](tvf)catalog tvf implements user permission checks and hides sensitive information (#41497) 8e3db001f21 is described below commit 8e3db001f21d00170af2b8b6d876e1fddfee0fac Author: daidai <2017501...@qq.com> AuthorDate: Tue Oct 8 18:13:41 2024 +0800 [Enhancement](tvf)catalog tvf implements user permission checks and hides sensitive information (#41497) before #21790 ## Proposed changes This PR unifies the duplicate parts of `catalog tvf` and `show catalogs`, adds permission check when querying `catalog tvf`, and hides sensitive information. --- be/src/vec/exec/scan/vmeta_scanner.cpp | 1 + .../org/apache/doris/datasource/CatalogMgr.java | 85 +++++++++++++--------- .../doris/tablefunction/MetadataGenerator.java | 9 ++- .../external_table_p0/tvf/test_catalogs_tvf.out | 40 ++++++++++ .../external_table_p0/tvf/test_catalogs_tvf.groovy | 68 ++++++++++++++++- 5 files changed, 162 insertions(+), 41 deletions(-) diff --git a/be/src/vec/exec/scan/vmeta_scanner.cpp b/be/src/vec/exec/scan/vmeta_scanner.cpp index 74fed8c80c7..180d18b0c2c 100644 --- a/be/src/vec/exec/scan/vmeta_scanner.cpp +++ b/be/src/vec/exec/scan/vmeta_scanner.cpp @@ -400,6 +400,7 @@ Status VMetaScanner::_build_catalogs_metadata_request(const TMetaScanRange& meta // create TMetadataTableRequestParams TMetadataTableRequestParams metadata_table_params; metadata_table_params.__set_metadata_type(TMetadataType::CATALOGS); + metadata_table_params.__set_current_user_ident(_user_identity); request->__set_metada_table_params(metadata_table_params); return Status::OK(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java index b77374e3094..3b8551da144 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/CatalogMgr.java @@ -24,6 +24,7 @@ import org.apache.doris.analysis.CreateCatalogStmt; import org.apache.doris.analysis.DropCatalogStmt; import org.apache.doris.analysis.ShowCatalogStmt; import org.apache.doris.analysis.ShowCreateCatalogStmt; +import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.EnvFactory; @@ -371,30 +372,27 @@ public class CatalogMgr implements Writable, GsonPostProcessable { matcher = PatternMatcherWrapper.createMysqlPattern(showStmt.getPattern(), CaseSensibility.CATALOG.getCaseSensibility()); } - for (CatalogIf catalog : nameToCatalog.values()) { - if (Env.getCurrentEnv().getAccessManager() - .checkCtlPriv(ConnectContext.get(), catalog.getName(), PrivPredicate.SHOW)) { - String name = catalog.getName(); - // Filter catalog name - if (matcher != null && !matcher.match(name)) { - continue; - } - List<String> row = Lists.newArrayList(); - row.add(String.valueOf(catalog.getId())); - row.add(name); - row.add(catalog.getType()); - if (name.equals(currentCtlg)) { - row.add("Yes"); - } else { - row.add("No"); - } - Map<String, String> props = catalog.getProperties(); - String createTime = props.getOrDefault(ExternalCatalog.CREATE_TIME, FeConstants.null_string); - row.add(createTime); - row.add(TimeUtils.longToTimeString(catalog.getLastUpdateTime())); - row.add(catalog.getComment()); - rows.add(row); + for (CatalogIf catalog : listCatalogsWithCheckPriv(ConnectContext.get().getCurrentUserIdentity())) { + String name = catalog.getName(); + // Filter catalog name + if (matcher != null && !matcher.match(name)) { + continue; + } + List<String> row = Lists.newArrayList(); + row.add(String.valueOf(catalog.getId())); + row.add(name); + row.add(catalog.getType()); + if (name.equals(currentCtlg)) { + row.add("Yes"); + } else { + row.add("No"); } + Map<String, String> props = catalog.getProperties(); + String createTime = props.getOrDefault(ExternalCatalog.CREATE_TIME, FeConstants.null_string); + row.add(createTime); + row.add(TimeUtils.longToTimeString(catalog.getLastUpdateTime())); + row.add(catalog.getComment()); + rows.add(row); // sort by catalog name rows.sort((x, y) -> { @@ -414,18 +412,8 @@ public class CatalogMgr implements Writable, GsonPostProcessable { if (!Strings.isNullOrEmpty(catalog.getResource())) { rows.add(Arrays.asList("resource", catalog.getResource())); } - // use tree map to maintain display order, making it easier to view properties - Map<String, String> sortedMap = new TreeMap<>(catalog.getProperties()).descendingMap(); - for (Map.Entry<String, String> elem : sortedMap.entrySet()) { - if (PrintableMap.HIDDEN_KEY.contains(elem.getKey())) { - continue; - } - if (PrintableMap.SENSITIVE_KEY.contains(elem.getKey())) { - rows.add(Arrays.asList(elem.getKey(), PrintableMap.PASSWORD_MASK)); - } else { - rows.add(Arrays.asList(elem.getKey(), elem.getValue())); - } - } + Map<String, String> sortedMap = getCatalogPropertiesWithPrintable(catalog); + sortedMap.forEach((k, v) -> rows.add(Arrays.asList(k, v))); } } finally { readUnlock(); @@ -434,6 +422,25 @@ public class CatalogMgr implements Writable, GsonPostProcessable { return new ShowResultSet(showStmt.getMetaData(), rows); } + public static Map<String, String> getCatalogPropertiesWithPrintable(CatalogIf<?> catalog) { + // use tree map to maintain display order, making it easier to view properties + Map<String, String> sortedMap = new TreeMap<>(); + catalog.getProperties().forEach( + (key, value) -> { + if (PrintableMap.HIDDEN_KEY.contains(key)) { + return; + } + if (PrintableMap.SENSITIVE_KEY.contains(key)) { + sortedMap.put(key, PrintableMap.PASSWORD_MASK); + } else { + sortedMap.put(key, value); + } + } + ); + return sortedMap; + } + + public ShowResultSet showCreateCatalog(ShowCreateCatalogStmt showStmt) throws AnalysisException { List<List<String>> rows = Lists.newArrayList(); readLock(); @@ -538,6 +545,14 @@ public class CatalogMgr implements Writable, GsonPostProcessable { return nameToCatalog.values().stream().collect(Collectors.toList()); } + public List<CatalogIf> listCatalogsWithCheckPriv(UserIdentity userIdentity) { + return nameToCatalog.values().stream().filter( + catalog -> Env.getCurrentEnv().getAccessManager() + .checkCtlPriv(userIdentity, catalog.getName(), PrivPredicate.SHOW) + ).collect(Collectors.toList()); + } + + /** * Reply for alter catalog props event. */ 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 466d324c369..a1cac535995 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 @@ -47,6 +47,7 @@ import org.apache.doris.common.util.NetUtils; import org.apache.doris.common.util.TimeUtils; import org.apache.doris.common.util.Util; import org.apache.doris.datasource.CatalogIf; +import org.apache.doris.datasource.CatalogMgr; import org.apache.doris.datasource.ExternalCatalog; import org.apache.doris.datasource.ExternalMetaCacheMgr; import org.apache.doris.datasource.InternalCatalog; @@ -513,17 +514,17 @@ public class MetadataGenerator { private static TFetchSchemaTableDataResult catalogsMetadataResult(TMetadataTableRequestParams params) { TFetchSchemaTableDataResult result = new TFetchSchemaTableDataResult(); - List<CatalogIf> info = Env.getCurrentEnv().getCatalogMgr().listCatalogs(); - List<TRow> dataBatch = Lists.newArrayList(); + UserIdentity currentUserIdentity = UserIdentity.fromThrift(params.getCurrentUserIdent()); + List<CatalogIf> info = Env.getCurrentEnv().getCatalogMgr().listCatalogsWithCheckPriv(currentUserIdentity); + List<TRow> dataBatch = Lists.newArrayList(); for (CatalogIf catalog : info) { TRow trow = new TRow(); trow.addToColumnValue(new TCell().setLongVal(catalog.getId())); trow.addToColumnValue(new TCell().setStringVal(catalog.getName())); trow.addToColumnValue(new TCell().setStringVal(catalog.getType())); - Map<String, String> properties = catalog.getProperties(); - + Map<String, String> properties = CatalogMgr.getCatalogPropertiesWithPrintable(catalog); for (Map.Entry<String, String> entry : properties.entrySet()) { TRow subTrow = new TRow(trow); subTrow.addToColumnValue(new TCell().setStringVal(entry.getKey())); diff --git a/regression-test/data/external_table_p0/tvf/test_catalogs_tvf.out b/regression-test/data/external_table_p0/tvf/test_catalogs_tvf.out index 310da69d766..7f97c337999 100644 --- a/regression-test/data/external_table_p0/tvf/test_catalogs_tvf.out +++ b/regression-test/data/external_table_p0/tvf/test_catalogs_tvf.out @@ -8,3 +8,43 @@ catalog_test_hive00 hms type hms -- !create -- catalog_test_es00 es type es +-- !test_10 -- +catalog_tvf_test_dlf hms dlf.catalog.id 987654321 + +-- !test_11 -- +catalog_tvf_test_dlf hms dlf.secret_key *XXX + +-- !test_12 -- +catalog_tvf_test_dlf hms dlf.access_key AAAAAAAAAAAAAAAAAAAAAA + +-- !test_13 -- +catalog_tvf_test_dlf hms dlf.uid 123456789 + +-- !test_14 -- +catalog_tvf_test_dlf hms type hms + +-- !test_15 -- + +-- !test_16 -- +internal internal NULL NULL + +-- !test_17 -- +catalog_tvf_test_dlf hms dlf.secret_key *XXX + +-- !test_18 -- +catalog_tvf_test_dlf hms dlf.access_key AAAAAAAAAAAAAAAAAAAAAA + +-- !test_19 -- +catalog_tvf_test_dlf hms dlf.uid 123456789 + +-- !test_20 -- +catalog_tvf_test_dlf hms type hms + +-- !test_21 -- + +-- !test_22 -- + +-- !test_23 -- + +-- !test_24 -- + diff --git a/regression-test/suites/external_table_p0/tvf/test_catalogs_tvf.groovy b/regression-test/suites/external_table_p0/tvf/test_catalogs_tvf.groovy index a59953cf567..748a7e49d14 100644 --- a/regression-test/suites/external_table_p0/tvf/test_catalogs_tvf.groovy +++ b/regression-test/suites/external_table_p0/tvf/test_catalogs_tvf.groovy @@ -18,12 +18,12 @@ suite("test_catalogs_tvf","p0,external,tvf,external_docker") { List<List<Object>> table = sql """ select * from catalogs(); """ assertTrue(table.size() > 0) - assertEquals(5, table[0].size) + assertEquals(5, table[0].size()) table = sql """ select CatalogId,CatalogName from catalogs();""" assertTrue(table.size() > 0) - assertTrue(table[0].size == 2) + assertTrue(table[0].size() == 2) table = sql """ select * from catalogs() where CatalogId=0;""" @@ -76,4 +76,68 @@ suite("test_catalogs_tvf","p0,external,tvf,external_docker") { // check exception exception "catalogs table-valued-function does not support any params" } + + sql """ drop catalog if exists catalog_tvf_test_dlf """ + + sql """ + CREATE CATALOG catalog_tvf_test_dlf PROPERTIES ( + "type"="hms", + "hive.metastore.type" = "dlf", + "dlf.proxy.mode" = "DLF_ONLY", + "dlf.endpoint" = "dlf-vpc.cn-beijing.aliyuncs.com", + "dlf.region" = "cn-beijing", + "dlf.uid" = "123456789", + "dlf.catalog.id" = "987654321", + "dlf.access_key" = "AAAAAAAAAAAAAAAAAAAAAA", + "dlf.secret_key" = "BBBBBBBBBBBBBBBBBBBBBB" + );""" + + order_qt_test_10 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.catalog.id" """ + order_qt_test_11 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.secret_key" """ + order_qt_test_12 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.access_key" """ + order_qt_test_13 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.uid" """ + order_qt_test_14 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "type" """ + + + def user = 'catalog_user_test' + def pwd = 'C123_567p' + try_sql("DROP USER ${user}") + + sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}'""" + sql """GRANT SELECT_PRIV on `internal`.``.`` to '${user}'""" + + + + connect(user=user, password="${pwd}", url=context.config.jdbcUrl) { + sql """ switch internal """ + order_qt_test_15 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "type" """ + order_qt_test_16 """ select CatalogName,CatalogType,Property,Value from catalogs() """ + } + + sql """GRANT SELECT_PRIV on `catalog_tvf_test_dlf`.``.`` to '${user}'""" + + + connect(user=user, password="${pwd}", url=context.config.jdbcUrl) { + sql """ switch internal """ + + order_qt_test_17 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.secret_key" """ + order_qt_test_18 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.access_key" """ + order_qt_test_19 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.uid" """ + order_qt_test_20 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "type" """ + } + + sql """REVOKE SELECT_PRIV on `catalog_tvf_test_dlf`.``.`` FROM '${user}'""" + + + connect(user=user, password="${pwd}", url=context.config.jdbcUrl) { + sql """ switch internal """ + + order_qt_test_21 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.secret_key" """ + order_qt_test_22 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.access_key" """ + order_qt_test_23 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "dlf.uid" """ + order_qt_test_24 """ select CatalogName,CatalogType,Property,Value from catalogs() where CatalogName = "catalog_tvf_test_dlf" and Property= "type" """ + } + + + } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org