Skip to content

[fix](auth) Add missing privilege checks for several Nereids commands - #66218

Open
CalvinKirs wants to merge 3 commits into
apache:masterfrom
CalvinKirs:tde_auth
Open

[fix](auth) Add missing privilege checks for several Nereids commands#66218
CalvinKirs wants to merge 3 commits into
apache:masterfrom
CalvinKirs:tde_auth

Conversation

@CalvinKirs

@CalvinKirs CalvinKirs commented Jul 29, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

The Nereids path in StmtExecutor dispatches straight to Command.run(), so each command has to enforce its own privileges. A number of commands never got that check, and can currently be executed by any authenticated user regardless of their grants.

This PR adds the missing checks:

Command Required privilege Follows
AdminSetEncryptionRootKeyCommand, AdminRotateTdeRootKeyCommand global ADMIN AdminSetFrontendConfig, AdminSetTableStatus, AdminSetReplicaStatus, AdminCleanTrash
DropCatalogRecycleBinCommand global ADMIN SHOW CATALOG RECYCLE BIN already requires global ADMIN. RECOVER uses ALTER_CREATE, but it is name-scoped while erasing takes a raw object id, so it cannot be authorized at db/table level
CreateDictionaryCommand CREATE on the dictionary and SELECT on the source table CREATE TABLE / CREATE MTMV. The SELECT check is needed because the load task runs internally, and unlike an MTMV the source table is not bound by the planner
DropDictionaryCommand DROP on the dictionary DROP TABLE / DROP MTMV
AddConstraintCommand, DropConstraintCommand ALTER on the table the rest of ALTER TABLE
WarmUpClusterCommand USAGE on the source and destination compute groups, plus SELECT on each table named by WITH TABLE UseCloudClusterCommand
CancelWarmUpJobCommand global ADMIN CloudWarmUpJob records no owner, so a job cannot be scoped to the user who created it
DropStageCommand global ADMIN CreateStageCommand, which already checked it

Note that ADMIN_PRIV satisfies every predicate used above, so admin users are unaffected by any of this.

Where the check is placed, and why

  • AddConstraintCommand: for a foreign key the referenced table is checked as well, because adding the constraint registers a reverse reference on it.
  • DropConstraintCommand: the check sits after the two table-resolution paths converge. Resolution can fall back to a name-only lookup, and putting the check on the normal path only would let the fallback skip it.
  • CreateDictionaryCommand: the check has to run after validateAndSet(), since that is what fills in the default catalog/db names.
  • WarmUpClusterCommand: the per-table SELECT check is inside the existing WITH TABLE resolution loop, so it reuses the table that was just resolved.

Incidental changes reviewers should look at

These are not privilege checks, but they fall out of adding them:

  1. AdminRotateTdeRootKeyCommand, DropCatalogRecycleBinCommand, DropStageCommand had no validate() method at all. One was added to each and is called at the top of run().
  2. CreateDictionaryCommand.run() and DropDictionaryCommand.run() now declare throws Exception.
  3. CreateDictionaryCommand.run(): the single try block that wrapped validateAndSet() + createDictionary() is split in two, with the check in between. Consequence: an access-denied error is not wrapped in the "Failed to create dictionary: ..." prefix, while the failure messages from validateAndSet() and createDictionary() are unchanged.
  4. WarmUpClusterCommand.validate(): order is now cloud-mode → compute group USAGE → compute group existence/virtual-group validation → table resolution. The non-cloud error message is unchanged, but in cloud mode a user without USAGE now gets an access-denied error where they previously got "compute group doesn't exist".

Open questions

  • WarmUpClusterCommand: global ADMIN felt too coarse for an operation scoped to compute groups the user already has USAGE on, so it uses checkCloudPriv(..., ResourceTypeEnum.CLUSTER) instead. Happy to switch it back to ADMIN if the cloud maintainers prefer that.
  • CancelWarmUpJobCommand keeps ADMIN only because there is nothing to scope it to. If CloudWarmUpJob recorded the submitting user, letting that user cancel their own job would be better.
  • Out of scope, but noted while looking around: ShowWarmUpCommand (SHOW WARM UP JOB) and ShowDictionariesCommand (SHOW DICTIONARIES) have no privilege check either. Happy to follow up in a separate PR.

Release note

Fix missing privilege checks on ADMIN SET ENCRYPTION ROOT KEY, ADMIN ROTATE TDE ROOT KEY, DROP CATALOG RECYCLE BIN, CREATE/DROP DICTIONARY, ALTER TABLE ADD/DROP CONSTRAINT, WARM UP CLUSTER, CANCEL WARM UP JOB and DROP STAGE. These statements previously ran for any authenticated user.

Check List (For Author)

  • Test
    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason

New auth_call cases for constraint, dictionary and recycle bin, each covering both the denied and the granted path. The cloud-only commands (WARM UP CLUSTER, CANCEL WARM UP JOB, DROP STAGE) are not covered by a regression case.

  • Behavior changed:

    • No.
    • Yes. Users without the privileges listed above can no longer run these statements; they now get an access-denied error. See "Incidental changes reviewers should look at" above for the two error-message changes that come with it.
  • Does this need documentation?

    • No.
    • Yes.

The privilege documentation for these statements should list the required privileges.

Several Nereids commands do not check privileges before executing.
The Nereids path in StmtExecutor dispatches straight to Command.run(),
so every command has to enforce its own privileges, and these ones were
missed:

- AdminSetEncryptionRootKeyCommand / AdminRotateTdeRootKeyCommand: now
  require ADMIN, like the other ADMIN SET statements.
- DropCatalogRecycleBinCommand: now requires ADMIN. It takes a raw
  object id and erases instantly, so it cannot be authorized at
  db/table level.
- CreateDictionaryCommand: requires CREATE on the target database plus
  SELECT on the source table, since the load task runs internally.
  DropDictionaryCommand requires DROP on the database.
- AddConstraintCommand / DropConstraintCommand: require ALTER on the
  table. For a foreign key the referenced table is checked as well,
  because it gets a reverse reference registered on it. In
  DropConstraintCommand the check is placed after the name-based
  fallback so neither resolution path can skip it.
- WarmUpClusterCommand / CancelWarmUpJobCommand / DropStageCommand:
  require ADMIN, matching CreateStageCommand which already did.

Add auth_call regression cases for constraint, dictionary and recycle
bin covering both the denied and the granted path.
@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@CalvinKirs

Copy link
Copy Markdown
Member Author

run buildall

@CalvinKirs

Copy link
Copy Markdown
Member Author

/review

…ions

Follow-up on the privilege checks added in the previous commit.

Dictionary: use checkTblPriv on the dictionary itself instead of
checkDbPriv on its database, matching CREATE/DROP TABLE and
CREATE/DROP MTMV. checkDbPriv would reject a user who was granted the
privilege on the dictionary name directly.

Warm up: WARM UP CLUSTER now requires USAGE on the source and
destination compute groups instead of global ADMIN, matching
UseCloudClusterCommand, plus SELECT on each table named by WITH TABLE.
CANCEL WARM UP JOB keeps ADMIN because CloudWarmUpJob records no
owner, so a job cannot be scoped to the user who created it.
…intCommand

WarmUpClusterOnTablesParseTest builds a bare ConnectContext with no user
identity, so the privilege check added to WarmUpClusterCommand.validate()
hit a NullPointerException in getRolesByUserWithLdap(). Neither
checkGlobalPriv(ctx, ...) nor checkCloudPriv(ctx, ...) tolerates a null
identity, which is fine for the real execution path since StmtExecutor
always runs with an authenticated context. Give the test an identity and
let it bypass the checks, since it covers ON TABLES parsing rather than
authorization.

Also make AddConstraintCommand use the ConnectContext passed to run()
instead of the static ConnectContext.get(). DropConstraintCommand already
did, and the static one is null on any path that has no thread local set.
@CalvinKirs
CalvinKirs requested a review from gavinchou as a code owner July 29, 2026 09:31
@CalvinKirs

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29006 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 7efece3b359dce9fb468a0637e3c272119fc4aed, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17713	4075	4003	4003
q2	2033	321	198	198
q3	10298	1463	828	828
q4	4683	479	338	338
q5	7511	830	579	579
q6	186	171	136	136
q7	762	814	601	601
q8	9325	1384	1334	1334
q9	5443	4302	4296	4296
q10	6746	1773	1479	1479
q11	508	363	329	329
q12	728	576	452	452
q13	18097	3281	2761	2761
q14	265	262	235	235
q15	q16	789	770	707	707
q17	973	957	1044	957
q18	6978	5783	5508	5508
q19	1325	1271	1097	1097
q20	802	674	553	553
q21	5920	2588	2320	2320
q22	421	358	295	295
Total cold run time: 101506 ms
Total hot run time: 29006 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4343	4276	4276	4276
q2	285	318	210	210
q3	4576	5007	4370	4370
q4	2014	2141	1349	1349
q5	4342	4249	4267	4249
q6	229	173	129	129
q7	1713	1623	1702	1623
q8	2695	2202	2154	2154
q9	8010	8214	7624	7624
q10	4674	4755	4256	4256
q11	560	416	396	396
q12	788	771	560	560
q13	3406	3984	2960	2960
q14	308	301	319	301
q15	q16	743	751	670	670
q17	1369	1332	1365	1332
q18	8409	7659	7435	7435
q19	1221	1134	1065	1065
q20	2210	2181	1948	1948
q21	5193	4501	4380	4380
q22	515	443	401	401
Total cold run time: 57603 ms
Total hot run time: 51688 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177551 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 7efece3b359dce9fb468a0637e3c272119fc4aed, data reload: false

query5	4326	628	488	488
query6	461	226	219	219
query7	4994	627	329	329
query8	328	187	170	170
query9	8758	4053	4110	4053
query10	465	348	301	301
query11	5940	2344	2158	2158
query12	157	103	105	103
query13	1269	603	430	430
query14	6275	5186	4906	4906
query14_1	4261	4233	4220	4220
query15	219	205	186	186
query16	1045	484	498	484
query17	1155	707	581	581
query18	2540	483	350	350
query19	218	198	157	157
query20	120	111	108	108
query21	236	163	138	138
query22	13624	13582	13415	13415
query23	17457	16545	16115	16115
query23_1	16158	16237	16182	16182
query24	7481	1790	1295	1295
query24_1	1306	1285	1270	1270
query25	579	462	383	383
query26	1352	392	213	213
query27	2494	582	387	387
query28	4409	2004	2000	2000
query29	1084	629	507	507
query30	343	265	229	229
query31	1123	1100	972	972
query32	109	67	62	62
query33	526	336	258	258
query34	1197	1110	672	672
query35	770	782	679	679
query36	1035	1033	863	863
query37	154	107	94	94
query38	1880	1694	1698	1694
query39	891	873	849	849
query39_1	827	844	848	844
query40	246	164	144	144
query41	67	62	68	62
query42	92	93	89	89
query43	313	327	277	277
query44	1424	763	753	753
query45	191	181	177	177
query46	1047	1191	689	689
query47	2124	2111	2015	2015
query48	407	398	302	302
query49	578	417	300	300
query50	1055	435	373	373
query51	10563	10673	10655	10655
query52	88	86	73	73
query53	254	277	202	202
query54	272	233	226	226
query55	74	75	67	67
query56	323	290	277	277
query57	1327	1276	1220	1220
query58	283	251	281	251
query59	1606	1690	1438	1438
query60	335	273	275	273
query61	153	153	151	151
query62	545	494	437	437
query63	247	196	196	196
query64	2794	1033	829	829
query65	4737	4665	4627	4627
query66	1837	500	433	433
query67	29227	29156	29171	29156
query68	3197	1538	928	928
query69	429	300	269	269
query70	908	828	806	806
query71	370	341	300	300
query72	3041	2743	2413	2413
query73	832	837	435	435
query74	5088	4939	4734	4734
query75	2559	2486	2127	2127
query76	2332	1179	804	804
query77	342	367	292	292
query78	11971	11888	11307	11307
query79	1397	1142	765	765
query80	1331	538	462	462
query81	559	331	285	285
query82	635	153	118	118
query83	376	333	288	288
query84	285	162	129	129
query85	1001	618	561	561
query86	419	247	222	222
query87	1834	1825	1744	1744
query88	3722	2798	2781	2781
query89	453	370	330	330
query90	1929	209	189	189
query91	204	196	164	164
query92	61	60	54	54
query93	1668	1506	988	988
query94	718	366	316	316
query95	801	571	497	497
query96	1031	834	366	366
query97	2623	2616	2494	2494
query98	217	209	200	200
query99	1105	1133	968	968
Total cold run time: 263495 ms
Total hot run time: 177551 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.03 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 7efece3b359dce9fb468a0637e3c272119fc4aed, data reload: false

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.26	0.14	0.14
query4	1.60	0.15	0.14
query5	0.24	0.22	0.22
query6	1.25	1.10	1.03
query7	0.04	0.00	0.00
query8	0.05	0.04	0.04
query9	0.39	0.30	0.30
query10	0.53	0.61	0.53
query11	0.20	0.13	0.13
query12	0.19	0.14	0.14
query13	0.47	0.47	0.47
query14	1.03	1.02	1.02
query15	0.61	0.60	0.60
query16	0.33	0.31	0.34
query17	1.08	1.08	1.13
query18	0.22	0.21	0.21
query19	2.14	2.00	1.99
query20	0.02	0.01	0.01
query21	15.47	0.22	0.14
query22	4.81	0.05	0.05
query23	16.16	0.30	0.12
query24	2.94	0.39	0.33
query25	0.11	0.05	0.05
query26	0.74	0.20	0.16
query27	0.04	0.03	0.04
query28	3.56	0.94	0.54
query29	12.48	4.10	3.27
query30	0.27	0.14	0.15
query31	2.78	0.60	0.31
query32	3.22	0.59	0.50
query33	3.12	3.17	3.33
query34	15.65	4.18	3.52
query35	3.56	3.49	3.53
query36	0.55	0.46	0.42
query37	0.09	0.06	0.06
query38	0.06	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.17	0.16
query41	0.08	0.03	0.03
query42	0.04	0.02	0.02
query43	0.04	0.04	0.04
Total cold run time: 96.73 s
Total hot run time: 25.03 s

@github-actions

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Review context preparation failed before Codex ran; inspect the 'Prepare authoritative PR context and required AGENTS guides' step.
Workflow run: https://github.com/apache/doris/actions/runs/30430336300

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29290 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 7efece3b359dce9fb468a0637e3c272119fc4aed, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17649	4100	4073	4073
q2	2042	328	203	203
q3	10314	1406	819	819
q4	4677	477	342	342
q5	7524	847	571	571
q6	187	175	138	138
q7	789	805	618	618
q8	9344	1533	1532	1532
q9	5581	4336	4323	4323
q10	6782	1740	1479	1479
q11	508	349	325	325
q12	756	574	460	460
q13	18098	3424	2739	2739
q14	269	274	245	245
q15	q16	784	779	709	709
q17	965	1064	950	950
q18	6897	5719	5484	5484
q19	1297	1278	1125	1125
q20	820	684	576	576
q21	5839	2654	2274	2274
q22	423	357	305	305
Total cold run time: 101545 ms
Total hot run time: 29290 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4390	4288	4299	4288
q2	289	311	233	233
q3	4553	5000	4457	4457
q4	2076	2163	1368	1368
q5	4345	4206	4262	4206
q6	226	175	131	131
q7	1733	1648	2071	1648
q8	2659	2206	2172	2172
q9	7987	8173	7821	7821
q10	4628	4660	4219	4219
q11	577	433	382	382
q12	781	746	559	559
q13	3232	3599	2949	2949
q14	300	316	295	295
q15	q16	714	746	669	669
q17	1344	1333	1329	1329
q18	7976	7429	7436	7429
q19	1158	1140	1090	1090
q20	2208	2199	1944	1944
q21	5217	4508	4417	4417
q22	541	468	418	418
Total cold run time: 56934 ms
Total hot run time: 52024 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177166 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 7efece3b359dce9fb468a0637e3c272119fc4aed, data reload: false

query5	4334	627	490	490
query6	478	228	209	209
query7	4923	594	328	328
query8	360	187	175	175
query9	8777	3995	4036	3995
query10	489	365	308	308
query11	5957	2344	2122	2122
query12	162	102	101	101
query13	1255	562	419	419
query14	6253	5195	4873	4873
query14_1	4216	4218	4222	4218
query15	209	212	182	182
query16	995	471	468	468
query17	939	708	599	599
query18	2456	476	364	364
query19	214	195	158	158
query20	108	109	107	107
query21	231	163	135	135
query22	13706	13499	13277	13277
query23	17353	16424	16157	16157
query23_1	16257	16289	16246	16246
query24	7502	1771	1261	1261
query24_1	1325	1288	1290	1288
query25	578	457	387	387
query26	1361	366	223	223
query27	2567	600	390	390
query28	4453	2046	2046	2046
query29	1078	623	490	490
query30	335	263	227	227
query31	1113	1092	976	976
query32	125	62	62	62
query33	549	325	264	264
query34	1195	1131	643	643
query35	755	793	663	663
query36	1017	1021	906	906
query37	158	110	103	103
query38	1914	1694	1661	1661
query39	888	860	870	860
query39_1	849	822	826	822
query40	255	165	142	142
query41	66	65	64	64
query42	96	92	91	91
query43	317	325	282	282
query44	1413	764	766	764
query45	197	190	173	173
query46	1060	1197	730	730
query47	2118	2135	1997	1997
query48	412	375	297	297
query49	579	408	301	301
query50	1045	429	339	339
query51	10798	10593	10653	10593
query52	85	85	74	74
query53	274	271	204	204
query54	286	234	219	219
query55	75	69	66	66
query56	308	304	293	293
query57	1323	1311	1221	1221
query58	271	263	249	249
query59	1535	1624	1393	1393
query60	317	278	261	261
query61	153	153	150	150
query62	545	494	435	435
query63	242	200	200	200
query64	2816	1093	875	875
query65	4741	4622	4630	4622
query66	1851	544	373	373
query67	29246	28537	28983	28537
query68	3432	1519	1070	1070
query69	421	304	271	271
query70	880	808	819	808
query71	398	347	321	321
query72	3025	2705	2558	2558
query73	873	819	415	415
query74	5080	4897	4742	4742
query75	2548	2503	2159	2159
query76	2285	1188	800	800
query77	348	407	285	285
query78	11899	11844	11431	11431
query79	1377	1166	742	742
query80	1176	555	472	472
query81	542	336	287	287
query82	876	155	125	125
query83	382	332	307	307
query84	324	161	131	131
query85	999	615	525	525
query86	393	238	239	238
query87	1840	1828	1771	1771
query88	3680	2813	2805	2805
query89	444	384	322	322
query90	1938	194	190	190
query91	208	192	165	165
query92	66	60	54	54
query93	1540	1668	987	987
query94	658	360	302	302
query95	810	597	467	467
query96	1128	794	361	361
query97	2618	2608	2495	2495
query98	215	203	196	196
query99	1092	1111	972	972
Total cold run time: 263777 ms
Total hot run time: 177166 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.94 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 7efece3b359dce9fb468a0637e3c272119fc4aed, data reload: false

query1	0.01	0.00	0.01
query2	0.11	0.05	0.05
query3	0.26	0.14	0.13
query4	1.61	0.14	0.14
query5	0.23	0.23	0.22
query6	1.25	1.05	1.09
query7	0.04	0.01	0.00
query8	0.06	0.03	0.03
query9	0.37	0.31	0.30
query10	0.55	0.59	0.58
query11	0.18	0.13	0.14
query12	0.18	0.14	0.14
query13	0.47	0.47	0.46
query14	1.02	1.02	1.01
query15	0.61	0.58	0.60
query16	0.32	0.32	0.33
query17	1.11	1.14	1.08
query18	0.23	0.21	0.21
query19	2.03	1.91	2.00
query20	0.01	0.01	0.01
query21	15.41	0.20	0.14
query22	4.97	0.05	0.05
query23	16.15	0.31	0.13
query24	2.95	0.39	0.34
query25	0.10	0.05	0.05
query26	0.74	0.20	0.16
query27	0.05	0.04	0.04
query28	3.60	0.89	0.53
query29	12.46	4.10	3.26
query30	0.28	0.18	0.15
query31	2.77	0.58	0.32
query32	3.21	0.58	0.48
query33	3.14	3.18	3.22
query34	15.55	4.29	3.50
query35	3.53	3.52	3.50
query36	0.55	0.44	0.40
query37	0.10	0.07	0.07
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.19	0.16	0.15
query41	0.09	0.03	0.03
query42	0.04	0.02	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.67 s
Total hot run time: 24.94 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 38.46% (30/78) 🎉
Increment coverage report
Complete coverage report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants