github-actions[bot] commented on code in PR #67343:
URL: https://github.com/apache/doris/pull/67343#discussion_r3894193276


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/refresh/RefreshDictionaryCommand.java:
##########
@@ -45,7 +50,24 @@ public RefreshDictionaryCommand(String dbName, String 
dicName) {
     public void run(ConnectContext ctx, StmtExecutor executor) throws 
Exception {
         DictionaryManager dictionaryManager = 
ctx.getEnv().getDictionaryManager();
         String db = dbName == null ? ctx.getDatabase() : dbName;
+        // The reload is an INSERT INTO the dictionary executed as the current 
user, which requires
+        // LOAD on the dictionary (and SELECT on the source table). Check LOAD 
up front so a user
+        // without it can neither probe whether the dictionary exists nor flip 
it to LOADING.
+        if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, 
InternalCatalog.INTERNAL_CATALOG_NAME,
+                db, dictionaryName, PrivPredicate.LOAD)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, 
"LOAD",
+                    ctx.getQualifiedUser(), ctx.getRemoteIP(), db + ": " + 
dictionaryName);
+        }
         Dictionary dictionary = dictionaryManager.getDictionary(db, 
dictionaryName);
+        // The reload also reads the source table as the current user. 
dataLoad() publishes the
+        // LOADING status before that INSERT is analyzed, so reject a missing 
SELECT here instead of
+        // letting an unauthorized request block concurrent refreshes until 
planning fails.
+        if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, 
dictionary.getSourceCtlName(),

Review Comment:
   [P2] Use the column-aware source authorization here. The generated 
dictionary load does not require table-wide SELECT: 
`BindSink.bindDictionarySink` projects the source to 
`dictionary.getFullSchema()`, then `CheckPrivileges` authorizes the actually 
required slots through `checkColumnsPriv`. A caller with dictionary LOAD plus 
`SELECT_PRIV(id)` and `SELECT_PRIV(value)` for a dictionary containing those 
source columns is authorized by that load plan (and equivalent Ranger column 
policies work too), but `checkTblPriv(..., SELECT)` rejects it before planning. 
Please preflight the actual dictionary source-column set through the same 
column-aware contract, or centralize planning/authorization before publishing 
`LOADING`, and add a column-only regression case.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExplainDictionaryCommand.java:
##########
@@ -62,11 +68,17 @@ public ShowResultSetMetaData getMetaData() {
     }
 
     @Override
-    public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) 
throws DdlException {
+    public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) 
throws DdlException, AnalysisException {
         List<List<String>> rows = Lists.newArrayList();
 
         DictionaryManager dictionaryManager = 
ctx.getEnv().getDictionaryManager();
         String db = dbName == null ? ctx.getDatabase() : dbName;
+        // Describing a dictionary exposes its schema, so require SHOW on it 
like DESCRIBE on a table.
+        if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, 
InternalCatalog.INTERNAL_CATALOG_NAME,

Review Comment:
   [P1] This authorization is bypassed by the actual dictionary read path. 
`DictGet.customSignatureDict` and `DictGetMany.customSignatureDict` call 
`DictionaryManager.getDictionary` directly, inspect its schema, and let 
`ExpressionTranslator` send its ID/version to the BE without any access-manager 
check; because `SELECT dict_get(...)` needs no relation, `CheckPrivileges` 
cannot catch it. A user for whom this command returns `denied` and `SHOW 
DICTIONARIES` hides the row can still guess `db.dict` and read its values (or 
distinguish dictionary/column errors). Apply the same dictionary read 
authorization to both scalar functions before lookup/translation, return the 
same denial for missing and unauthorized names, and add hidden-user read tests.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowDictionariesCommand.java:
##########
@@ -73,14 +76,23 @@ public ShowResultSet doRun(ConnectContext ctx, StmtExecutor 
executor) throws Ana
 
         DictionaryManager dictionaryManager = 
ctx.getEnv().getDictionaryManager();
         List<Dictionary> queryDicts = Lists.newArrayList();
+        String dbName = ctx.getDatabase();
         // getDictionaries() already have read lock
-        Map<String, Dictionary> dbDictionaries = 
dictionaryManager.getDictionaries(ctx.getDatabase());
+        Map<String, Dictionary> dbDictionaries = 
dictionaryManager.getDictionaries(dbName);
         for (Map.Entry<String, Dictionary> entry : dbDictionaries.entrySet()) {
             String dictionaryName = entry.getKey();
             // Apply wild condition filtering if wild pattern is provided
-            if (wild == null || matcher.match(dictionaryName)) {
-                queryDicts.add(entry.getValue());
+            if (wild != null && !matcher.match(dictionaryName)) {
+                continue;
             }
+            // Dictionaries are authorized like tables of the internal 
catalog. Hide the ones the user
+            // may not show, the same way SHOW TABLES hides tables, so the 
source table name, status
+            // and data distribution are not exposed to users without 
privileges on the dictionary.
+            if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ctx, 
InternalCatalog.INTERNAL_CATALOG_NAME,

Review Comment:
   [P2] Short-circuit when this filter leaves `queryDicts` empty. 
`collectDictionaryStatus(emptyList())` does not mean ‘collect none’: the 
Thrift/BE contract treats an empty ID list as ALL, so a low-privilege user 
whose correct result is empty still fans status RPCs to every alive BE, logs 
every returned dictionary as missing from the requested set, and can have `SHOW 
DICTIONARIES` fail because of a failed/null response from a contacted alive BE. 
Return the empty result before status collection (or preserve an explicit 
none-vs-all distinction).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to