Skip to content

Commit db9e0f9

Browse files
ggnmstrJelteF
andauthored
feat(planner): check postgres user rights for view in duckdb planner (#949)
resolves #948 --------- Co-authored-by: Jelte Fennema-Nio <[email protected]>
1 parent 382705e commit db9e0f9

File tree

4 files changed

+123
-1
lines changed

4 files changed

+123
-1
lines changed

src/pgduckdb_planner.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,16 @@ extern "C" {
2020
#include "tcop/pquery.h"
2121
#include "utils/syscache.h"
2222
#include "utils/guc.h"
23+
#include "parser/parse_relation.h"
24+
#include "utils/acl.h"
25+
#include "utils/lsyscache.h"
26+
#include "utils/rel.h"
2327

2428
#include "pgduckdb/pgduckdb_ruleutils.h"
29+
30+
#if PG_VERSION_NUM >= 180000
31+
#include "executor/executor.h"
32+
#endif
2533
}
2634

2735
#include "pgduckdb/pgduckdb_duckdb.hpp"
@@ -133,8 +141,56 @@ DuckdbRangeTableEntry(CustomScan *custom_scan) {
133141
return rte;
134142
}
135143

144+
static void
145+
check_view_perms_recursive(Query *query) {
146+
ListCell *lc;
147+
148+
if (query == NULL) {
149+
return;
150+
}
151+
152+
foreach (lc, query->rtable) {
153+
RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
154+
155+
#if PG_VERSION_NUM < 160000
156+
if (rte->relkind == RELKIND_VIEW) {
157+
bool result = ExecCheckRTEPerms(rte);
158+
if (!result) {
159+
aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_VIEW, get_rel_name(rte->relid));
160+
}
161+
}
162+
#else
163+
if (rte->perminfoindex != 0 && rte->relkind == RELKIND_VIEW) {
164+
RTEPermissionInfo *perminfo = getRTEPermissionInfo(query->rteperminfos, rte);
165+
bool result = ExecCheckOneRelPerms(perminfo);
166+
if (!result) {
167+
aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_VIEW, get_rel_name(perminfo->relid));
168+
}
169+
}
170+
#endif
171+
172+
if (rte->rtekind == RTE_SUBQUERY && rte->subquery) {
173+
check_view_perms_recursive(rte->subquery);
174+
}
175+
}
176+
177+
if (query->cteList) {
178+
ListCell *lc_cte;
179+
foreach (lc_cte, query->cteList) {
180+
CommonTableExpr *cte = (CommonTableExpr *)lfirst(lc_cte);
181+
if (IsA(cte->ctequery, Query)) {
182+
check_view_perms_recursive((Query *)cte->ctequery);
183+
}
184+
}
185+
}
186+
}
187+
136188
PlannedStmt *
137189
DuckdbPlanNode(Query *parse, int cursor_options, bool throw_error) {
190+
191+
/* Properly check perms if there's a view or WITH statement */
192+
check_view_perms_recursive(parse);
193+
138194
/* We need to check can we DuckDB create plan */
139195

140196
Plan *duckdb_plan = InvokeCPPFunc(CreatePlan, parse, throw_error);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
CREATE USER duckdb_view_admin IN ROLE duckdb_group;
2+
GRANT ALL ON SCHEMA public TO duckdb_view_admin;
3+
CREATE USER duckdb_view_user1 IN ROLE duckdb_group;
4+
SET ROLE duckdb_view_admin;
5+
CREATE VIEW duckdb_view AS SELECT r['a']::int as a FROM duckdb.query($$ SELECT 1 a $$) r;
6+
CREATE VIEW postgres_view AS SELECT 2 from generate_series(1,2);
7+
SET ROLE duckdb_view_user1;
8+
SELECT * from duckdb_view;
9+
ERROR: permission denied for view duckdb_view
10+
SELECT * from postgres_view;
11+
ERROR: permission denied for view postgres_view
12+
SELECT * from duckdb.query($$ FROM pgduckdb.public.duckdb_view $$);
13+
ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Executor Error: (PGDuckDB/Init) permission denied for view duckdb_view
14+
SELECT * from duckdb.query($$ FROM pgduckdb.public.postgres_view $$);
15+
ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Executor Error: (PGDuckDB/Init) permission denied for view postgres_view
16+
SET ROLE duckdb_view_admin;
17+
GRANT SELECT ON duckdb_view TO duckdb_view_user1;
18+
GRANT SELECT ON postgres_view TO duckdb_view_user1;
19+
SET ROLE duckdb_view_user1;
20+
SELECT * from duckdb_view;
21+
a
22+
---
23+
1
24+
(1 row)
25+
26+
SELECT * from postgres_view;
27+
?column?
28+
----------
29+
2
30+
2
31+
(2 rows)
32+
33+
SELECT * from duckdb.query($$ FROM pgduckdb.public.duckdb_view $$);
34+
ERROR: (PGDuckDB/Duckdb_ExecCustomScan_Cpp) Executor Error: (PGDuckDB/GetNextTuple) Function 'duckdb.query' only works with DuckDB execution
35+
SELECT * from duckdb.query($$ FROM pgduckdb.public.postgres_view $$);
36+
?column?
37+
----------
38+
2
39+
2
40+
(2 rows)
41+

test/regression/expected/execution_error.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Did you mean "main.pragma_user_agent"?
1616

1717
LINE 1: SELECT raw_query FROM duckdb.raw_query('aaaaa'::text) raw_query(raw_query)
1818
^
19-
LOCATION: CreatePlan, pgduckdb_planner.cpp:58
19+
LOCATION: CreatePlan, pgduckdb_planner.cpp:66
2020
ERROR: XX000: (PGDuckDB/pgduckdb_raw_query_cpp) Parser Error: syntax error at or near "aaaaa"
2121

2222
LINE 1: aaaaa
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
CREATE USER duckdb_view_admin IN ROLE duckdb_group;
2+
GRANT ALL ON SCHEMA public TO duckdb_view_admin;
3+
CREATE USER duckdb_view_user1 IN ROLE duckdb_group;
4+
5+
SET ROLE duckdb_view_admin;
6+
7+
CREATE VIEW duckdb_view AS SELECT r['a']::int as a FROM duckdb.query($$ SELECT 1 a $$) r;
8+
CREATE VIEW postgres_view AS SELECT 2 from generate_series(1,2);
9+
10+
SET ROLE duckdb_view_user1;
11+
12+
SELECT * from duckdb_view;
13+
SELECT * from postgres_view;
14+
SELECT * from duckdb.query($$ FROM pgduckdb.public.duckdb_view $$);
15+
SELECT * from duckdb.query($$ FROM pgduckdb.public.postgres_view $$);
16+
17+
SET ROLE duckdb_view_admin;
18+
GRANT SELECT ON duckdb_view TO duckdb_view_user1;
19+
GRANT SELECT ON postgres_view TO duckdb_view_user1;
20+
SET ROLE duckdb_view_user1;
21+
22+
SELECT * from duckdb_view;
23+
SELECT * from postgres_view;
24+
SELECT * from duckdb.query($$ FROM pgduckdb.public.duckdb_view $$);
25+
SELECT * from duckdb.query($$ FROM pgduckdb.public.postgres_view $$);

0 commit comments

Comments
 (0)