|
| 1 | +#coding:utf-8 |
| 2 | + |
| 3 | +""" |
| 4 | +ID: syspriv.ignore-db-triggers |
| 5 | +TITLE: Check ability of non-sysdba and non-owner to ignore DB triggers |
| 6 | +DESCRIPTION: |
| 7 | + Test creates two users (tmp_senior, tmp_junior) and role with IGNORE_DB_TRIGGERS system privilege. |
| 8 | + This role is granted as default to tmp_senior (and only to him). |
| 9 | + Also, all types of DB-level triggers are created and each of them appends ros into 'tlog' table. |
| 10 | + Then we run ISQL with requirement to skip execution of DB triggers ('-nod' switch). |
| 11 | + ISQL first make attempt to connect as tmp_junior and this must fail with SQLSTATE = 28000. |
| 12 | + Then ISQL makes connection as tmp_junior and does commit, implicit start of TX, select, rollback and |
| 13 | + implicit disconnect followed by connection by SYSDBA. |
| 14 | + All these operations (performed by tmp_senior) must ignore DB-level triggers and this is checked |
| 15 | + by query to the table TLOG: it must remain empty. |
| 16 | + Finally, we REVOKE role from tmp_senior and try to make connection again, using '-nod' switch. |
| 17 | + This must fail with SQLSTATE = 28000 ("Unable to perform ... / ... IGNORE_DB_TRIGGERS is missing") |
| 18 | +NOTES: |
| 19 | + [24.04.2024] pzotov |
| 20 | + This system privilege also is used in following tests: |
| 21 | + test_change_header_settings.py ; test_change_shutdown_mode.py ; test_use_gstat_utility.py |
| 22 | + Checked on: 6.0.0.325, 5.0.1.1383, 4.0.5.3086. |
| 23 | +""" |
| 24 | + |
| 25 | +import locale |
| 26 | +import pytest |
| 27 | +from firebird.qa import * |
| 28 | + |
| 29 | +init_script = """ |
| 30 | + set wng off; |
| 31 | + set bail on; |
| 32 | +
|
| 33 | + recreate table tlog ( |
| 34 | + id int generated by default as identity |
| 35 | + ,event_name varchar(50) |
| 36 | + ,conn_user varchar(32) default current_user |
| 37 | + ,conn_role varchar(32) default current_role |
| 38 | + ); |
| 39 | +
|
| 40 | + create or alter view v_check as |
| 41 | + select |
| 42 | + current_user as who_ami |
| 43 | + ,r.rdb$role_name |
| 44 | + ,rdb$role_in_use(r.rdb$role_name) as RDB_ROLE_IN_USE |
| 45 | + ,r.rdb$system_privileges |
| 46 | + from rdb$roles r |
| 47 | + where r.rdb$system_flag is distinct from 1 |
| 48 | + ; |
| 49 | + commit; |
| 50 | + grant select on v_check to public; |
| 51 | +
|
| 52 | + set term ^; |
| 53 | + execute block as |
| 54 | + begin |
| 55 | + rdb$set_context('USER_SESSION', 'INIT_SQL', 1); |
| 56 | + end |
| 57 | + ^ |
| 58 | + create or alter trigger trg_attach active on connect as |
| 59 | + begin |
| 60 | + if ( rdb$get_context('USER_SESSION', 'INIT_SQL') is null ) then |
| 61 | + insert into tlog(event_name) values ('attach'); |
| 62 | + end |
| 63 | + ^ |
| 64 | + create or alter trigger trg_detach active on disconnect as |
| 65 | + begin |
| 66 | + if ( rdb$get_context('USER_SESSION', 'INIT_SQL') is null ) then |
| 67 | + insert into tlog(event_name) values ('detach'); |
| 68 | + end |
| 69 | + ^ |
| 70 | + create or alter trigger trg_tx_start active on transaction start as |
| 71 | + begin |
| 72 | + if ( rdb$get_context('USER_SESSION', 'INIT_SQL') is null ) then |
| 73 | + insert into tlog(event_name) values ('tx_start'); |
| 74 | + end |
| 75 | + ^ |
| 76 | + create or alter trigger trg_tx_commit active on transaction commit as |
| 77 | + begin |
| 78 | + if ( rdb$get_context('USER_SESSION', 'INIT_SQL') is null ) then |
| 79 | + insert into tlog(event_name) values ('tx_commit'); |
| 80 | + end |
| 81 | + ^ |
| 82 | + create or alter trigger trg_tx_rollback active on transaction rollback as |
| 83 | + begin |
| 84 | + if ( rdb$get_context('USER_SESSION', 'INIT_SQL') is null ) then |
| 85 | + insert into tlog(event_name) values ('tx_rolback'); |
| 86 | + end |
| 87 | + ^ |
| 88 | + set term ;^ |
| 89 | + commit; |
| 90 | +""" |
| 91 | + |
| 92 | +db = db_factory(init = init_script) |
| 93 | +act = python_act('db', substitutions=[('[ \t]+', ' ')]) |
| 94 | + |
| 95 | +tmp_junior = user_factory('db', name='tmp$junior', password='123', plugin = 'Srp') |
| 96 | +tmp_senior = user_factory('db', name='tmp$senior', password='456', plugin = 'Srp') |
| 97 | +tmp_role = role_factory('db', name='tmp$role_ignore_dbtrg') |
| 98 | + |
| 99 | +@pytest.mark.version('>=4.0') |
| 100 | +def test_1(act: Action, tmp_junior: User, tmp_senior: User, tmp_role: Role): |
| 101 | + |
| 102 | + test_script = f""" |
| 103 | + set wng off; |
| 104 | + set list on; |
| 105 | + set count on; |
| 106 | + set bail on; |
| 107 | +
|
| 108 | + set term ^; |
| 109 | + execute block as |
| 110 | + begin |
| 111 | + rdb$set_context('USER_SESSION', 'INIT_SQL', 1); |
| 112 | + end |
| 113 | + ^ |
| 114 | + set term ;^ |
| 115 | + alter role {tmp_role.name} |
| 116 | + set system privileges to |
| 117 | + IGNORE_DB_TRIGGERS |
| 118 | + ; |
| 119 | + revoke all on all from {tmp_senior.name}; |
| 120 | + grant default {tmp_role.name} to user {tmp_senior.name}; |
| 121 | + commit; |
| 122 | + set bail off; |
| 123 | + ---------------------------------------------------------------------- |
| 124 | + connect '{act.db.dsn}' user {tmp_junior.name} password '{tmp_junior.password}'; |
| 125 | + rollback; |
| 126 | + connect '{act.db.dsn}' user {tmp_senior.name} password '{tmp_senior.password}'; |
| 127 | + commit; |
| 128 | + select 'check-1a' as msg, v.* from v_check v; |
| 129 | + rollback; |
| 130 | + ---------------------------------------------------------------------- |
| 131 | + connect '{act.db.dsn}' user {act.db.user} password '{act.db.password}'; |
| 132 | + select 'check-1b' as msg, g.* from rdb$database left join tlog g on upper(g.conn_user) is distinct from upper('{act.db.user}'); |
| 133 | + """ |
| 134 | + |
| 135 | + act.expected_stdout = f""" |
| 136 | + Statement failed, SQLSTATE = 28000 |
| 137 | + Unable to perform operation |
| 138 | + -System privilege IGNORE_DB_TRIGGERS is missing |
| 139 | +
|
| 140 | + MSG check-1a |
| 141 | + WHO_AMI TMP$SENIOR |
| 142 | + RDB$ROLE_NAME TMP$ROLE_IGNORE_DBTRG |
| 143 | + RDB_ROLE_IN_USE <true> |
| 144 | + RDB$SYSTEM_PRIVILEGES 0040000000000000 |
| 145 | + Records affected: 1 |
| 146 | +
|
| 147 | + MSG check-1b |
| 148 | + ID <null> |
| 149 | + EVENT_NAME <null> |
| 150 | + CONN_USER <null> |
| 151 | + CONN_ROLE <null> |
| 152 | + Records affected: 1 |
| 153 | + """ |
| 154 | + act.isql(switches=['-n', '-q', '-nod'], input = test_script, combine_output = True, io_enc = locale.getpreferredencoding()) |
| 155 | + assert act.clean_stdout == act.clean_expected_stdout |
| 156 | + act.reset() |
| 157 | + |
| 158 | + ################################################### |
| 159 | + |
| 160 | + test_script = f""" |
| 161 | + set list on; |
| 162 | + set count on; |
| 163 | + set bail on; |
| 164 | +
|
| 165 | + set term ^; |
| 166 | + execute block as |
| 167 | + begin |
| 168 | + rdb$set_context('USER_SESSION', 'INIT_SQL', 1); |
| 169 | + end |
| 170 | + ^ |
| 171 | + set term ;^ |
| 172 | + alter role {tmp_role.name} |
| 173 | + set system privileges to |
| 174 | + IGNORE_DB_TRIGGERS |
| 175 | + ; |
| 176 | + revoke default {tmp_role.name} from user {tmp_senior.name}; |
| 177 | + commit; |
| 178 | + set bail off; |
| 179 | + ---------------------------------------------------------------------- |
| 180 | + connect '{act.db.dsn}' user {tmp_senior.name} password '{tmp_senior.password}'; |
| 181 | + commit; |
| 182 | + select 'check-2a' as msg, v.* from v_check v; |
| 183 | + rollback; |
| 184 | + ---------------------------------------------------------------------- |
| 185 | + connect '{act.db.dsn}' user {act.db.user} password '{act.db.password}'; |
| 186 | + select 'check-2b' as msg, g.* from rdb$database left join tlog g on upper(g.conn_user) is distinct from upper('{act.db.user}'); |
| 187 | + """ |
| 188 | + |
| 189 | + act.expected_stdout = f""" |
| 190 | + Statement failed, SQLSTATE = 28000 |
| 191 | + Unable to perform operation |
| 192 | + -System privilege IGNORE_DB_TRIGGERS is missing |
| 193 | +
|
| 194 | + MSG check-2b |
| 195 | + ID <null> |
| 196 | + EVENT_NAME <null> |
| 197 | + CONN_USER <null> |
| 198 | + CONN_ROLE <null> |
| 199 | + Records affected: 1 |
| 200 | + """ |
| 201 | + act.isql(switches=['-n', '-q', '-nod'], input = test_script, combine_output = True, io_enc = locale.getpreferredencoding()) |
| 202 | + assert act.clean_stdout == act.clean_expected_stdout |
| 203 | + act.reset() |
| 204 | + |
0 commit comments