#coding:utf-8 # # id: functional.tabloid.dml_privileges_sufficiency # title: Verify sufficiency of privileges for performing DML actions. Verify that RETURNING clause can not be used without SELECT privilege. # decription: # Test creates three users (for I/U/D) and gives them initial privileges for INSERT, UPDATE and DELETE (but without SELECT). # Then we check that each user: # 1) can do "his" DML without using RETURNING clause and this action must pass; # 2) can NOT do "his" DML with using RETURNING clause because of absense of SELETC privilege. # After this we add SELECT privilege for all of them and repeat. All actions must pased in this case. # # Created by request of dimitr, letter 16.06.2020 13:54. # Checked on 4.0.0.2066. # ::: NB ::: # Do NOT use this test on 4.0.0.2046 and 4.0.0.2048 - these snapshots have bug and will crash on this test. # # tracker_id: # min_versions: ['4.0.0'] # versions: 4.0 # qmid: None import pytest from firebird.qa import db_factory, isql_act, Action # version: 4.0 # resources: None substitutions_1 = [('[ \t]+', ' ')] init_script_1 = """""" db_1 = db_factory(sql_dialect=3, init=init_script_1) test_script_1 = """ set wng off; set list on; set term ^; execute block as begin begin execute statement 'drop user tmp$modifier_ins' with autonomous transaction; when any do begin end end begin execute statement 'drop user tmp$modifier_upd' with autonomous transaction; when any do begin end end begin execute statement 'drop user tmp$modifier_del' with autonomous transaction; when any do begin end end end^ set term ;^ commit; --------------- 4.0.0.2046, 4.0.0.2048: crash here set bail off; create user tmp$modifier_ins password '123'; create user tmp$modifier_upd password '123'; create user tmp$modifier_del password '123'; revoke all on all from tmp$modifier_ins; revoke all on all from tmp$modifier_upd; revoke all on all from tmp$modifier_del; create sequence g; recreate table test(id int primary key, x int); insert into test(id,x) values( gen_id(g,1), 100); commit; grant usage on sequence g to tmp$modifier_ins; grant usage on sequence g to tmp$modifier_upd; grant insert on test to tmp$modifier_ins; grant update on test to tmp$modifier_upd; grant delete on test to tmp$modifier_del; commit; create or alter view v_privs as select rdb$user -- tmp$c6317 ,rdb$relation_name -- test ,rdb$privilege -- S ,rdb$grant_option -- 0 ,rdb$field_name -- ,rdb$object_type -- 0 from rdb$user_privileges p where rdb$user in ( upper('tmp$modifier_ins'), upper('tmp$modifier_upd'), upper('tmp$modifier_del') ) order by rdb$user, rdb$privilege ; commit; -- ####### P R I V I L E G E O N L Y F O R I N S E R T ######## connect '$(DSN)' user tmp$modifier_ins password '123'; select current_user as whoami, 'Has only INSERT privilege' as msg from rdb$database; -- must fail because no 'select' privilege was granted to 'tmp$modifier_ins': select * from test; -- no exception must be here: insert into test(id,x) values(gen_id(g,1), 200); rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_ins': insert into test(id,x) values(gen_id(g,1), 1234567) returning id,x; rollback; -- must PASS: we have privilege to add record and RETURNING clause -- does NOT contain anything from *table*: insert into test(id,x) values(gen_id(g,1), 1234567) returning pi(); rollback; -- ####### P R I V I L E G E O N L Y F O R U P D A T E ######## connect '$(DSN)' user tmp$modifier_upd password '123'; select current_user as whoami, 'Has only UPDATE privilege' as msg from rdb$database; -- must fail because no 'select' privilege was granted to 'tmp$modifier_upd': select * from test; -- must fail because no 'select' privilege was granted to 'tmp$modifier_upd' -- NB: "set x = -x" - this statement DOES query to old value of 'x', -- i.e. is SELECTS table thust must fail: update test set x = -x; rollback; -- must PASS, no exception must be here: we do NOT interesting on old value of 'x': update test set x = 0; rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_upd': update test set x = 0 order by id rows 1; rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_upd': update test set x = 111 where id = 1; rollback; -- must PASS: we have privilege to change column and RETURNING clause -- does NOT contain anything from *table*: update test set x = 0 returning pi(); rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_upd': update test set x = 0 returning x; rollback; -- ####### P R I V I L E G E O N L Y F O R D E L E T E ######## connect '$(DSN)' user tmp$modifier_del password '123'; select current_user as whoami, 'Has only DELETE privilege' as msg from rdb$database; -- must fail because no 'select' privilege was granted to 'tmp$modifier_del': select * from test; -- must PASS: user has privilege to DELETE rows from this table: delete from test; rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_del': delete from test where id > 0; rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_del': delete from test order by id rows 1; rollback; -- must fail because no 'select' privilege was granted to 'tmp$modifier_del': delete from test returning id; rollback; -- ############################################################## -- ### A D D P R I V I L E G E F O R S E L E C T ### -- ############################################################## connect '$(DSN)' user SYSDBA password 'masterkey'; grant select on test to tmp$modifier_ins; grant select on test to tmp$modifier_upd; grant select on test to tmp$modifier_del; commit; -- #### P R I V I L E G E F O R I N S E R T + S E L E C T ##### connect '$(DSN)' user tmp$modifier_ins password '123'; select current_user as whoami, 'Has INSERT + SELECT privileges' as msg from rdb$database; -- All subsequent statements must PASS: select * from test; insert into test(id,x) values(-1, 1234567) returning id,x; rollback; -- #### P R I V I L E G E F O R U P D A T E + S E L E C T ##### connect '$(DSN)' user tmp$modifier_upd password '123'; select current_user as whoami, 'Has UPDATE + SELECT privileges' as msg from rdb$database; -- All subsequent statements must PASS: select * from test; update test set x = -x; rollback; update test set x = 0; rollback; update test set x = 0 order by id rows 1; rollback; update test set x = 111 where id = 1; rollback; update test set x = 0 returning x; rollback; -- #### P R I V I L E G E F O R D E L E T E + S E L E C T ##### connect '$(DSN)' user tmp$modifier_del password '123'; select current_user as whoami, 'Has DELETE + SELECT privileges' as msg from rdb$database; -- All subsequent statements must PASS: select * from test; delete from test where id > 0; rollback; delete from test order by id rows 1; rollback; delete from test returning id; rollback; -- ######################### -- ### C L E A N U P ### -- ######################### connect '$(DSN)' user SYSDBA password 'masterkey'; drop user tmp$modifier_ins; drop user tmp$modifier_upd; drop user tmp$modifier_del; commit; """ act_1 = isql_act('db_1', test_script_1, substitutions=substitutions_1) expected_stdout_1 = """ WHOAMI TMP$MODIFIER_INS MSG Has only INSERT privilege PI 3.141592653589793 WHOAMI TMP$MODIFIER_UPD MSG Has only UPDATE privilege PI 3.141592653589793 WHOAMI TMP$MODIFIER_DEL MSG Has only DELETE privilege WHOAMI TMP$MODIFIER_INS MSG Has INSERT + SELECT privileges ID 1 X 100 ID -1 X 1234567 WHOAMI TMP$MODIFIER_UPD MSG Has UPDATE + SELECT privileges ID 1 X 100 X 0 WHOAMI TMP$MODIFIER_DEL MSG Has DELETE + SELECT privileges ID 1 X 100 ID 1 """ expected_stderr_1 = """ Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_INS Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_INS Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_UPD Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_UPD Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_UPD Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_UPD Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_UPD Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_DEL Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_DEL Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_DEL Statement failed, SQLSTATE = 28000 no permission for SELECT access to TABLE TEST -Effective user is TMP$MODIFIER_DEL """ @pytest.mark.version('>=4.0') def test_1(act_1: Action): act_1.expected_stdout = expected_stdout_1 act_1.expected_stderr = expected_stderr_1 act_1.execute() assert act_1.clean_expected_stderr == act_1.clean_stderr assert act_1.clean_expected_stdout == act_1.clean_stdout