[Bug] Dictionaries share the table privilege namespace and may collide with a same-name table
- Dominant language
- Java
- Stars
- 15.9k
- Forks
- 3.9k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 520
Description
### Search before asking
- [x] I had searched in the [issues](https://github.com/apache/doris/issues?q=is%3Aissue) and found no similar issues.
### Version
master (4a9956e0a93)
### What's Wrong?
Dictionaries are stored in `DictionaryManager`, outside the `Database` table map, but they are authorized with the table privilege key of the internal catalog: `checkTblPriv(internal, db, , ...)` is used by `CREATE/DROP DICTIONARY` (#66218) and by `SHOW/EXPLAIN/REFRESH DICTIONARY` (#67343).
Two things make that namespace leaky:
1. Name collisions are allowed. `CREATE DICTIONARY db.foo ...` only checks that no dictionary `foo` exists, and `CREATE TABLE db.foo` never checks for a dictionary `foo`, so a table and a dictionary can share a name in the same database.
2. Privileges are matched by name only. With a same-name table, any grant on table `db.foo` (including a column grant, which `Role.checkTblPriv` treats as `SHOW`) also satisfies the dictionary checks: such a user can see the dictionary in `SHOW DICTIONARIES`, describe it, drop it with `DROP` on the table, or refresh it with `LOAD` on the table.
Related: `GRANT ... ON db.` is rejected with `table: ... does not exist` for every privilege except `CREATE` (the existence check in `Auth.grantInternal` is skipped for `CREATE_PRIV`), so today dictionaries can only be authorized at the database level.
### What You Expected?
Either
- reject name collisions between tables and dictionaries in both `CREATE DICTIONARY` and `CREATE TABLE` (internal catalog), so a grant on `db.foo` can only ever refer to one object; or
- give dictionaries their own privilege object so that `GRANT`, the internal access controller and Ranger authorize them independently of tables.
### How to Reproduce?
```sql
CREATE TABLE db.src (id INT, v VARCHAR(32)) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES("replication_num"="1");
CREATE TABLE db.foo (id INT) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES("replication_num"="1");
CREATE DICTIONARY db.foo USING db.src (id KEY, v VALUE) LAYOUT(HASH_MAP) PROPERTIES('data_lifetime'='600');
CREATE USER u IDENTIFIED BY 'Pwd_12345';
GRANT SELECT_PRIV ON db.foo TO u; -- grant on the *table* foo
-- as u
USE db;
SHOW DICTIONARIES; -- lists dictionary foo with its source table
EXPLAIN DICTIONARY foo; -- returns the dictionary schema
```
### Anything Else?
Found while adding the missing privilege checks in #67343; that PR keeps the existing table-keyed model on purpose, so the collision handling / dedicated privilege object is tracked here.
### Are you willing to submit PR?
- [x] Yes I am willing to submit a PR!
### Code of Conduct
- [x] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)
Contributor guide
Research direction
Start with DictionaryManager and the named authorization entry points: checkTblPriv, Role.checkTblPriv, and Auth.grantInternal. Reproduce the same-name table and dictionary scenario from the SQL example, then trace CREATE TABLE and CREATE/DROP DICTIONARY handling. Done means table privileges no longer authorize a dictionary, through collision rejection or a separate dictionary privilege object, with the listed dictionary operations covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, sql
- Domain
- authorization, databases
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100