6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00

Added/Updated tests\bugs\core_6469_test.py: One need to check for admin rights of current OS user (noted by Dimitry Sibiryakov). ISQL output must be checked for matching to expected before trace log (see func run_script()). Replaced hard-coded name of role with 'f{tmp_role.name}' notation.

This commit is contained in:
pavel-zotov 2024-08-02 11:36:32 +03:00
parent a3a170d07c
commit 9c70256e56

View File

@ -1,283 +1,311 @@
#coding:utf-8 #coding:utf-8
""" """
ID: issue-2376 ID: issue-2376
ISSUE: 2376 ISSUE: 2376
TITLE: Provide ability to see in the trace log actions related to session management (e.g. ALTER SESSION RESET) TITLE: Provide ability to see in the trace log actions related to session management (e.g. ALTER SESSION RESET)
DESCRIPTION: DESCRIPTION:
Test verifies management statements which are specified in doc/sql.extensions/README.management_statements_psql.md Test verifies management statements which are specified in doc/sql.extensions/README.management_statements_psql.md
We launch trace session before ISQL and stop it after its finish. We launch trace session before ISQL and stop it after its finish.
Every management statement is expected to be found in the trace log. Every management statement is expected to be found in the trace log.
NOTES:
ATTENTION: TWO SEPARATE BRANCHES present in this test for different OS. [08.04.2022] pzotov
ATTENTION: TWO SEPARATE BRANCHES present in this test for different OS.
NOTES FOR WINDOWS 1. NOTES FOR WINDOWS
################# ####################
Statement 'SET TRUSTED ROLE' is verified for appearance in the trace log. Statement 'SET TRUSTED ROLE' is verified for appearance in the trace log.
There are several prerequisites that must be met for check SET TRUSTED ROLE statement: There are several prerequisites that must be met for check SET TRUSTED ROLE statement:
* BOTH AuthServer and AuthClient parameters from firebird.conf contain 'Win_Sspi' as plugin, in any place; * BOTH AuthServer and AuthClient parameters from firebird.conf contain 'Win_Sspi' as plugin, in any place;
* current OS user has admin rights; * current OS user has admin rights, otherwise we get "SQLSTATE = 0P000 / Your attachment has no trusted role"
* OS environment has *no* variables ISC_USER and ISC_PASSWORD (i.e. they must be UNSET); * OS environment has *no* variables ISC_USER and ISC_PASSWORD (i.e. they must be UNSET);
* Two mappings are created (both uses plugin win_sspi): * Two mappings are created (both uses plugin win_sspi):
** from any user to user; ** from any user to user;
** from predefined_group domain_any_rid_admins to role <role_to_be_trusted> ** from predefined_group domain_any_rid_admins to role <role_to_be_trusted>
Connect to database should be done in form: CONNECT '<computername>:<our_database>' role <role_to_be_trusted>', Connect to database should be done in form: CONNECT '<computername>:<our_database>' role <role_to_be_trusted>',
and after this we can user 'SET TRUSTED ROLE' statement (see also: core_5887-trusted_role.fbt). and after this we can user 'SET TRUSTED ROLE' statement (see also: core_5887-trusted_role.fbt).
::: NOTE ::: ::: NOTE :::
We have to remove OS-veriable 'ISC_USER' before any check of trusted role. We have to remove OS-veriable 'ISC_USER' before any check of trusted role.
This variable could be set by other .fbts which was performed before current within batch mode (i.e. when fbt_run is called from <rundaily>) This variable could be set by other .fbts which was performed before current within batch mode (i.e. when fbt_run is called from <rundaily>)
NOTES FOR LINUX 2. NOTES FOR LINUX
############### ##################
Trusted role is not verified for this case. Trusted role is not verified for this case.
Weird behaviour detected when test was ran on FB 4.0.0.2377 SuperServer: if we run this test several times (e.g. in loop) then *all* Weird behaviour detected when test was ran on FB 4.0.0.2377 SuperServer: if we run this test several times (e.g. in loop) then *all*
statements related to session management can be missed in the trace - despite the fact that they *for sure* was performed successfully statements related to session management can be missed in the trace - despite the fact that they *for sure* was performed successfully
(this can be seen in ISQL log). It seems that fail somehow related to the duration of DELAY between subsequent runs: if delay more than ~30s (this can be seen in ISQL log). It seems that fail somehow related to the duration of DELAY between subsequent runs: if delay more than ~30s
then almost no fails. But if delay is small then test can fail for almost every run. then almost no fails. But if delay is small then test can fail for almost every run.
NO such trouble in the Classic. NO such trouble in the Classic.
The reason currently (03-mar-2021) remains unknown. The reason currently (03-mar-2021) remains unknown.
Sent letter to Alex et al, 03-mar-2021. Sent letter to Alex et al, 03-mar-2021.
NOTES:
[09.02.2022] pcisar [WINDOWS]
Test fails on Windows as script execution fails with: 1. The 'CONNECT ...' operator, being specified without USER/PASSWORD clauses, will take in account parameters that were specified in the command line
Statement failed, SQLSTATE = 0P000 of ISQL (confirmed by Alex, letter 03.04.2022 20:31).
Your attachment has no trusted role This means that it will use 'SYSDBA' / 'masterkey' rather than Windows trusted auth. This, in turn, leads that SYSDBA will be current user
when following is performed:
[08.04.2022] pzotov connect '{THIS_COMPUTER_NAME}:{act.db.db_path}' role tmp$r6469;
[WINDOWS] - and it causes 'set trusted role' to fail (SQLSTATE = 0P000 / Your attachment has no trusted role).
1. The 'CONNECT ...' operator, being specified without USER/PASSWORD clauses, will take in account parameters that were specified in the command line Because of this, we have to launch ISQL without using current credentials (which is True by default) - see 'credentials = False'.
of ISQL (confirmed by Alex, letter 03.04.2022 20:31). 2. One need to run ISQL with requirement do NOT establish connection to the test database because this will be done in the test script itself.
This means that it will use 'SYSDBA' / 'masterkey' rather than Windows trusted auth. This, in turn, leads that SYSDBA will be current user Otherwise we get 'Missing security context' *after* test finishes (the reason is unknown; instead, "Rolling back work." must be issued and redirected to STDERR).
when following is performed: To prevent such error, we have to specify 'connect_db = False' in db_factory() call.
connect '{THIS_COMPUTER_NAME}:{act.db.db_path}' role tmp$r6469; Checked on 4.0.1 Release, 5.0.0.467.
- and it causes 'set trusted role' to fail (SQLSTATE = 0P000 / Your attachment has no trusted role).
Because of this, we have to launch ISQL without using current credentials (which is True by default) - see 'credentials = False'. [02.08.2024] pzotov
2. One need to run ISQL with requirement do NOT establish connection to the test database because this will be done in the test script itself. One need to check for admin rights of current OS user (noted by Dimitry Sibiryakov).
Otherwise we get 'Missing security context' *after* test finishes (the reason is unknown; instead, "Rolling back work." must be issued and redirected to STDERR). ISQL output must be checked for matching to expected before trace log (see func run_script()).
To prevent such error, we have to specify 'connect_db = False' in db_factory() call. Replaced hard-coded name of role with 'f{tmp_role.name}' notation.
Checked on 4.0.1 Release, 5.0.0.467. Checked on Windows 6.0.0.406, 5.0.1.1469, 4.0.5.3139
JIRA: CORE-6469
JIRA: CORE-6469 FBTEST: bugs.core_6469
FBTEST: bugs.core_6469 """
"""
import os
import os import ctypes
import pytest import pytest
import re import re
import socket import socket
import getpass import getpass
from pathlib import Path from pathlib import Path
from firebird.qa import * from firebird.qa import *
import time import time
try: try:
del os.environ["ISC_USER"] del os.environ["ISC_USER"]
except KeyError as e: except KeyError as e:
pass pass
db = db_factory() db = db_factory()
act = python_act('db') act = python_act('db')
test_role = role_factory('db', name='TMP$R6469') tmp_role = role_factory('db', name='TMP$R6469')
tmp_file = temp_file('c6469_tmp.sql') tmp_file = temp_file('c6469_tmp.sql')
################################ ################################
### W I N D O W S ### ### W I N D O W S ###
################################ ################################
# version: 4.0 - Windows # version: 4.0 - Windows
expected_stdout_win = """ trace_win = ['log_initfini = false',
alter session reset 'log_statement_finish = true',
set session idle timeout 1800 second 'log_errors = true',
set statement timeout 190 second 'time_threshold = 0',
set bind of decfloat to double precision ]
set decfloat round ceiling
set decfloat traps to division_by_zero patterns_win = [re.compile('alter session reset', re.IGNORECASE),
set time zone 'america/sao_paulo' re.compile('set session idle timeout', re.IGNORECASE),
set role tmp$r6469 re.compile('set statement timeout', re.IGNORECASE),
set trusted role re.compile('set bind of decfloat to double precision', re.IGNORECASE),
""" re.compile('set decfloat round ceiling', re.IGNORECASE),
re.compile('set decfloat traps to Division_by_zero', re.IGNORECASE),
trace_win = ['log_initfini = false', re.compile('set time zone', re.IGNORECASE),
'log_statement_finish = true', re.compile('set role', re.IGNORECASE),
'log_errors = true', re.compile('set trusted role', re.IGNORECASE)]
'time_threshold = 0',
] #----------------------------------------------------------
patterns_win = [re.compile('alter session reset', re.IGNORECASE), def is_admin():
re.compile('set session idle timeout', re.IGNORECASE), # https://serverfault.com/questions/29659/crossplatform-way-to-check-admin-rights-in-python-script
re.compile('set statement timeout', re.IGNORECASE), # Checked on Windows 10.
re.compile('set bind of decfloat to double precision', re.IGNORECASE), try:
re.compile('set decfloat round ceiling', re.IGNORECASE), is_admin = os.getuid() == 0
re.compile('set decfloat traps to Division_by_zero', re.IGNORECASE), except AttributeError:
re.compile('set time zone', re.IGNORECASE), is_admin = ctypes.windll.shell32.IsUserAnAdmin()
re.compile('set role', re.IGNORECASE),
re.compile('set trusted role', re.IGNORECASE)] return is_admin
def run_script(act: Action, tmp_file: Path): #----------------------------------------------------------
#__tracebackhide__ = True
THIS_COMPUTER_NAME = socket.gethostname() def run_script(act: Action, tmp_role: Role, tmp_file: Path):
CURRENT_WIN_ADMIN = getpass.getuser() #__tracebackhide__ = True
script = f""" THIS_COMPUTER_NAME = socket.gethostname()
set bail on; CURRENT_WIN_ADMIN = getpass.getuser()
set list on; script = f"""
set echo on; set bail on;
connect '{act.db.dsn}' user '{act.db.user}' password '{act.db.password}'; set list on;
grant tmp$r6469 to "{THIS_COMPUTER_NAME}\\{CURRENT_WIN_ADMIN}"; -- set echo on;
commit; connect '{act.db.dsn}' user '{act.db.user}' password '{act.db.password}';
grant {tmp_role.name} to "{THIS_COMPUTER_NAME}\\{CURRENT_WIN_ADMIN}";
-- We have to use here "create mapping trusted_auth ... from any user to user" otherwise get commit;
-- Statement failed, SQLSTATE = 28000 /Missing security context for C:\\FBTESTING\\QA\\MISC\\C5887.FDB
-- on connect statement which specifies COMPUTERNAME:USERNAME instead path to DB: -- We have to use here "create mapping trusted_auth ... from any user to user" otherwise get
create or alter mapping trusted_auth using plugin win_sspi from any user to user; -- Statement failed, SQLSTATE = 28000 /Missing security context for C:\\FBTESTING\\QA\\MISC\\C5887.FDB
-- on connect statement which specifies COMPUTERNAME:USERNAME instead path to DB:
-- We have to use here "create mapping win_admins ... DOMAIN_ANY_RID_ADMINS" otherwise get create or alter mapping trusted_auth using plugin win_sspi from any user to user;
-- Statement failed, SQLSTATE = 0P000 / Your attachment has no trusted role
create or alter mapping win_admins using plugin win_sspi from predefined_group domain_any_rid_admins to role tmp$r6469; -- We have to use here "create mapping win_admins ... DOMAIN_ANY_RID_ADMINS" otherwise get
commit; -- Statement failed, SQLSTATE = 0P000 / Your attachment has no trusted role
create or alter mapping win_admins using plugin win_sspi from predefined_group domain_any_rid_admins to role {tmp_role.name};
-- We have to GRANT ROLE, even to SYSDBA. Otherwise: commit;
-- Statement failed, SQLSTATE = 0P000
-- Role TMP$R6469 is invalid or unavailable -- We have to GRANT ROLE, even to SYSDBA. Otherwise:
grant TMP$R6469 to sysdba; -- Statement failed, SQLSTATE = 0P000
commit; -- Role ... is invalid or unavailable
show role; grant {tmp_role.name} to sysdba;
show grants; commit;
show mapping; --show role;
--show grants;
set autoddl off; --show mapping;
commit;
set autoddl off;
-- Following management statements are taken from commit;
-- doc/sql.extensions/README.management_statements_psql.md:
-- ######################################################## -- Following management statements are taken from
alter session reset; -- doc/sql.extensions/README.management_statements_psql.md:
set session idle timeout 1800 second; -- ########################################################
set statement timeout 190 second; alter session reset;
set bind of decfloat to double precision; set session idle timeout 1800 second;
set decfloat round ceiling; set statement timeout 190 second;
set decfloat traps to Division_by_zero; set bind of decfloat to double precision;
set time zone 'America/Sao_Paulo'; set decfloat round ceiling;
set role tmp$r6469; set decfloat traps to Division_by_zero;
commit; set time zone 'America/Sao_Paulo';
set role {tmp_role.name};
connect '{THIS_COMPUTER_NAME}:{act.db.db_path}' role tmp$r6469; commit;
select mon$user,mon$role,mon$auth_method from mon$attachments where mon$attachment_id = current_connection; connect '{THIS_COMPUTER_NAME}:{act.db.db_path}' role {tmp_role.name};
commit;
select mon$user,mon$role,mon$auth_method from mon$attachments where mon$attachment_id = current_connection;
set trusted role; commit;
commit;
set trusted role;
connect '{act.db.dsn}' user {act.db.user} password '{act.db.password}'; commit;
drop mapping trusted_auth;
drop mapping win_admins; connect '{act.db.dsn}' user {act.db.user} password '{act.db.password}';
commit; drop mapping trusted_auth;
""" drop mapping win_admins;
tmp_file.write_text(script) commit;
"""
act.isql(switches=['-n', '-q'], input_file = tmp_file, connect_db = False, credentials = False) tmp_file.write_text(script)
@pytest.mark.trace act.expected_stdout = f"""
@pytest.mark.version('>=4.0') MON$USER {THIS_COMPUTER_NAME}\\{CURRENT_WIN_ADMIN.upper()}
@pytest.mark.platform('Windows') MON$ROLE {tmp_role.name.upper()}
def test_1(act: Action, test_role: Role, tmp_file: Path, capsys): MON$AUTH_METHOD Mapped from Win_Sspi
with act.trace(db_events=trace_win): """
run_script(act, tmp_file) act.isql(switches=['-n', '-q'], input_file = tmp_file, connect_db = False, credentials = False, combine_output = True)
assert act.clean_stdout == act.clean_expected_stdout
# process trace act.reset()
for line in act.trace_log:
if line.split(): #----------------------------------------------------------
if act.match_any(line, patterns_win):
print(' '.join(line.split()).lower()) @pytest.mark.trace
# Check @pytest.mark.version('>=4.0')
act.expected_stdout = expected_stdout_win @pytest.mark.platform('Windows')
act.stdout = capsys.readouterr().out def test_1(act: Action, tmp_role: Role, tmp_file: Path, capsys):
assert act.clean_stdout == act.clean_expected_stdout
if not is_admin():
pytest.skip("Current OS user must have admin rights.")
################################ with act.trace(db_events=trace_win):
### L I N U X ### run_script(act, tmp_role, tmp_file)
################################
# version: 4.0 - Linux # process trace
for line in act.trace_log:
expected_stdout_lin = """ if line.split():
alter session reset if act.match_any(line, patterns_win):
set session idle timeout 1800 second print(' '.join(line.split()).lower())
set statement timeout 190 second
set bind of decfloat to double precision expected_stdout_win = f"""
set decfloat round ceiling alter session reset
set decfloat traps to division_by_zero set session idle timeout 1800 second
set time zone 'america/sao_paulo' set statement timeout 190 second
set role tmp$r6469 set bind of decfloat to double precision
""" set decfloat round ceiling
set decfloat traps to division_by_zero
test_script_lin = """ set time zone 'america/sao_paulo'
set bail on; set role {tmp_role.name.lower()}
set list on; set trusted role
"""
-- We have to GRANT ROLE, even to SYSDBA. Otherwise:
-- Statement failed, SQLSTATE = 0P000 act.expected_stdout = expected_stdout_win
-- Role TMP$R6469 is invalid or unavailable act.stdout = capsys.readouterr().out
grant TMP$R6469 to sysdba; assert act.clean_stdout == act.clean_expected_stdout
commit;
select current_user as who_ami, current_role as whats_my_role from rdb$database;
set autoddl off; ################################
commit; ### L I N U X ###
################################
-- Following management statements are taken from # version: 4.0 - Linux
-- doc/sql.extensions/README.management_statements_psql.md:
-- ######################################################## trace_lin = ['log_initfini = false',
set echo on; 'log_connections = true',
alter session reset; 'log_statement_finish = true',
set session idle timeout 1800 second; 'log_errors = true',
set statement timeout 190 second; 'time_threshold = 0',
set bind of decfloat to double precision; ]
set decfloat round ceiling;
set decfloat traps to Division_by_zero; patterns_lin = [re.compile('alter session reset', re.IGNORECASE),
set time zone 'America/Sao_Paulo'; re.compile('set session idle timeout', re.IGNORECASE),
set role tmp$r6469; re.compile('set statement timeout', re.IGNORECASE),
commit; re.compile('set bind of decfloat to double precision', re.IGNORECASE),
select 'Completed' as msg from rdb$database; re.compile('set decfloat round ceiling', re.IGNORECASE),
""" re.compile('set decfloat traps to Division_by_zero', re.IGNORECASE),
re.compile('set time zone', re.IGNORECASE),
trace_lin = ['log_initfini = false', re.compile('set role', re.IGNORECASE)]
'log_connections = true',
'log_statement_finish = true', @pytest.mark.version('>=4.0')
'log_errors = true', @pytest.mark.platform('Linux')
'time_threshold = 0', def test_2(act: Action, tmp_role: Role, capsys):
]
expected_stdout_nix = f"""
patterns_lin = [re.compile('alter session reset', re.IGNORECASE), alter session reset
re.compile('set session idle timeout', re.IGNORECASE), set session idle timeout 1800 second
re.compile('set statement timeout', re.IGNORECASE), set statement timeout 190 second
re.compile('set bind of decfloat to double precision', re.IGNORECASE), set bind of decfloat to double precision
re.compile('set decfloat round ceiling', re.IGNORECASE), set decfloat round ceiling
re.compile('set decfloat traps to Division_by_zero', re.IGNORECASE), set decfloat traps to division_by_zero
re.compile('set time zone', re.IGNORECASE), set time zone 'america/sao_paulo'
re.compile('set role', re.IGNORECASE)] set role {tmp_role.name.lower()}
"""
@pytest.mark.version('>=4.0')
@pytest.mark.platform('Linux') test_script_nix = f"""
def test_2(act: Action, test_role: Role, capsys): set bail on;
with act.trace(db_events=trace_lin): set list on;
act.isql(switches=['-n', '-q'], input = test_script_lin)
-- We have to GRANT ROLE, even to SYSDBA. Otherwise:
# process trace -- Statement failed, SQLSTATE = 0P000
for line in act.trace_log: -- Role ... is invalid or unavailable
if line.split(): grant {tmp_role.name} to sysdba;
if act.match_any(line, patterns_lin): commit;
print(' '.join(line.split()).lower())
# Check select current_user as who_ami, current_role as whats_my_role from rdb$database;
act.expected_stdout = expected_stdout_lin set autoddl off;
act.stdout = capsys.readouterr().out commit;
assert act.clean_stdout == act.clean_expected_stdout
-- Following management statements are taken from
-- doc/sql.extensions/README.management_statements_psql.md:
-- ########################################################
set echo on;
alter session reset;
set session idle timeout 1800 second;
set statement timeout 190 second;
set bind of decfloat to double precision;
set decfloat round ceiling;
set decfloat traps to Division_by_zero;
set time zone 'America/Sao_Paulo';
set role {tmp_role.name};
commit;
select 'Completed' as msg from rdb$database;
"""
with act.trace(db_events=trace_lin):
act.isql(switches=['-n', '-q'], input = test_script_nix)
# process trace
for line in act.trace_log:
if line.split():
if act.match_any(line, patterns_lin):
print(' '.join(line.split()).lower())
# Check
act.expected_stdout = expected_stdout_nix
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout