2021-04-26 20:07:00 +02:00
#coding:utf-8
2022-02-04 19:05:19 +01:00
"""
ID : syspriv . access - shutdown - database
TITLE : Check ability to access to database in shutdown single mode as non - sysdba
DESCRIPTION :
We create role with granting system privilege ACCESS_SHUTDOWN_DATABASE to it .
Then we create user and make this role as DEFAULT to him .
2022-05-17 23:58:43 +02:00
Then we check that user ' TMP_SYSPRIV_USER ' :
1. can NOT CHANGE database attribute , i . e . can NOT shutdown or bring online database ;
2. CAN make attachment to DB in ' shutdown single maintenace ' mode and make some DML there .
Also , we check that while ' TMP_SYSPRIV_USER ' is connected , NO other attachment is possible .
2022-02-04 19:05:19 +01:00
This is done by trying to make ES EDS as SYSDBA - this should fail with " 335544528 : database shutdown " .
2021-04-26 20:07:00 +02:00
2022-02-04 19:05:19 +01:00
Checked on 4.0 .0 .267 . See also letter from Alex 23.06 .2016 11 : 46.
FBTEST : functional . syspriv . access_shutdown_database
2022-05-17 23:58:43 +02:00
NOTES : checked on 4.0 .1 .2692 , 5.0 .0 .489 .
2022-02-04 19:05:19 +01:00
"""
2021-04-26 20:07:00 +02:00
2022-02-04 19:05:19 +01:00
import pytest
from firebird . qa import *
2022-05-17 23:58:43 +02:00
from firebird . driver import ShutdownMode , ShutdownMethod
from firebird . driver . types import DatabaseError
substitutions = [ ( ' no permission for (shutdown|(bring online)) access to database .* ' , ' no permission for shutdown/online access to database ' )
2022-09-25 18:10:57 +02:00
, ( ' -Some database.* shutdown when trying to read mapping data ' , ' ' ) # <<< perhaps this is due to bug in Classic. May need to be deleted later // 25.09.2022
2022-05-17 23:58:43 +02:00
, ( ' 335544528 : database.* shutdown ' , ' 335544528 : database shutdown ' )
, ( ' Data source : Firebird::localhost:.* ' , ' Data source : Firebird::localhost: ' )
, ( ' -At block line: [ \\ d]+, col: [ \\ d]+ ' , ' -At block line ' )
]
db = db_factory ( )
2022-02-04 19:05:19 +01:00
2022-05-17 23:58:43 +02:00
tmp_user = user_factory ( ' db ' , name = ' tmp_syspriv_user ' , password = ' 123 ' )
tmp_role = role_factory ( ' db ' , name = ' tmp_role_for_access_shutdown_db ' )
2022-02-04 19:05:19 +01:00
act = python_act ( ' db ' , substitutions = substitutions )
2022-05-17 23:58:43 +02:00
expected_stdout_fbsvc = """
no permission for shutdown / online access to database
2022-02-04 19:05:19 +01:00
"""
2022-05-17 23:58:43 +02:00
expected_stdout_isql = """
WHO_AMI TMP_SYSPRIV_USER
2022-02-04 19:05:19 +01:00
RDB $ ROLE_NAME RDB $ ADMIN
RDB_ROLE_IN_USE < false >
RDB $ SYSTEM_PRIVILEGES FFFFFFFFFFFFFFFF
2022-05-17 23:58:43 +02:00
MON $ SHUTDOWN_MODE 2
WHO_AMI TMP_SYSPRIV_USER
RDB $ ROLE_NAME TMP_ROLE_FOR_ACCESS_SHUTDOWN_DB
2022-02-04 19:05:19 +01:00
RDB_ROLE_IN_USE < true >
RDB $ SYSTEM_PRIVILEGES 0001000000000000
MON $ SHUTDOWN_MODE 2
2022-05-17 23:58:43 +02:00
ATT_USER TMP_SYSPRIV_USER
2022-02-04 19:05:19 +01:00
ATT_PROT TCP
2022-05-17 23:58:43 +02:00
Statement failed , SQLSTATE = 42000
Execute statement error at attach :
335544528 : database shutdown
Data source : Firebird : : localhost :
- At block line
2022-02-04 19:05:19 +01:00
"""
@pytest.mark.version ( ' >=4.0 ' )
2022-05-17 23:58:43 +02:00
def test_1 ( act : Action , tmp_user : User , tmp_role : Role , capsys ) :
init_script = \
f '''
set wng off ;
create or alter view v_check as
select
current_user as who_ami
, r . rdb $ role_name
, rdb $ role_in_use ( r . rdb $ role_name ) as RDB_ROLE_IN_USE
, r . rdb $ system_privileges
, m . mon $ shutdown_mode
from mon $ database m cross join rdb $ roles r ;
commit ;
alter user { tmp_user . name } revoke admin role ;
revoke all on all from { tmp_user . name } ;
create or alter trigger trg_connect active on connect as
begin
end ;
commit ;
recreate table att_log (
att_id int ,
att_name varchar ( 255 ) ,
att_user varchar ( 255 ) ,
att_prot varchar ( 255 )
) ;
commit ;
grant select on v_check to public ;
grant all on att_log to public ;
commit ;
set term ^ ;
create or alter trigger trg_connect active on connect as
begin
if ( upper ( current_user ) < > upper ( ' SYSDBA ' ) ) then
in autonomous transaction do
insert into att_log ( att_name , att_user , att_prot )
select
mon $ attachment_name
, mon $ user
, left ( mon $ remote_protocol , 3 )
from mon $ attachments
where mon $ user = current_user
;
end
^
set term ; ^
commit ;
alter role { tmp_role . name }
set system privileges to ACCESS_SHUTDOWN_DATABASE ; - - CHANGE_SHUTDOWN_MODE , USE_GFIX_UTILITY , IGNORE_DB_TRIGGERS ;
commit ;
grant default { tmp_role . name } to user { tmp_user . name } ;
commit ;
'''
act . isql ( switches = [ ' -q ' ] , input = init_script )
# ---------------------------------------------------------------
2022-09-25 18:10:57 +02:00
# Must FAIL: user has right only to *access* to DB in shutdown-single mode and make some DMLs there.
# But he has NO right to change DB state to shutdown (any kind of mode).
# Expected error: "no permission for shutdown/online access to database ..."
2022-05-17 23:58:43 +02:00
with act . connect_server ( user = tmp_user . name , password = tmp_user . password , role = tmp_role . name ) as srv_nondba :
try :
srv_nondba . database . shutdown ( database = act . db . db_path
, mode = ShutdownMode . SINGLE
, method = ShutdownMethod . FORCED
, timeout = 0 )
except DatabaseError as e :
print ( e . __str__ ( ) )
2022-09-25 18:10:57 +02:00
act . expected_stdout = expected_stdout_fbsvc
act . stdout = capsys . readouterr ( ) . out
assert act . clean_stdout == act . clean_expected_stdout # <<<<<<<<<<<<<<<<<<<<<<<< check #0
act . reset ( )
#-----------------------------------------------------------------
2022-05-17 23:58:43 +02:00
2022-09-25 18:10:57 +02:00
# Must PASS: we change DB state to shut-single using SYSDBA account.
# No message must be issued now:
2022-05-17 23:58:43 +02:00
with act . connect_server ( ) as srv_sysdba :
try :
srv_sysdba . database . shutdown ( database = act . db . db_path
, mode = ShutdownMode . SINGLE
, method = ShutdownMethod . FORCED
, timeout = 0 )
except DatabaseError as e :
print ( e . __str__ ( ) )
2022-09-25 18:10:57 +02:00
act . expected_stdout = ' '
2022-05-17 23:58:43 +02:00
act . stdout = capsys . readouterr ( ) . out
assert act . clean_stdout == act . clean_expected_stdout # <<<<<<<<<<<<<<<<<<<<<<<< check #1
act . reset ( )
# ---------------------------------------------------------------
2022-09-25 18:10:57 +02:00
# Result: DB now is in shutdown-single mode.
# We have to check that only single attachment can be established to this DB:
2022-05-17 23:58:43 +02:00
sql_chk = '''
set list on ;
select v . * from v_check v ;
select a . att_user , att_prot from att_log a ;
set term ^ ;
execute block returns ( who_else_here rdb $ user ) as
declare another_user varchar ( 31 ) ;
begin
execute statement ' select current_user from rdb$database '
on external ' localhost: ' | | rdb $ get_context ( ' SYSTEM ' , ' DB_NAME ' )
as user ' SYSDBA ' password ' masterkey '
into who_else_here ;
suspend ;
end
^
set term ; ^
'''
act . isql ( switches = [ ' -q ' , ' -user ' , tmp_user . name , ' -pas ' , tmp_user . password , ' -role ' , tmp_role . name ] , input = sql_chk , credentials = False , combine_output = True )
act . expected_stdout = expected_stdout_isql
assert act . clean_stdout == act . clean_expected_stdout # <<<<<<<<<<<<<<<<<<<<<<<< check #2
act . reset ( )
# ---------------------------------------------------------------
# must FAIL: we attempt to bring DB online using NON-dba account:
2022-09-25 18:10:57 +02:00
# Expected error: "no permission for bring online access to database ..."
# !!!NB!!! As of 25.09.2022, for FB 4.x and 5.x in Classic mode additional message will raise here:
# "-Some database(s) were shutdown when trying to read mapping data"
# Sent report to Alex et al, 25.09.2022 18:55. Waiting for resolution.
#
2022-05-17 23:58:43 +02:00
with act . connect_server ( user = tmp_user . name , password = tmp_user . password , role = tmp_role . name ) as srv_nondba :
try :
srv_nondba . database . bring_online ( database = act . db . db_path )
except DatabaseError as e :
print ( e . __str__ ( ) )
2022-09-25 18:10:57 +02:00
act . expected_stdout = expected_stdout_fbsvc
act . stdout = capsys . readouterr ( ) . out
assert act . clean_stdout == act . clean_expected_stdout # <<<<<<<<<<<<<<<<<<<<<<<< check #3
act . reset ( )
2022-05-17 23:58:43 +02:00
# must PASS because here we return DB online using SYSDBA account:
with act . connect_server ( ) as srv_sysdba :
try :
srv_sysdba . database . bring_online ( database = act . db . db_path )
except DatabaseError as e :
print ( e . __str__ ( ) )
2022-09-25 18:10:57 +02:00
assert ' ' == capsys . readouterr ( ) . out
assert act . clean_stdout == act . clean_expected_stdout # <<<<<<<<<<<<<<<<<<<<<<<< check #4
2022-05-17 23:58:43 +02:00
act . reset ( )
2022-09-25 18:10:57 +02:00