Changeset: 1a20d058fda3 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=1a20d058fda3 Added Files: sql/test/Views/Tests/Indirect.py sql/test/Views/Tests/Indirect.stable.err sql/test/Views/Tests/Indirect.stable.out Modified Files: sql/server/rel_select.c sql/test/Views/Tests/All Branch: indirect-privs Log Message:
Fixed privileged access on views. If the user is allowed to select a subset of columns from a view, no error should be thrown at reference time. diffs (156 lines): diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c --- a/sql/server/rel_select.c +++ b/sql/server/rel_select.c @@ -962,9 +962,9 @@ table_ref(sql_query *query, sql_rel *rel } if (!allowed) rel = rel_reduce_on_column_privileges(sql, rel, t); - if (allowed && rel) - return rel; - return sql_error(sql, 02, SQLSTATE(42000) "SELECT: access denied for %s to table '%s.%s'", get_string_global_var(sql, "current_user"), t->s->base.name, tname); + if (!rel) + return sql_error(sql, 02, SQLSTATE(42000) "SELECT: access denied for %s to view '%s.%s'", get_string_global_var(sql, "current_user"), t->s->base.name, tname); + return rel; } if ((isMergeTable(t) || isReplicaTable(t)) && list_empty(t->members)) return sql_error(sql, 02, SQLSTATE(42000) "MERGE or REPLICA TABLE should have at least one table associated"); @@ -972,7 +972,7 @@ table_ref(sql_query *query, sql_rel *rel if (!allowed) { res = rel_reduce_on_column_privileges(sql, res, t); if (!res) - return sql_error(sql, 02, SQLSTATE(42000) "SELECT: access denied for %s to table '%s.%s'", get_string_global_var(sql, "current_user"), t->s->base.name, tname); + return sql_error(sql, 02, SQLSTATE(42000) "SELECT: access denied for %s to %s '%s.%s'", get_string_global_var(sql, "current_user"), isView(t) ? "view" : "table", t->s->base.name, tname); } if (tableref->data.lval->h->next->data.sym && tableref->data.lval->h->next->data.sym->data.lval->h->next->data.lval) { /* AS with column aliases */ res = rel_table_optname(sql, res, tableref->data.lval->h->next->data.sym, refs); diff --git a/sql/test/Views/Tests/All b/sql/test/Views/Tests/All --- a/sql/test/Views/Tests/All +++ b/sql/test/Views/Tests/All @@ -1,1 +1,2 @@ Views +Indirect diff --git a/sql/test/Views/Tests/Indirect.py b/sql/test/Views/Tests/Indirect.py new file mode 100644 --- /dev/null +++ b/sql/test/Views/Tests/Indirect.py @@ -0,0 +1,86 @@ +import os, sys, pymonetdb + + +port = int(os.environ['MAPIPORT']) +db = os.environ['TSTDB'] + +conn1 = pymonetdb.connect(port=port,database=db,autocommit=True,username='monetdb',password='monetdb') +cur1 = conn1.cursor() +cur1.execute(""" +start transaction; +create schema foo; +create user u1 with password '1' name 'u1' schema foo; +create user u2 with password '2' name 'u2' schema foo; +create table foo.tab1 (col1 int, col2 int); +create table foo.tab2 (col1 int, col2 int); +insert into foo.tab1 values (1, 1); +insert into foo.tab2 values (2, 2); +create view foo.v1(col1,col2) as (select col1, col2 from foo.tab1); +create view foo.v2(col1,col2) as (select col1, col2 from foo.tab2); +commit; +""") +cur1.close() +conn1.close() + +conn1 = pymonetdb.connect(port=port,database=db,autocommit=True,username='u1',password='1') +cur1 = conn1.cursor() +try: + cur1.execute('SELECT "col1" FROM "foo"."v1";') # error, not allowed + sys.stderr.write("Exception expected") +except pymonetdb.DatabaseError as e: + if "SELECT: access denied for u1 to view 'foo.v1'" not in str(e): + sys.stderr.write('Wrong error %s, expected SELECT: access denied for u1 to view \'foo.v1\'' % (str(e))) +try: + cur1.execute('SELECT "col2" FROM "foo"."v1";') # error, not allowed + sys.stderr.write("Exception expected") +except pymonetdb.DatabaseError as e: + if "SELECT: access denied for u1 to view 'foo.v1'" not in str(e): + sys.stderr.write('Wrong error %s, expected SELECT: access denied for u1 to view \'foo.v1\'' % (str(e))) +try: + cur1.execute('SELECT "col1" FROM "foo"."tab1";') # error, not allowed + sys.stderr.write("Exception expected") +except pymonetdb.DatabaseError as e: + if "SELECT: access denied for u1 to table 'foo.tab1'" not in str(e): + sys.stderr.write('Wrong error %s, expected SELECT: access denied for u1 to table \'foo.tab1\'' % (str(e))) +cur1.close() +conn1.close() + +conn1 = pymonetdb.connect(port=port,database=db,autocommit=True,username='monetdb',password='monetdb') +cur1 = conn1.cursor() +cur1.execute(""" +grant select ("col1") ON "foo"."v1" TO u1; +""") +cur1.close() +conn1.close() + +conn1 = pymonetdb.connect(port=port,database=db,autocommit=True,username='u1',password='1') +cur1 = conn1.cursor() +cur1.execute('SELECT "col1" FROM "foo"."v1";') +if cur1.fetchall() != [(1, )]: + sys.stderr.write("[(1, )] expected") +try: + cur1.execute('SELECT "col2" FROM "foo"."v1";') # error, not allowed + sys.stderr.write("Exception expected") +except pymonetdb.DatabaseError as e: + if "SELECT: identifier 'col2' unknown" not in str(e): + sys.stderr.write('Wrong error %s, expected "SELECT: identifier \'col2\' unknown' % (str(e))) +try: + cur1.execute('SELECT "col1" FROM "foo"."tab1";') # error, not allowed + sys.stderr.write("Exception expected") +except pymonetdb.DatabaseError as e: + if "SELECT: access denied for u1 to table 'foo.tab1'" not in str(e): + sys.stderr.write('Wrong error %s, expected SELECT: access denied for u1 to table \'foo.tab1\'' % (str(e))) +cur1.close() +conn1.close() + +conn1 = pymonetdb.connect(port=port,database=db,autocommit=True,username='monetdb',password='monetdb') +cur1 = conn1.cursor() +cur1.execute(""" +start transaction; +drop user u1; +drop user u2; +drop schema foo cascade; +commit; +""") +cur1.close() +conn1.close() diff --git a/sql/test/Views/Tests/Indirect.stable.err b/sql/test/Views/Tests/Indirect.stable.err new file mode 100644 --- /dev/null +++ b/sql/test/Views/Tests/Indirect.stable.err @@ -0,0 +1,12 @@ +stderr of test 'Indirect` in directory 'sql/test/Views` itself: + + +# 17:45:28 > +# 17:45:28 > "/usr/bin/python3.9" "Indirect.py" "Indirect" +# 17:45:28 > + + +# 17:45:28 > +# 17:45:28 > "Done." +# 17:45:28 > + diff --git a/sql/test/Views/Tests/Indirect.stable.out b/sql/test/Views/Tests/Indirect.stable.out new file mode 100644 --- /dev/null +++ b/sql/test/Views/Tests/Indirect.stable.out @@ -0,0 +1,12 @@ +stdout of test 'Indirect` in directory 'sql/test/Views` itself: + + +# 17:45:28 > +# 17:45:28 > "/usr/bin/python3.9" "Indirect.py" "Indirect" +# 17:45:28 > + + +# 17:45:28 > +# 17:45:28 > "Done." +# 17:45:28 > + _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list