Merge pull request #19017 from MyroTk/tfs_rbac_alter_fetch_fix_and_new_tests

Enabling TestFlows RBAC tests and adding new tests for SYSTEM privileges.
This commit is contained in:
alexey-milovidov 2021-01-15 17:31:45 +03:00 committed by GitHub
commit 2cdc5319c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 13706 additions and 11084 deletions

View File

@ -25,6 +25,8 @@ issue_17147 = "https://github.com/ClickHouse/ClickHouse/issues/17147"
issue_17653 = "https://github.com/ClickHouse/ClickHouse/issues/17653"
issue_17655 = "https://github.com/ClickHouse/ClickHouse/issues/17655"
issue_17766 = "https://github.com/ClickHouse/ClickHouse/issues/17766"
issue_18110 = "https://github.com/ClickHouse/ClickHouse/issues/18110"
issue_18206 = "https://github.com/ClickHouse/ClickHouse/issues/18206"
xfails = {
"syntax/show create quota/I show create quota current":
@ -113,8 +115,22 @@ xfails = {
[(Fail, issue_17147)],
"privileges/show dictionaries/:/check privilege/:/exists/EXISTS with privilege":
[(Fail, issue_17655)],
"privileges/public tables/query log":
[(Fail, issue_17766)]
"privileges/public tables/sensitive tables":
[(Fail, issue_18110)],
"privileges/system merges/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
"privileges/system ttl merges/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
"privileges/system moves/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
"privileges/system sends/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
"privileges/system fetches/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
"privileges/system restart replica/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
"privileges/system replication queues/:/:/:/:/SYSTEM:":
[(Fail, issue_18206)],
}
xflags = {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to grant role with `ADMIN OPTION` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(test=grant_role, flags=TE)(grant_target_name=user_name, user_name=user_name)
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to grant role with `ADMIN OPTION` privilege granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(test=grant_role, flags=TE)(grant_target_name=role_name, user_name=user_name)
@TestSuite
def grant_role(self, grant_target_name, user_name, node=None):
"""Check that user is able to execute to grant roles if and only if they have role with `ADMIN OPTION`.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("Grant role without privilege"):
grant_role_name = f"grant_role_{getuid()}"
target_user_name = f"target_user_{getuid()}"
with user(node, target_user_name), role(node, grant_role_name):
with When("I check the user can't grant a role"):
node.query(f"GRANT {grant_role_name} TO {target_user_name}", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("Grant role with privilege"):
grant_role_name = f"grant_role_{getuid()}"
target_user_name = f"target_user_{getuid()}"
with user(node, target_user_name), role(node, grant_role_name):
with When(f"I grant ADMIN OPTION"):
node.query(f"GRANT {grant_role_name} TO {grant_target_name} WITH ADMIN OPTION")
with Then("I check the user can grant a role"):
node.query(f"GRANT {grant_role_name} TO {target_user_name}", settings = [("user", f"{user_name}")])
with Scenario("Grant role on cluster"):
grant_role_name = f"grant_role_{getuid()}"
target_user_name = f"target_user_{getuid()}"
try:
with Given("I have a role on a cluster"):
node.query(f"CREATE ROLE {grant_role_name} ON CLUSTER sharded_cluster")
with And("I have a user on a cluster"):
node.query(f"CREATE USER {target_user_name} ON CLUSTER sharded_cluster")
with When("I grant ADMIN OPTION privilege"):
node.query(f"GRANT {grant_role_name} TO {grant_target_name} WITH ADMIN OPTION")
with Then("I check the user can grant a role"):
node.query(f"GRANT {grant_role_name} TO {target_user_name} ON CLUSTER sharded_cluster", settings = [("user", f"{user_name}")])
finally:
with Finally("I drop the user"):
node.query(f"DROP ROLE IF EXISTS {grant_role_name} ON CLUSTER sharded_cluster")
with Scenario("Grant role with revoked privilege"):
grant_role_name = f"grant_role_{getuid()}"
target_user_name = f"target_user_{getuid()}"
with user(node, target_user_name), role(node, grant_role_name):
with When(f"I grant ADMIN OPTION"):
node.query(f"GRANT {grant_role_name} TO {grant_target_name} WITH ADMIN OPTION")
with And(f"I revoke ADMIN OPTION"):
node.query(f"REVOKE {grant_role_name} FROM {grant_target_name}")
with Then("I check the user cannot grant a role"):
node.query(f"GRANT {grant_role_name} TO {target_user_name}", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestFeature
@Name("admin option")
@Requirements(
RQ_SRS_006_RBAC_Privileges_AdminOption("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of ADMIN OPTION.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -24,7 +24,7 @@ aliases = {
"RENAME COLUMN" : ["ALTER RENAME COLUMN", "RENAME COLUMN"],
"COMMENT COLUMN": ["ALTER COMMENT COLUMN", "COMMENT COLUMN"],
"DROP COLUMN": ["ALTER DROP COLUMN", "DROP COLUMN"],
"ALTER COLUMN" : ["ALTER COLUMN"], #super-privilege
"ALTER COLUMN" : ["ALTER COLUMN", "ALL"], #super-privilege
}
# extra permutation is for 'ALTER COLUMN' super-privilege
@ -675,7 +675,8 @@ def scenario_parallelization(self, table_type, permutation):
@TestFeature
@Requirements(
RQ_SRS_006_RBAC_Privileges_AlterColumn("1.0"),
RQ_SRS_006_RBAC_Privileges_AlterColumn_TableEngines("1.0")
RQ_SRS_006_RBAC_Privileges_AlterColumn_TableEngines("1.0"),
RQ_SRS_006_RBAC_Privileges_All("1.0")
)
@Examples("table_type", [
(key,) for key in table_types.keys()

View File

@ -17,7 +17,7 @@ subprivileges = {
aliases = {
"ADD CONSTRAINT" : ["ALTER ADD CONSTRAINT", "ADD CONSTRAINT"],
"DROP CONSTRAINT": ["ALTER DROP CONSTRAINT", "DROP CONSTRAINT"],
"ALTER CONSTRAINT": ["ALTER CONSTRAINT", "CONSTRAINT"] # super-privilege
"ALTER CONSTRAINT": ["ALTER CONSTRAINT", "CONSTRAINT", "ALL"] # super-privilege
}
# Extra permutation is for 'ALTER CONSTRAINT' super-privilege
@ -274,7 +274,8 @@ def user_with_privileges_on_cluster(self, table_type, node=None):
@TestFeature
@Requirements(
RQ_SRS_006_RBAC_Privileges_AlterConstraint("1.0"),
RQ_SRS_006_RBAC_Privileges_AlterConstraint_TableEngines("1.0")
RQ_SRS_006_RBAC_Privileges_AlterConstraint_TableEngines("1.0"),
RQ_SRS_006_RBAC_Privileges_All("1.0")
)
@Examples("table_type", [
(key,) for key in table_types.keys()

View File

@ -7,7 +7,7 @@ from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
aliases = {"ALTER DELETE", "DELETE"}
aliases = {"ALTER DELETE", "DELETE", "ALL"}
@TestSuite
def privilege_granted_directly_or_via_role(self, table_type, privilege, node=None):
@ -65,6 +65,7 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
@TestFeature
@Requirements(
RQ_SRS_006_RBAC_Privileges_AlterDelete("1.0"),
RQ_SRS_006_RBAC_Privileges_All("1.0")
)
@Examples("table_type", [
(key,) for key in table_types.keys()

View File

@ -7,7 +7,7 @@ from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
aliases = {"ALTER FETCH PARTITION", "FETCH PARTITION"}
aliases = {"ALTER FETCH PARTITION", "FETCH PARTITION", "ALL"}
@TestSuite
def privilege_granted_directly_or_via_role(self, table_type, privilege, node=None):
@ -44,7 +44,7 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
with table(node, table_name, table_type):
with When("I attempt to fetch a partition without privilege"):
node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/tables/{{shard}}/{table_name}'", settings = [("user", user_name)],
node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/'", settings = [("user", user_name)],
exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
@ -55,7 +55,7 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}")
with Then("I attempt to fetch a partition"):
node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/tables/{{shard}}/{table_name}'", settings = [("user", user_name)],
node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/'", settings = [("user", user_name)],
exitcode=231, message="DB::Exception: No node")
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
@ -69,12 +69,13 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
node.query(f"REVOKE {privilege} ON {table_name} FROM {grant_target_name}")
with Then("I attempt to fetch a partition"):
node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/tables/{{shard}}/{table_name}'", settings = [("user", user_name)],
node.query(f"ALTER TABLE {table_name} FETCH PARTITION 1 FROM '/clickhouse/'", settings = [("user", user_name)],
exitcode=exitcode, message=message)
@TestFeature
@Requirements(
RQ_SRS_006_RBAC_Privileges_AlterFetch("1.0"),
RQ_SRS_006_RBAC_Privileges_All("1.0")
)
@Examples("table_type",[
("ReplicatedMergeTree-sharded_cluster",),

View File

@ -7,7 +7,7 @@ from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
aliases = {"ALTER FREEZE PARTITION", "FREEZE PARTITION"}
aliases = {"ALTER FREEZE PARTITION", "FREEZE PARTITION", "ALL"}
@TestSuite
def privilege_granted_directly_or_via_role(self, table_type, privilege, node=None):
@ -39,6 +39,7 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
table_name = f"merge_tree_{getuid()}"
with table(node, table_name, table_type):
with When("I attempt to freeze partitions without privilege"):
node.query(f"ALTER TABLE {table_name} FREEZE", settings = [("user", user_name)],
exitcode=exitcode, message=message)
@ -46,18 +47,22 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
table_name = f"merge_tree_{getuid()}"
with table(node, table_name, table_type):
with When("I grant the freeze privilege"):
node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}")
with Then("I attempt to freeze partitions"):
node.query(f"ALTER TABLE {table_name} FREEZE", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
table_name = f"merge_tree_{getuid()}"
with table(node, table_name, table_type):
with When("I grant the freeze privilege"):
node.query(f"GRANT {privilege} ON {table_name} TO {grant_target_name}")
with And("I revoke the freeze privilege"):
node.query(f"REVOKE {privilege} ON {table_name} FROM {grant_target_name}")
with Then("I attempt to freeze partitions"):
node.query(f"ALTER TABLE {table_name} FREEZE", settings = [("user", user_name)],
exitcode=exitcode, message=message)
@ -65,6 +70,7 @@ def privilege_check(grant_target_name, user_name, table_type, privilege, node=No
@TestFeature
@Requirements(
RQ_SRS_006_RBAC_Privileges_AlterFreeze("1.0"),
RQ_SRS_006_RBAC_Privileges_All("1.0")
)
@Examples("table_type", [
(key,) for key in table_types.keys()

View File

@ -36,8 +36,9 @@ def privilege_check(grant_target_name, user_name, node=None):
table_name = f"table_{getuid()}"
try:
with When("I attempt to attach a table without privilege"):
node.query(f"ATTACH TABLE {table_name} (x Int8) ENGINE = Memory", settings = [("user", user_name)],
node.query(f"ATTACH TABLE {table_name}", settings = [("user", user_name)],
exitcode=exitcode, message=message)
finally:
@ -48,12 +49,12 @@ def privilege_check(grant_target_name, user_name, node=None):
table_name = f"table_{getuid()}"
try:
with When("I grant create table privilege"):
with When("I grant create table privilege"):
node.query(f"GRANT CREATE TABLE ON *.* TO {grant_target_name}")
with Then("I attempt to attach a table"):
node.query(f"ATTACH TABLE {table_name} (x Int8) ENGINE = Memory", settings = [("user", user_name)],
exitcode=80, message="DB::Exception: Incorrect ATTACH TABLE query")
node.query(f"ATTACH TABLE {table_name}", settings = [("user", user_name)],
exitcode=134, message=f"DB::Exception: Table `{table_name}` doesn't exist.")
finally:
with Finally("I drop the table"):
@ -70,7 +71,7 @@ def privilege_check(grant_target_name, user_name, node=None):
node.query(f"REVOKE CREATE TABLE ON *.* FROM {grant_target_name}")
with Then("I attempt to attach a table"):
node.query(f"ATTACH TABLE {table_name} (x Int8) ENGINE = Memory", settings = [("user", user_name)],
node.query(f"ATTACH TABLE {table_name}", settings = [("user", user_name)],
exitcode=exitcode, message=message)
finally:

View File

@ -706,7 +706,7 @@ def create_as_merge(self, node=None):
with When("I grant CREATE TABLE privilege to a user"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {user_name}")
with And("I grant SELECT privilege to a user to allow executing the table function merge()"):
with And("I grant SELECT privilege on the source table"):
node.query(f"GRANT SELECT ON {source_table_name} TO {user_name}")
with Then("I try to create a table as another table"):
@ -722,6 +722,8 @@ def create_as_merge(self, node=None):
)
@Name("create table")
def feature(self, stress=None, parallel=None, node="clickhouse1"):
"""Check the RBAC functionality of CREATE TABLE.
"""
self.context.node = self.context.cluster.node(node)
if stress is not None:

View File

@ -45,9 +45,9 @@ def privilege_check(grant_target_name, user_name, node=None):
finally:
with Finally("I reattach the view as a table", flags=TE):
node.query(f"ATTACH TABLE IF NOT EXISTS {view_name}")
node.query(f"ATTACH VIEW IF NOT EXISTS {view_name} AS SELECT 1")
with And("I drop the view", flags=TE):
node.query(f"DROP TABLE IF EXISTS {view_name}")
node.query(f"DROP VIEW IF EXISTS {view_name}")
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
view_name = f"view_{getuid()}"
@ -64,9 +64,9 @@ def privilege_check(grant_target_name, user_name, node=None):
finally:
with Finally("I reattach the view as a table", flags=TE):
node.query(f"ATTACH TABLE IF NOT EXISTS {view_name}")
node.query(f"ATTACH VIEW IF NOT EXISTS {view_name} AS SELECT 1")
with And("I drop the table", flags=TE):
node.query(f"DROP TABLE IF EXISTS {view_name}")
node.query(f"DROP VIEW IF EXISTS {view_name}")
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
view_name = f"view_{getuid()}"
@ -87,9 +87,9 @@ def privilege_check(grant_target_name, user_name, node=None):
finally:
with Finally("I reattach the view as a table", flags=TE):
node.query(f"ATTACH TABLE IF NOT EXISTS {view_name}")
node.query(f"ATTACH VIEW IF NOT EXISTS {view_name} AS SELECT 1")
with And("I drop the view", flags=TE):
node.query(f"DROP TABLE IF EXISTS {view_name}")
node.query(f"DROP VIEW IF EXISTS {view_name}")
@TestFeature
@Requirements(

View File

@ -0,0 +1,646 @@
import os
from contextlib import contextmanager
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@contextmanager
def dict_setup(node, table_name, dict_name, type="UInt64"):
"""Setup and teardown of table and dictionary needed for the tests.
"""
try:
with Given("I have a table"):
node.query(f"CREATE TABLE {table_name} (x UInt64, y UInt64, z {type}) ENGINE = Memory")
with And("I have a dictionary"):
node.query(f"CREATE DICTIONARY {dict_name} (x UInt64 HIERARCHICAL IS_OBJECT_ID, y UInt64 HIERARCHICAL, z {type}) PRIMARY KEY x LAYOUT(FLAT()) SOURCE(CLICKHOUSE(host 'localhost' port 9000 user 'default' password '' db 'default' table '{table_name}')) LIFETIME(0)")
yield
finally:
with Finally("I drop the table", flags=TE):
node.query(f"DROP TABLE IF EXISTS {table_name}")
with And("I drop the dictionary", flags=TE):
node.query(f"DROP DICTIONARY IF EXISTS {dict_name}")
@TestSuite
def dictGet_granted_directly(self, node=None):
"""Run dictGet checks with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictGet_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictGet_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictGet_granted_via_role(self, node=None):
"""Run dictGet checks with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictGet_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictGet_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("dictGet",),
("dictHas",),
("dictGetHierarchy",),
("dictIsIn",),
])
@Requirements(
RQ_SRS_006_RBAC_dictGet_RequiredPrivilege("1.0")
)
def dictGet_check(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is able to execute `dictGet` if and only if they have the necessary privileges.
"""
if node is None:
node = self.context.node
exitcode, message = errors.not_enough_privileges(name=f"{user_name}")
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I attempt to dictGet without privilege"):
node.query(f"SELECT dictGet ({dict_name},'y',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When(f"I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with Then("I attempt to dictGet with privilege"):
node.query(f"SELECT dictGet ({dict_name},'y',toUInt64(1))", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with And("I revoke privilege"):
node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}")
with When("I attempt to dictGet without privilege"):
node.query(f"SELECT dictGet ({dict_name},'y',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
@TestSuite
def dictGetOrDefault_granted_directly(self, node=None):
"""Run dictGetOrDefault checks with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictGetOrDefault_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictGetOrDefault_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictGetOrDefault_granted_via_role(self, node=None):
"""Run dictGetOrDefault checks with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictGetOrDefault_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictGetOrDefault_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("dictGet",),
("dictHas",),
("dictGetHierarchy",),
("dictIsIn",),
])
@Requirements(
RQ_SRS_006_RBAC_dictGet_OrDefault_RequiredPrivilege("1.0")
)
def dictGetOrDefault_check(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is able to execute `dictGetOrDefault` if and only if they have the necessary privileges.
"""
if node is None:
node = self.context.node
exitcode, message = errors.not_enough_privileges(name=f"{user_name}")
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I attempt to dictGetOrDefault without privilege"):
node.query(f"SELECT dictGetOrDefault ({dict_name},'y',toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When(f"I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with Then("I attempt to dictGetOrDefault with privilege"):
node.query(f"SELECT dictGetOrDefault ({dict_name},'y',toUInt64(1),toUInt64(1))", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with And("I revoke privilege"):
node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}")
with When("I attempt to dictGetOrDefault without privilege"):
node.query(f"SELECT dictGetOrDefault ({dict_name},'y',toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
@TestSuite
def dictHas_granted_directly(self, node=None):
"""Run dictHas checks with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictHas_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictHas_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictHas_granted_via_role(self, node=None):
"""Run checks with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictHas_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictHas_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("dictGet",),
("dictHas",),
("dictGetHierarchy",),
("dictIsIn",),
])
@Requirements(
RQ_SRS_006_RBAC_dictHas_RequiredPrivilege("1.0")
)
def dictHas_check(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is able to execute `dictHas` if and only if they have the necessary privileges.
"""
if node is None:
node = self.context.node
exitcode, message = errors.not_enough_privileges(name=f"{user_name}")
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I attempt to dictHas without privilege"):
node.query(f"SELECT dictHas({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with Then("I attempt to dictHas with privilege"):
node.query(f"SELECT dictHas({dict_name},toUInt64(1))", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with And("I revoke privilege"):
node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}")
with When("I attempt to dictHas without privilege"):
node.query(f"SELECT dictHas({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
@TestSuite
def dictGetHierarchy_granted_directly(self, node=None):
"""Run dictGetHierarchy checks with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictGetHierarchy_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictGetHierarchy_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictGetHierarchy_granted_via_role(self, node=None):
"""Run checks with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictGetHierarchy_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictGetHierarchy_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("dictGet",),
("dictHas",),
("dictGetHierarchy",),
("dictIsIn",),
])
@Requirements(
RQ_SRS_006_RBAC_dictGetHierarchy_RequiredPrivilege("1.0")
)
def dictGetHierarchy_check(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is able to execute `dictGetHierarchy` if and only if they have the necessary privileges.
"""
if node is None:
node = self.context.node
exitcode, message = errors.not_enough_privileges(name=f"{user_name}")
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I attempt to dictGetHierarchy without privilege"):
node.query(f"SELECT dictGetHierarchy({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with Then("I attempt to dictGetHierarchy with privilege"):
node.query(f"SELECT dictGetHierarchy({dict_name},toUInt64(1))", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with And("I revoke privilege"):
node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}")
with When("I attempt to dictGetHierarchy without privilege"):
node.query(f"SELECT dictGetHierarchy({dict_name},toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
@TestSuite
def dictIsIn_granted_directly(self, node=None):
"""Run dictIsIn checks with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictIsIn_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictIsIn_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictIsIn_granted_via_role(self, node=None):
"""Run checks with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictIsIn_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictIsIn_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("dictGet",),
("dictHas",),
("dictGetHierarchy",),
("dictIsIn",),
])
@Requirements(
RQ_SRS_006_RBAC_dictIsIn_RequiredPrivilege("1.0")
)
def dictIsIn_check(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is able to execute `dictIsIn` if and only if they have the necessary privileges.
"""
if node is None:
node = self.context.node
exitcode, message = errors.not_enough_privileges(name=f"{user_name}")
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I attempt to dictIsIn without privilege"):
node.query(f"SELECT dictIsIn({dict_name},toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with Then("I attempt to dictIsIn with privilege"):
node.query(f"SELECT dictIsIn({dict_name},toUInt64(1),toUInt64(1))", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with And("I revoke privilege"):
node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}")
with When("I attempt to dictIsIn without privilege"):
node.query(f"SELECT dictIsIn({dict_name},toUInt64(1),toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
@TestSuite
@Examples("type",[
("Int8",),
("Int16",),
("Int32",),
("Int64",),
("UInt8",),
("UInt16",),
("UInt32",),
("UInt64",),
("Float32",),
("Float64",),
("Date",),
("DateTime",),
("UUID",),
("String",),
])
def dictGetType_granted_directly(self, type, node=None):
"""Run checks on dictGet with a type specified with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictGetType_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name type", [
tuple(list(row)+[user_name,user_name,type]) for row in dictGetType_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
@Examples("type",[
("Int8",),
("Int16",),
("Int32",),
("Int64",),
("UInt8",),
("UInt16",),
("UInt32",),
("UInt64",),
("Float32",),
("Float64",),
("Date",),
("DateTime",),
("UUID",),
("String",),
])
def dictGetType_granted_via_role(self, type, node=None):
"""Run checks on dictGet with a type specified with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictGetType_check, setup=instrument_clickhouse_server_log,
examples=Examples("privilege grant_target_name user_name type", [
tuple(list(row)+[role_name,user_name,type]) for row in dictGetType_check.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("dictGet",),
("dictHas",),
("dictGetHierarchy",),
("dictIsIn",),
])
@Requirements(
RQ_SRS_006_RBAC_dictGet_Type_RequiredPrivilege("1.0")
)
def dictGetType_check(self, privilege, grant_target_name, user_name, type, node=None):
"""Check that user is able to execute `dictGet` if and only if they have the necessary privileges.
"""
if node is None:
node = self.context.node
exitcode, message = errors.not_enough_privileges(name=f"{user_name}")
with Scenario("user without privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name, type):
with When("I attempt to dictGet without privilege"):
node.query(f"SELECT dictGet{type}({dict_name},'z',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
with Scenario("user with privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name, type):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with Then("I attempt to dictGet with privilege"):
node.query(f"SELECT dictGet{type}({dict_name},'z',toUInt64(1))", settings = [("user", user_name)])
with Scenario("user with revoked privilege", setup=instrument_clickhouse_server_log):
dict_name = f"dict_{getuid()}"
with dict_setup(node, table_name, dict_name, type):
with When("I grant privilege"):
node.query(f"GRANT {privilege} ON {dict_name} TO {grant_target_name}")
with And("I revoke privilege"):
node.query(f"REVOKE {privilege} ON {dict_name} FROM {grant_target_name}")
with When("I attempt to dictGet without privilege"):
node.query(f"SELECT dictGet{type}({dict_name},'z',toUInt64(1))", settings = [("user", user_name)], exitcode=exitcode, message=message)
@TestFeature
@Requirements(
RQ_SRS_006_RBAC_dictGet_Privilege("1.0")
)
@Name("dictGet")
def feature(self, node="clickhouse1", stress=None, parallel=None):
"""Check the RBAC functionality of dictGet.
"""
self.context.node = self.context.cluster.node(node)
if parallel is not None:
self.context.parallel = parallel
if stress is not None:
self.context.stress = stress
pool = Pool(20)
try:
tasks = []
try:
run_scenario(pool, tasks, Suite(test=dictGet_granted_directly))
run_scenario(pool, tasks, Suite(test=dictGet_granted_via_role))
run_scenario(pool, tasks, Suite(test=dictGetOrDefault_granted_directly))
run_scenario(pool, tasks, Suite(test=dictGetOrDefault_granted_via_role))
run_scenario(pool, tasks, Suite(test=dictHas_granted_directly))
run_scenario(pool, tasks, Suite(test=dictHas_granted_via_role))
run_scenario(pool, tasks, Suite(test=dictGetHierarchy_granted_directly))
run_scenario(pool, tasks, Suite(test=dictGetHierarchy_granted_via_role))
run_scenario(pool, tasks, Suite(test=dictIsIn_granted_directly))
run_scenario(pool, tasks, Suite(test=dictIsIn_granted_via_role))
for example in dictGetType_granted_directly.examples:
type, = example
with Example(example):
run_scenario(pool, tasks, Suite(test=dictGetType_granted_directly),{"type" : type})
run_scenario(pool, tasks, Suite(test=dictGetType_granted_via_role),{"type" : type})
finally:
join(tasks)
finally:
pool.close()

View File

@ -61,7 +61,7 @@ def table(self, name, cluster=None, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Table_DistributedTable_Create("1.0"),
RQ_SRS_006_RBAC_DistributedTable_Create("1.0"),
)
def create(self):
"""Check the RBAC functionality of distributed table with CREATE.
@ -161,7 +161,7 @@ def create_with_privilege(self, user_name, grant_target_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Table_DistributedTable_Select("1.0"),
RQ_SRS_006_RBAC_DistributedTable_Select("1.0"),
)
def select(self):
"""Check the RBAC functionality of distributed table with SELECT.
@ -275,7 +275,7 @@ def select_with_privilege(self, user_name, grant_target_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Table_DistributedTable_Insert("1.0"),
RQ_SRS_006_RBAC_DistributedTable_Insert("1.0"),
)
def insert(self):
"""Check the RBAC functionality of distributed table with INSERT.
@ -389,7 +389,7 @@ def insert_with_privilege(self, user_name, grant_target_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Table_DistributedTable_SpecialTables("1.0"),
RQ_SRS_006_RBAC_DistributedTable_SpecialTables("1.0"),
)
def special_cases(self):
"""Check that the user is able to successfully execute queries on distributed tables using special tables,
@ -875,7 +875,7 @@ def insert_with_table_on_distributed_table(self, user_name, grant_target_name, n
" where one replica is on clickhouse1 and another on clickhouse2 accessed from clickhouse1")),
])
@Requirements(
RQ_SRS_006_RBAC_Table_DistributedTable_LocalUser("1.0")
RQ_SRS_006_RBAC_DistributedTable_LocalUser("1.0")
)
def local_user(self, cluster, node=None):
"""Check that a user that exists locally and not present on the remote nodes
@ -912,7 +912,7 @@ def local_user(self, cluster, node=None):
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Table_DistributedTable_SameUserDifferentNodesDifferentPrivileges("1.0")
RQ_SRS_006_RBAC_DistributedTable_SameUserDifferentNodesDifferentPrivileges("1.0")
)
def multiple_node_user(self, node=None):
"""Check that a user that exists on multiple nodes with different privileges on each is able to execute queries

View File

@ -7,7 +7,7 @@ from rbac.helper.common import *
def feature(self):
tasks = []
pool = Pool(16)
pool = Pool(10)
try:
try:
@ -21,6 +21,10 @@ def feature(self):
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.kill_query", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.kill_mutation", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.role_admin", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.dictGet", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.introspection", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.sources", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.admin_option", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_tables", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.show.show_dictionaries", "feature"), flags=TE), {})
@ -76,7 +80,22 @@ def feature(self):
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_dictionary", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_table", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.detach.detach_view", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.drop_cache", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.reload", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.flush", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.merges", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.moves", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.replication_queues", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.ttl_merges", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.restart_replica", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.sends", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.sync_replica", "feature"), flags=TE), {})
run_scenario(pool, tasks, Feature(test=load("rbac.tests.privileges.system.fetches", "feature"), flags=TE), {})
finally:
join(tasks)
finally:
pool.close()
Feature(test=load("rbac.tests.privileges.system.shutdown", "feature"), flags=TE)

View File

@ -96,7 +96,7 @@ def user_with_privilege_on_columns(self, table_type):
@TestOutline
@Requirements(
RQ_SRS_006_RBAC_Privileges_Insert_Column("1.0"),
RQ_SRS_006_RBAC_Insert_Column("1.0"),
)
@Examples("grant_columns revoke_columns insert_columns_fail insert_columns_pass data_fail data_pass", [
("d", "d", "x", "d", '\'woo\'', '\'2020-01-01\''),
@ -219,7 +219,7 @@ def role_with_privilege_on_columns(self, table_type):
@TestOutline
@Requirements(
RQ_SRS_006_RBAC_Privileges_Insert_Column("1.0"),
RQ_SRS_006_RBAC_Insert_Column("1.0"),
)
@Examples("grant_columns revoke_columns insert_columns_fail insert_columns_pass data_fail data_pass", [
("d", "d", "x", "d", '\'woo\'', '\'2020-01-01\''),
@ -264,7 +264,7 @@ def role_column_privileges(self, grant_columns, insert_columns_pass, data_fail,
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Insert_Cluster("1.0"),
RQ_SRS_006_RBAC_Insert_Cluster("1.0"),
)
def user_with_privilege_on_cluster(self, table_type, node=None):
"""Check that user is able or unable to insert into a table
@ -305,7 +305,7 @@ def user_with_privilege_on_cluster(self, table_type, node=None):
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Insert_Cluster("1.0"),
RQ_SRS_006_RBAC_Insert_Cluster("1.0"),
)
def role_with_privilege_on_cluster(self, table_type, node=None):
"""Check that user with role is able to insert into a table
@ -351,8 +351,8 @@ def role_with_privilege_on_cluster(self, table_type, node=None):
@TestOutline(Feature)
@Requirements(
RQ_SRS_006_RBAC_Privileges_Insert("1.0"),
RQ_SRS_006_RBAC_Privileges_Insert_TableEngines("1.0")
RQ_SRS_006_RBAC_Insert("1.0"),
RQ_SRS_006_RBAC_Insert_TableEngines("1.0")
)
@Examples("table_type", [
(key,) for key in table_types.keys()
@ -360,6 +360,8 @@ def role_with_privilege_on_cluster(self, table_type, node=None):
@Flags(TE)
@Name("insert")
def feature(self, table_type, parallel=None, stress=None, node="clickhouse1"):
"""Check the RBAC functionality of INSERT.
"""
self.context.node = self.context.cluster.node(node)
self.context.node1 = self.context.cluster.node("clickhouse1")

View File

@ -0,0 +1,285 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@contextmanager
def allow_introspection_functions(node):
setting = ("allow_introspection_functions", 1)
default_query_settings = None
try:
with Given("I add allow_introspection_functions to the default query settings"):
default_query_settings = getsattr(current().context, "default_query_settings", [])
default_query_settings.append(setting)
yield
finally:
with Finally("I remove allow_introspection_functions from the default query settings"):
if default_query_settings:
try:
default_query_settings.pop(default_query_settings.index(setting))
except ValueError:
pass
@TestSuite
def addressToLine_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `addressToLine` with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=addressToLine, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in addressToLine.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def addressToLine_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `addressToLine` with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=addressToLine, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in addressToLine.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("INTROSPECTION",),
("INTROSPECTION FUNCTIONS",),
("addressToLine",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Introspection_addressToLine("1.0"),
)
def addressToLine(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `addressToLine` when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("addressToLine without privilege"):
with When("I check the user can't use addressToLine"):
node.query(f"WITH addressToLine(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("addressToLine with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use addressToLine"):
node.query(f"WITH addressToLine(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings = [("user", f"{user_name}")])
with Scenario("addressToLine with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use addressToLine"):
node.query(f"WITH addressToLine(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def addressToSymbol_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `addressToSymbol` with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=addressToSymbol, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in addressToSymbol.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def addressToSymbol_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `addressToSymbol` with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=addressToSymbol, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in addressToSymbol.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("INTROSPECTION",),
("INTROSPECTION FUNCTIONS",),
("addressToSymbol",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Introspection_addressToSymbol("1.0"),
)
def addressToSymbol(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `addressToSymbol` when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("addressToSymbol without privilege"):
with When("I check the user can't use addressToSymbol"):
node.query(f"WITH addressToSymbol(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("addressToSymbol with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use addressToSymbol"):
node.query(f"WITH addressToSymbol(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings = [("user", f"{user_name}")])
with Scenario("addressToSymbol with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use addressToSymbol"):
node.query(f"WITH addressToSymbol(toUInt64(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def demangle_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `demangle` with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=demangle, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in demangle.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def demangle_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `demangle` with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=demangle, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in demangle.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("INTROSPECTION",),
("INTROSPECTION FUNCTIONS",),
("demangle",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Introspection_demangle("1.0"),
)
def demangle(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `demangle` when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("demangle without privilege"):
with When("I check the user can't use demangle"):
node.query(f"WITH demangle(toString(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("demangle with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use demangle"):
node.query(f"WITH demangle(toString(dummy)) AS addr SELECT 1 WHERE addr = ''", settings = [("user", f"{user_name}")])
with Scenario("demangle with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use demangle"):
node.query(f"WITH demangle(toString(dummy)) AS addr SELECT 1 WHERE addr = ''", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestFeature
@Name("introspection")
@Requirements(
RQ_SRS_006_RBAC_Privileges_Introspection("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of INTROSPECTION.
"""
self.context.node = self.context.cluster.node(node)
with allow_introspection_functions(self.context.node):
Suite(run=addressToLine_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=addressToLine_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=addressToSymbol_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=addressToSymbol_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=demangle_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=demangle_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -18,7 +18,8 @@ def public_tables(self, node=None):
node = self.context.node
with user(node, f"{user_name}"):
with Then("I check the user is able to select on system.one"):
with When("I check the user is able to select on system.one"):
node.query("SELECT count(*) FROM system.one", settings = [("user",user_name)])
with And("I check the user is able to select on system.numbers"):
@ -32,10 +33,10 @@ def public_tables(self, node=None):
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Table_QueryLog("1.0"),
RQ_SRS_006_RBAC_Table_SensitiveTables("1.0"),
)
def query_log(self, node=None):
"""Check that a user with no privilege is only able to see their own queries.
def sensitive_tables(self, node=None):
"""Check that a user with no privilege is not able to see from these tables.
"""
user_name = f"user_{getuid()}"
if node is None:
@ -45,8 +46,48 @@ def query_log(self, node=None):
with Given("I create a query"):
node.query("SELECT 1")
with Then("The user reads system.query_log"):
output = node.query("SELECT count() FROM system.query_log", settings = [("user",user_name)]).output
with When("I select from processes"):
output = node.query("SELECT count(*) FROM system.processes", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from query_log"):
output = node.query("SELECT count(*) FROM system.query_log", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from query_thread_log"):
output = node.query("SELECT count(*) FROM system.query_thread_log", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from clusters"):
output = node.query("SELECT count(*) FROM system.clusters", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from events"):
output = node.query("SELECT count(*) FROM system.events", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from graphite_retentions"):
output = node.query("SELECT count(*) FROM system.graphite_retentions", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from stack_trace"):
output = node.query("SELECT count(*) FROM system.stack_trace", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from trace_log"):
output = node.query("SELECT count(*) FROM system.trace_log", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from user_directories"):
output = node.query("SELECT count(*) FROM system.user_directories", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from zookeeper"):
output = node.query("SELECT count(*) FROM system.zookeeper WHERE path = '/clickhouse' ", settings = [("user",user_name)]).output
assert output == 0, error()
with And("I select from macros"):
output = node.query("SELECT count(*) FROM system.macros", settings = [("user",user_name)]).output
assert output == 0, error()
@TestFeature
@ -55,4 +96,4 @@ def feature(self, node="clickhouse1"):
self.context.node = self.context.cluster.node(node)
Scenario(run=public_tables, setup=instrument_clickhouse_server_log, flags=TE)
Scenario(run=query_log, setup=instrument_clickhouse_server_log, flags=TE)
Scenario(run=sensitive_tables, setup=instrument_clickhouse_server_log, flags=TE)

View File

@ -95,10 +95,10 @@ def role_admin(self, grant_target_name, user_name, node=None):
with user(node, target_user_name), role(node, role_admin_name):
with When(f"I grant ROLE ADMIN on the database"):
with When(f"I grant ROLE ADMIN"):
node.query(f"GRANT ROLE ADMIN ON *.* TO {grant_target_name}")
with And(f"I revoke ROLE ADMIN on the database"):
with And(f"I revoke ROLE ADMIN"):
node.query(f"REVOKE ROLE ADMIN ON *.* FROM {grant_target_name}")
with Then("I check the user cannot grant a role"):

View File

@ -76,7 +76,7 @@ def user_with_privilege_on_columns(self, table_type):
@TestOutline
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select_Column("1.0"),
RQ_SRS_006_RBAC_Select_Column("1.0"),
)
@Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass", [
("d", "d", "x", "d", '\'2020-01-01\''),
@ -197,7 +197,7 @@ def role_with_privilege_on_columns(self, table_type):
@TestOutline
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select_Column("1.0"),
RQ_SRS_006_RBAC_Select_Column("1.0"),
)
@Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass", [
("d", "d", "x", "d", '\'2020-01-01\''),
@ -241,7 +241,7 @@ def role_column_privileges(self, grant_columns, select_columns_pass, data_pass,
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select_Cluster("1.0"),
RQ_SRS_006_RBAC_Select_Cluster("1.0"),
)
def user_with_privilege_on_cluster(self, table_type, node=None):
"""Check that user is able to select from a table with
@ -270,14 +270,16 @@ def user_with_privilege_on_cluster(self, table_type, node=None):
@TestOutline(Feature)
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_TableEngines("1.0")
RQ_SRS_006_RBAC_Select("1.0"),
RQ_SRS_006_RBAC_Select_TableEngines("1.0")
)
@Examples("table_type", [
(key,) for key in table_types.keys()
])
@Name("select")
def feature(self, table_type, parallel=None, stress=None, node="clickhouse1"):
"""Check the RBAC functionality of SELECT.
"""
self.context.node = self.context.cluster.node(node)
if stress is not None:

View File

@ -41,7 +41,7 @@ def describe_with_privilege_granted_via_role(self, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_DescribeTable("1.0"),
RQ_SRS_006_RBAC_DescribeTable_RequiredPrivilege("1.0"),
)
def describe(self, grant_target_name, user_name, table_name, node=None):
"""Check that user is able to execute DESCRIBE only when they have SHOW COLUMNS privilege.
@ -112,7 +112,7 @@ def show_create_with_privilege_granted_via_role(self, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateTable("1.0"),
RQ_SRS_006_RBAC_ShowCreateTable_RequiredPrivilege("1.0"),
)
def show_create(self, grant_target_name, user_name, table_name, node=None):
"""Check that user is able to execute SHOW CREATE on a table only when they have SHOW COLUMNS privilege.
@ -150,7 +150,7 @@ def show_create(self, grant_target_name, user_name, table_name, node=None):
@TestFeature
@Name("show columns")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowColumns("1.0")
RQ_SRS_006_RBAC_ShowColumns_Privilege("1.0")
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW COLUMNS.

View File

@ -71,7 +71,7 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, db_name,
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowDatabases_Query("1.0"),
RQ_SRS_006_RBAC_ShowDatabases_RequiredPrivilege("1.0"),
)
def show_db(self, privilege, on, grant_target_name, user_name, db_name, node=None):
"""Check that user is only able to see a database in SHOW DATABASES when they have a privilege on that database.
@ -114,7 +114,7 @@ def show_db(self, privilege, on, grant_target_name, user_name, db_name, node=Non
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_UseDatabase("1.0"),
RQ_SRS_006_RBAC_UseDatabase_RequiredPrivilege("1.0"),
)
def use(self, privilege, on, grant_target_name, user_name, db_name, node=None):
"""Check that user is able to execute EXISTS on a database if and only if the user has SHOW DATABASE privilege
@ -158,7 +158,7 @@ def use(self, privilege, on, grant_target_name, user_name, db_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateDatabase("1.0"),
RQ_SRS_006_RBAC_ShowCreateDatabase_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, on, grant_target_name, user_name, db_name, node=None):
"""Check that user is able to execute EXISTS on a database if and only if the user has SHOW DATABASE privilege
@ -203,7 +203,7 @@ def show_create(self, privilege, on, grant_target_name, user_name, db_name, node
@TestFeature
@Name("show databases")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowDatabases("1.0")
RQ_SRS_006_RBAC_ShowDatabases_Privilege("1.0")
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW DATABASES.

View File

@ -71,7 +71,7 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, dict_name
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowDictionaries_Query("1.0"),
RQ_SRS_006_RBAC_ShowDictionaries_RequiredPrivilege("1.0"),
)
def show_dict(self, privilege, on, grant_target_name, user_name, dict_name, node=None):
"""Check that user is only able to see a dictionary in SHOW DICTIONARIES
@ -115,7 +115,7 @@ def show_dict(self, privilege, on, grant_target_name, user_name, dict_name, node
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ExistsDictionary("1.0"),
RQ_SRS_006_RBAC_ExistsDictionary_RequiredPrivilege("1.0"),
)
def exists(self, privilege, on, grant_target_name, user_name, dict_name, node=None):
"""Check that user is able to execute EXISTS on a dictionary if and only if the user has SHOW DICTIONARY privilege
@ -159,7 +159,7 @@ def exists(self, privilege, on, grant_target_name, user_name, dict_name, node=No
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateDictionary("1.0"),
RQ_SRS_006_RBAC_ShowCreateDictionary_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, on, grant_target_name, user_name, dict_name, node=None):
"""Check that user is able to execute SHOW CREATE on a dictionary if and only if the user has SHOW DICTIONARY privilege
@ -204,7 +204,7 @@ def show_create(self, privilege, on, grant_target_name, user_name, dict_name, no
@TestFeature
@Name("show dictionaries")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowDictionaries("1.0"),
RQ_SRS_006_RBAC_ShowDictionaries_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW DICTIONARIES.

View File

@ -74,7 +74,7 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowQuotas_Query("1.0"),
RQ_SRS_006_RBAC_ShowQuotas_RequiredPrivilege("1.0"),
)
def show_quotas(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW QUOTAS` when they have the necessary privilege.
@ -112,7 +112,7 @@ def show_quotas(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateQuota("1.0"),
RQ_SRS_006_RBAC_ShowCreateQuota_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW CREATE QUOTA` when they have the necessary privilege.
@ -160,7 +160,7 @@ def show_create(self, privilege, grant_target_name, user_name, node=None):
@TestFeature
@Name("show quotas")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowQuotas("1.0"),
RQ_SRS_006_RBAC_ShowQuotas_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW QUOTAS.

View File

@ -62,7 +62,7 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowRoles_Query("1.0"),
RQ_SRS_006_RBAC_ShowRoles_RequiredPrivilege("1.0"),
)
def show_roles(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW ROLES` when they have the necessary privilege.
@ -100,7 +100,7 @@ def show_roles(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateRole("1.0"),
RQ_SRS_006_RBAC_ShowCreateRole_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW CREATE ROLE` when they have the necessary privilege.
@ -148,7 +148,7 @@ def show_create(self, privilege, grant_target_name, user_name, node=None):
@TestFeature
@Name("show roles")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowRoles("1.0"),
RQ_SRS_006_RBAC_ShowRoles_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW ROLES.

View File

@ -76,7 +76,7 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowRowPolicies_Query("1.0"),
RQ_SRS_006_RBAC_ShowRowPolicies_RequiredPrivilege("1.0"),
)
def show_row_policies(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW ROW POLICIES` when they have the necessary privilege.
@ -114,7 +114,7 @@ def show_row_policies(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateRowPolicy("1.0"),
RQ_SRS_006_RBAC_ShowCreateRowPolicy_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW CREATE ROW POLICY` when they have the necessary privilege.
@ -165,7 +165,7 @@ def show_create(self, privilege, grant_target_name, user_name, node=None):
@TestFeature
@Name("show row policies")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowRowPolicies("1.0"),
RQ_SRS_006_RBAC_ShowRowPolicies_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW ROW POLICYS.

View File

@ -76,7 +76,7 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowSettingsProfiles_Query("1.0"),
RQ_SRS_006_RBAC_ShowSettingsProfiles_RequiredPrivilege("1.0"),
)
def show_settings_profiles(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW SETTINGS PROFILES` when they have the necessary privilege.
@ -114,7 +114,7 @@ def show_settings_profiles(self, privilege, grant_target_name, user_name, node=N
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateSettingsProfile("1.0"),
RQ_SRS_006_RBAC_ShowCreateSettingsProfile_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW CREATE SETTINGS PROFILE` when they have the necessary privilege.
@ -162,7 +162,7 @@ def show_create(self, privilege, grant_target_name, user_name, node=None):
@TestFeature
@Name("show settings profiles")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowSettingsProfiles("1.0"),
RQ_SRS_006_RBAC_ShowSettingsProfiles_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW SETTINGS PROFILES.

View File

@ -73,7 +73,7 @@ def check_privilege(self, privilege, on, grant_target_name, user_name, table_nam
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowTables_Query("1.0"),
RQ_SRS_006_RBAC_ShowTables_RequiredPrivilege("1.0"),
)
def show_tables(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to see a table in SHOW TABLES when they have a privilege on that table.
@ -112,7 +112,7 @@ def show_tables(self, privilege, on, grant_target_name, user_name, table_name, n
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ExistsTable("1.0"),
RQ_SRS_006_RBAC_ExistsTable_RequiredPrivilege("1.0"),
)
def exists(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is able to execute EXISTS on a table if and only if the user has SHOW TABLE privilege
@ -152,7 +152,7 @@ def exists(self, privilege, on, grant_target_name, user_name, table_name, node=N
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_CheckTable("1.0"),
RQ_SRS_006_RBAC_CheckTable_RequiredPrivilege("1.0"),
)
def check(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is able to execute CHECK on a table if and only if the user has SHOW TABLE privilege
@ -193,7 +193,7 @@ def check(self, privilege, on, grant_target_name, user_name, table_name, node=No
@TestFeature
@Name("show tables")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowTables("1.0"),
RQ_SRS_006_RBAC_ShowTables_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW TABLES.

View File

@ -62,7 +62,7 @@ def check_privilege(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowUsers_Query("1.0"),
RQ_SRS_006_RBAC_ShowUsers_RequiredPrivilege("1.0"),
)
def show_users(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW USERS` when they have the necessary privilege.
@ -100,7 +100,7 @@ def show_users(self, privilege, grant_target_name, user_name, node=None):
@TestSuite
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowCreateUser("1.0"),
RQ_SRS_006_RBAC_ShowCreateUser_RequiredPrivilege("1.0"),
)
def show_create(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SHOW CREATE USER` when they have the necessary privilege.
@ -148,7 +148,7 @@ def show_create(self, privilege, grant_target_name, user_name, node=None):
@TestFeature
@Name("show users")
@Requirements(
RQ_SRS_006_RBAC_Privileges_ShowUsers("1.0"),
RQ_SRS_006_RBAC_ShowUsers_Privilege("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SHOW USERS.

View File

@ -0,0 +1,713 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def file_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `File` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=file, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in file.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def file_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `File` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=file, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in file.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("FILE",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_File("1.0"),
)
def file(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `File` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("File source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the File source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=File()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("File source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the File source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=File()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("File source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the File source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=File()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def url_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `URL` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=url, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in url.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def url_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `URL` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=url, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in url.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("URL",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_URL("1.0"),
)
def url(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `URL` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("URL source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the URL source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=URL()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("URL source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the URL source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=URL()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("URL source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the URL source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=URL()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def remote_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a Remote source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=remote, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in remote.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def remote_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a Remote source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=remote, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in remote.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("REMOTE",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_Remote("1.0"),
)
def remote(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a remote source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("Remote source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the Remote source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE = Distributed()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("Remote source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the Remote source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE = Distributed()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("Remote source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the Remote source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE = Distributed()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def MySQL_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `MySQL` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=MySQL, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in MySQL.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def MySQL_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `MySQL` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=MySQL, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in MySQL.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("MYSQL",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_MySQL("1.0"),
)
def MySQL(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `MySQL` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("MySQL source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the MySQL source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=MySQL()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("MySQL source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the MySQL source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=MySQL()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("MySQL source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the MySQL source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=MySQL()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def ODBC_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `ODBC` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=ODBC, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in ODBC.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def ODBC_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `ODBC` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=ODBC, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in ODBC.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("ODBC",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_ODBC("1.0"),
)
def ODBC(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `ODBC` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("ODBC source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the ODBC source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=ODBC()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("ODBC source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the ODBC source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=ODBC()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("ODBC source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the ODBC source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=ODBC()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def JDBC_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `JDBC` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=JDBC, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in JDBC.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def JDBC_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `JDBC` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=JDBC, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in JDBC.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("JDBC",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_JDBC("1.0"),
)
def JDBC(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `JDBC` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("JDBC source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the JDBC source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=JDBC()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("JDBC source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the JDBC source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=JDBC()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("JDBC source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the JDBC source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=JDBC()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def HDFS_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `HDFS` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=HDFS, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in HDFS.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def HDFS_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `HDFS` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=HDFS, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in HDFS.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("HDFS",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_HDFS("1.0"),
)
def HDFS(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `HDFS` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("HDFS source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the HDFS source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=HDFS()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("HDFS source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the HDFS source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=HDFS()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("HDFS source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the HDFS source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=HDFS()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def S3_privileges_granted_directly(self, node=None):
"""Check that a user is able to create a table from a `S3` source with privileges are granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=S3, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in S3.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def S3_privileges_granted_via_role(self, node=None):
"""Check that a user is able to create a table from a `S3` source with privileges are granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=S3, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in S3.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SOURCES",),
("S3",),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources_S3("1.0"),
)
def S3(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to to create a table from a `S3` source when they have the necessary privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("S3 source without privilege"):
table_name = f'table_{getuid()}'
with Given("The user has table privilege"):
node.query(f"GRANT CREATE TABLE ON {table_name} TO {grant_target_name}")
with When("I check the user can't use the S3 source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=S3()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("S3 source with privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use the S3 source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=S3()", settings = [("user", f"{user_name}")],
exitcode=42, message='Exception: Storage')
with Scenario("S3 source with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use the S3 source"):
node.query(f"CREATE TABLE {table_name} (x String) ENGINE=S3()", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestFeature
@Name("sources")
@Requirements(
RQ_SRS_006_RBAC_Privileges_Sources("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SOURCES.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=file_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=file_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=url_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=url_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=remote_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=remote_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=MySQL_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=MySQL_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=ODBC_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=ODBC_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=JDBC_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=JDBC_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=HDFS_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=HDFS_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=S3_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=S3_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,269 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def dns_cache_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM DROP DNS CACHE` if and only if
they have `SYSTEM DROP DNS CACHE` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dns_cache, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dns_cache.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dns_cache_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM DROP DNS CACHE` if and only if
they have `SYSTEM DROP DNS CACHE` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dns_cache, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dns_cache.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_DropCache_DNS("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM DROP CACHE",),
("SYSTEM DROP DNS CACHE",),
("DROP CACHE",),
("DROP DNS CACHE",),
("SYSTEM DROP DNS",),
("DROP DNS",),
])
def dns_cache(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM DROP DNS CACHE` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM DROP DNS CACHE without privilege"):
with When("I check the user is unable to execute SYSTEM DROP DNS CACHE"):
node.query("SYSTEM DROP DNS CACHE", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM DROP DNS CACHE with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM DROP DNS CACHE"):
node.query("SYSTEM DROP DNS CACHE", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM DROP DNS CACHE with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM DROP DNS CACHE"):
node.query("SYSTEM DROP DNS CACHE", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def mark_cache_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM DROP MARK CACHE` if and only if
they have `SYSTEM DROP MARK CACHE` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=mark_cache, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in mark_cache.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def mark_cache_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM DROP MARK CACHE` if and only if
they have `SYSTEM DROP MARK CACHE` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=mark_cache, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in mark_cache.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_DropCache_Mark("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM DROP CACHE",),
("SYSTEM DROP MARK CACHE",),
("DROP CACHE",),
("DROP MARK CACHE",),
("SYSTEM DROP MARK",),
("DROP MARKS",),
])
def mark_cache(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM DROP MARK CACHE` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM DROP MARK CACHE without privilege"):
with When("I check the user is unable to execute SYSTEM DROP MARK CACHE"):
node.query("SYSTEM DROP MARK CACHE", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM DROP MARK CACHE with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM DROP MARK CACHE"):
node.query("SYSTEM DROP MARK CACHE", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM DROP MARK CACHE with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM DROP MARK CACHE"):
node.query("SYSTEM DROP MARK CACHE", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def uncompressed_cache_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM DROP UNCOMPRESSED CACHE` if and only if
they have `SYSTEM DROP UNCOMPRESSED CACHE` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=uncompressed_cache, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in uncompressed_cache.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def uncompressed_cache_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM DROP UNCOMPRESSED CACHE` if and only if
they have `SYSTEM DROP UNCOMPRESSED CACHE` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=uncompressed_cache, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in uncompressed_cache.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_DropCache_Uncompressed("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM DROP CACHE",),
("SYSTEM DROP UNCOMPRESSED CACHE",),
("DROP CACHE",),
("DROP UNCOMPRESSED CACHE",),
("SYSTEM DROP UNCOMPRESSED",),
("DROP UNCOMPRESSED",),
])
def uncompressed_cache(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM DROP UNCOMPRESSED CACHE` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM DROP UNCOMPRESSED CACHE without privilege"):
with When("I check the user is unable to execute SYSTEM DROP UNCOMPRESSED CACHE"):
node.query("SYSTEM DROP UNCOMPRESSED CACHE", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM DROP UNCOMPRESSED CACHE with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM DROP UNCOMPRESSED CACHE"):
node.query("SYSTEM DROP UNCOMPRESSED CACHE", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM DROP UNCOMPRESSED CACHE with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM DROP UNCOMPRESSED CACHE"):
node.query("SYSTEM DROP UNCOMPRESSED CACHE", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system drop cache")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_DropCache("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM DROP CACHE.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=dns_cache_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=dns_cache_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=mark_cache_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=mark_cache_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=uncompressed_cache_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=uncompressed_cache_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,150 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def replicated_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM FETCHES` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=check_replicated_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in check_replicated_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def replicated_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM FETCHES` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_replicated_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in check_replicated_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM FETCHES", "table"),
("SYSTEM STOP FETCHES", "table"),
("SYSTEM START FETCHES", "table"),
("START FETCHES", "table"),
("STOP FETCHES", "table"),
])
def check_replicated_privilege(self, privilege, on, grant_target_name, user_name, node=None):
"""Run checks for commands that require SYSTEM FETCHES privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name)
Suite(test=stop_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name)
@TestSuite
def start_replication_queues(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM START FETCHES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM START FETCHES without privilege"):
with When("I check the user can't start fetches"):
node.query(f"SYSTEM START FETCHES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START FETCHES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start fetches"):
node.query(f"SYSTEM START FETCHES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START FETCHES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start fetches"):
node.query(f"SYSTEM START FETCHES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def stop_replication_queues(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP FETCHES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM STOP FETCHES without privilege"):
with When("I check the user can't stop fetches"):
node.query(f"SYSTEM STOP FETCHES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP FETCHES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start fetches"):
node.query(f"SYSTEM STOP FETCHES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP FETCHES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start fetches"):
node.query(f"SYSTEM STOP FETCHES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system fetches")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Fetches("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM FETCHES.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=replicated_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=replicated_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,194 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM FLUSH LOGS` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=flush_logs, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in flush_logs.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM FLUSH LOGS` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=flush_logs, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in flush_logs.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM FLUSH", "*.*"),
("SYSTEM FLUSH LOGS", "*.*"),
("FLUSH LOGS", "*.*"),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Flush_Logs("1.0"),
)
def flush_logs(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM START REPLICATED FLUSH` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM FLUSH LOGS without privilege"):
with When("I check the user can't flush logs"):
node.query(f"SYSTEM FLUSH LOGS", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM FLUSH LOGS with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can flush logs"):
node.query(f"SYSTEM FLUSH LOGS", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM FLUSH LOGS with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't flush logs"):
node.query(f"SYSTEM FLUSH LOGS", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def distributed_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM FLUSH DISTRIBUTED` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
table_name = f"table_name_{getuid()}"
Suite(run=flush_distributed, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[user_name,user_name,table_name]) for row in flush_distributed.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def distributed_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM FLUSH DISTRIBUTED` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
table_name = f"table_name_{getuid()}"
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=flush_distributed, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[role_name,user_name,table_name]) for row in flush_distributed.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM FLUSH", "*.*"),
("SYSTEM FLUSH DISTRIBUTED", "table"),
("FLUSH DISTRIBUTED", "table"),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Flush_Distributed("1.0"),
)
def flush_distributed(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM FLUSH DISTRIBUTED` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table0_name = f"table0_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table0_name):
try:
with Given("I have a distributed table"):
node.query(f"CREATE TABLE {table_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())")
with Scenario("SYSTEM FLUSH DISTRIBUTED without privilege"):
with When("I check the user can't flush distributed"):
node.query(f"SYSTEM FLUSH DISTRIBUTED {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM FLUSH DISTRIBUTED with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can flush distributed"):
node.query(f"SYSTEM FLUSH DISTRIBUTED {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM FLUSH DISTRIBUTED with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't flush distributed"):
node.query(f"SYSTEM FLUSH DISTRIBUTED {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
finally:
with Finally("I drop the distributed table"):
node.query(f"DROP TABLE IF EXISTS {table_name}")
@TestFeature
@Name("system flush")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Flush("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM FLUSH.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=distributed_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=distributed_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,150 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM MERGES` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
table_name = f"table_name_{getuid()}"
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM MERGES` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
table_name = f"table_name_{getuid()}"
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM MERGES", "table"),
("SYSTEM STOP MERGES", "table"),
("SYSTEM START MERGES", "table"),
("START MERGES", "table"),
("STOP MERGES", "table"),
])
def check_privilege(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Run checks for commands that require SYSTEM MERGES privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
Suite(test=stop_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
@TestSuite
def start_merges(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM START MERGES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name):
with Scenario("SYSTEM START MERGES without privilege"):
with When("I check the user can't start merges"):
node.query(f"SYSTEM START MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START MERGES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start merges"):
node.query(f"SYSTEM START MERGES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START MERGES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start merges"):
node.query(f"SYSTEM START MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def stop_merges(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP MERGES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name):
with Scenario("SYSTEM STOP MERGES without privilege"):
with When("I check the user can't stop merges"):
node.query(f"SYSTEM STOP MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP MERGES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can stop merges"):
node.query(f"SYSTEM STOP MERGES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP MERGES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't stop merges"):
node.query(f"SYSTEM STOP MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system merges")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Merges("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM MERGES.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,150 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM MOVES` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
table_name = f"table_name_{getuid()}"
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM MOVES` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
table_name = f"table_name_{getuid()}"
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM MOVES", "table"),
("SYSTEM STOP MOVES", "table"),
("SYSTEM START MOVES", "table"),
("START MOVES", "table"),
("STOP MOVES", "table"),
])
def check_privilege(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Run checks for commands that require SYSTEM MOVES privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
Suite(test=stop_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
@TestSuite
def start_moves(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM START MOVES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name):
with Scenario("SYSTEM START MOVES without privilege"):
with When("I check the user can't start moves"):
node.query(f"SYSTEM START MOVES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START MOVES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start moves"):
node.query(f"SYSTEM START MOVES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START MOVES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start moves"):
node.query(f"SYSTEM START MOVES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def stop_moves(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP MOVES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name):
with Scenario("SYSTEM STOP MOVES without privilege"):
with When("I check the user can't stop moves"):
node.query(f"SYSTEM STOP MOVES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP MOVES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can stop moves"):
node.query(f"SYSTEM STOP MOVES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP MOVES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't stop moves"):
node.query(f"SYSTEM STOP MOVES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system moves")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Moves("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM MOVES.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,379 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@contextmanager
def dict_setup(node, table_name, dict_name):
"""Setup and teardown of table and dictionary needed for the tests.
"""
try:
with Given("I have a table"):
node.query(f"CREATE TABLE {table_name} (key UInt64, val UInt64) Engine=Memory()")
with And("I have a dictionary"):
node.query(f"CREATE DICTIONARY {dict_name} (key UInt64 DEFAULT 0, val UInt64 DEFAULT 10) PRIMARY KEY key SOURCE(CLICKHOUSE(HOST 'localhost' PORT tcpPort() USER 'default' TABLE '{table_name}' PASSWORD '' DB 'default')) LIFETIME(MIN 0 MAX 0) LAYOUT(FLAT())")
yield
finally:
with Finally("I drop the table", flags=TE):
node.query(f"DROP TABLE IF EXISTS {table_name}")
with And("I drop the dictionary", flags=TE):
node.query(f"DROP DICTIONARY IF EXISTS default.{dict_name}")
@TestSuite
def config_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD CONFIG` if and only if
they have `SYSTEM RELOAD CONFIG` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=config, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in config.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def config_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD CONFIG` if and only if
they have `SYSTEM RELOAD CONFIG` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=config, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in config.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Reload_Config("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM RELOAD",),
("SYSTEM RELOAD CONFIG",),
("RELOAD CONFIG",),
])
def config(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM RELOAD CONFIG` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM RELOAD CONFIG without privilege"):
with When("I check the user is unable to execute SYSTEM RELOAD CONFIG"):
node.query("SYSTEM RELOAD CONFIG", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM RELOAD CONFIG with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM RELOAD CONFIG"):
node.query("SYSTEM RELOAD CONFIG", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM RELOAD CONFIG with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM RELOAD CONFIG"):
node.query("SYSTEM RELOAD CONFIG", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def dictionary_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD DICTIONARY` if and only if
they have `SYSTEM RELOAD DICTIONARY` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictionary, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictionary.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictionary_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD DICTIONARY` if and only if
they have `SYSTEM RELOAD DICTIONARY` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictionary, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictionary.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionary("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM RELOAD",),
("SYSTEM RELOAD DICTIONARIES",),
("RELOAD DICTIONARIES",),
("RELOAD DICTIONARY",),
])
def dictionary(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM RELOAD DICTIONARY` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM RELOAD DICTIONARY without privilege"):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When("I check the user is unable to execute SYSTEM RELOAD DICTIONARY"):
node.query(f"SYSTEM RELOAD DICTIONARY default.{dict_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM RELOAD DICTIONARY with privilege"):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM RELOAD DICTIONARY"):
node.query(f"SYSTEM RELOAD DICTIONARY default.{dict_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM RELOAD DICTIONARY with revoked privilege"):
dict_name = f"dict_{getuid()}"
table_name = f"table_{getuid()}"
with dict_setup(node, table_name, dict_name):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM RELOAD DICTIONARY"):
node.query(f"SYSTEM RELOAD DICTIONARY default.{dict_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def dictionaries_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD DICTIONARIES` if and only if
they have `SYSTEM RELOAD DICTIONARIES` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=dictionaries, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in dictionaries.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def dictionaries_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD DICTIONARIES` if and only if
they have `SYSTEM RELOAD DICTIONARIES` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=dictionaries, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in dictionaries.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Reload_Dictionaries("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM RELOAD",),
("SYSTEM RELOAD DICTIONARIES",),
("RELOAD DICTIONARIES",),
("RELOAD DICTIONARY",),
])
def dictionaries(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM RELOAD DICTIONARIES` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM RELOAD DICTIONARIES without privilege"):
with When("I check the user is unable to execute SYSTEM RELOAD DICTIONARIES"):
node.query("SYSTEM RELOAD DICTIONARIES", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM RELOAD DICTIONARIES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM RELOAD DICTIONARIES"):
node.query("SYSTEM RELOAD DICTIONARIES", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM RELOAD DICTIONARIES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM RELOAD DICTIONARIES"):
node.query("SYSTEM RELOAD DICTIONARIES", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def embedded_dictionaries_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD EMBEDDED DICTIONARIES` if and only if
they have `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=embedded_dictionaries, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in embedded_dictionaries.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def embedded_dictionaries_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM RELOAD EMBEDDED DICTIONARIES` if and only if
they have `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=embedded_dictionaries, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in embedded_dictionaries.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Reload_EmbeddedDictionaries("1.0"),
)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM RELOAD",),
("SYSTEM RELOAD EMBEDDED DICTIONARIES",),
("SYSTEM RELOAD DICTIONARY",),
])
def embedded_dictionaries(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for `SYSTEM RELOAD EMBEDDED DICTIONARIES` privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM RELOAD EMBEDDED DICTIONARIES without privilege"):
with When("I check the user is unable to execute SYSTEM RELOAD EMBEDDED DICTIONARIES"):
node.query("SYSTEM RELOAD EMBEDDED DICTIONARIES", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM RELOAD EMBEDDED DICTIONARIES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user is bale to execute SYSTEM RELOAD EMBEDDED DICTIONARIES"):
node.query("SYSTEM RELOAD EMBEDDED DICTIONARIES", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM RELOAD EMBEDDED DICTIONARIES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user is unable to execute SYSTEM RELOAD EMBEDDED DICTIONARIES"):
node.query("SYSTEM RELOAD EMBEDDED DICTIONARIES", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system reload")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Reload("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM RELOAD.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=config_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=config_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=dictionary_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=dictionary_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=dictionaries_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=dictionaries_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=embedded_dictionaries_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=embedded_dictionaries_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,150 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def replicated_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM REPLICATION QUEUES` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=check_replicated_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in check_replicated_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def replicated_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM REPLICATION QUEUES` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_replicated_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in check_replicated_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM REPLICATION QUEUES", "table"),
("SYSTEM STOP REPLICATION QUEUES", "table"),
("SYSTEM START REPLICATION QUEUES", "table"),
("START REPLICATION QUEUES", "table"),
("STOP REPLICATION QUEUES", "table"),
])
def check_replicated_privilege(self, privilege, on, grant_target_name, user_name, node=None):
"""Run checks for commands that require SYSTEM REPLICATION QUEUES privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name)
Suite(test=stop_replication_queues, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name)
@TestSuite
def start_replication_queues(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM START REPLICATION QUEUES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM START REPLICATION QUEUES without privilege"):
with When("I check the user can't start sends"):
node.query(f"SYSTEM START REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START REPLICATION QUEUES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start sends"):
node.query(f"SYSTEM START REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START REPLICATION QUEUES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start sends"):
node.query(f"SYSTEM START REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def stop_replication_queues(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP REPLICATION QUEUES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM STOP REPLICATION QUEUES without privilege"):
with When("I check the user can't stop sends"):
node.query(f"SYSTEM STOP REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP REPLICATION QUEUES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start sends"):
node.query(f"SYSTEM STOP REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP REPLICATION QUEUES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start sends"):
node.query(f"SYSTEM STOP REPLICATION QUEUES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system replication queues")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_ReplicationQueues("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM REPLICATION QUEUES.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=replicated_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=replicated_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,99 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM RESTART REPLICA` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=restart_replica, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in restart_replica.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM RESTART REPLICA` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=restart_replica, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in restart_replica.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM RESTART REPLICA", "table"),
("RESTART REPLICA", "table"),
])
def restart_replica(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM RESTARTE REPLICA` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM RESTART REPLICA without privilege"):
with When("I check the user can't restart replica"):
node.query(f"SYSTEM RESTART REPLICA {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM RESTART REPLICA with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can restart replica"):
node.query(f"SYSTEM RESTART REPLICA {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM RESTART REPLICA with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't restart replica"):
node.query(f"SYSTEM RESTART REPLICA {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system restart replica")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_RestartReplica("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM RESTART REPLICA.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,314 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def replicated_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM REPLICATED SENDS` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=check_replicated_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in check_replicated_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def replicated_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM REPLICATED SENDS` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_replicated_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in check_replicated_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM SENDS", "*.*"),
("SYSTEM START SENDS", "*.*"),
("SYSTEM STOP SENDS", "*.*"),
("START SENDS", "*.*"),
("STOP SENDS", "*.*"),
("SYSTEM REPLICATED SENDS", "table"),
("SYSTEM STOP REPLICATED SENDS", "table"),
("SYSTEM START REPLICATED SENDS", "table"),
("START REPLICATED SENDS", "table"),
("STOP REPLICATED SENDS", "table"),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Sends_Replicated("1.0"),
)
def check_replicated_privilege(self, privilege, on, grant_target_name, user_name, node=None):
"""Run checks for commands that require SYSTEM REPLICATED SENDS privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_replicated_sends, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name)
Suite(test=stop_replicated_sends, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name)
@TestSuite
def start_replicated_sends(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM START REPLICATED SENDS` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM START REPLICATED SENDS without privilege"):
with When("I check the user can't start sends"):
node.query(f"SYSTEM START REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START REPLICATED SENDS with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start sends"):
node.query(f"SYSTEM START REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START REPLICATED SENDS with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start sends"):
node.query(f"SYSTEM START REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def stop_replicated_sends(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP REPLICATED SENDS` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM STOP REPLICATED SENDS without privilege"):
with When("I check the user can't stop sends"):
node.query(f"SYSTEM STOP REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP REPLICATED SENDS with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can stop sends"):
node.query(f"SYSTEM STOP REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP REPLICATED SENDS with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't stop sends"):
node.query(f"SYSTEM STOP REPLICATED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def distributed_privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM DISTRIBUTED SENDS` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
table_name = f"table_name_{getuid()}"
Suite(run=check_distributed_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[user_name,user_name,table_name]) for row in check_distributed_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def distributed_privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM DISTRIBUTED SENDS` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
table_name = f"table_name_{getuid()}"
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_distributed_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[role_name,user_name,table_name]) for row in check_distributed_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM SENDS", "*.*"),
("SYSTEM START SENDS", "*.*"),
("SYSTEM STOP SENDS", "*.*"),
("START SENDS", "*.*"),
("STOP SENDS", "*.*"),
("SYSTEM DISTRIBUTED SENDS", "table"),
("SYSTEM STOP DISTRIBUTED SENDS", "table"),
("SYSTEM START DISTRIBUTED SENDS", "table"),
("START DISTRIBUTED SENDS", "table"),
("STOP DISTRIBUTED SENDS", "table"),
])
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Sends_Distributed("1.0"),
)
def check_distributed_privilege(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Run checks for commands that require SYSTEM DISTRIBUTED SENDS privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_distributed_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
Suite(test=stop_distributed_moves, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
@TestSuite
def start_distributed_moves(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM START DISTRIBUTED SENDS` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table0_name = f"table0_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table0_name):
try:
with Given("I have a distributed table"):
node.query(f"CREATE TABLE {table_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())")
with Scenario("SYSTEM START DISTRIBUTED SENDS without privilege"):
with When("I check the user can't start merges"):
node.query(f"SYSTEM START DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START DISTRIBUTED SENDS with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start merges"):
node.query(f"SYSTEM START DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START DISTRIBUTED SENDS with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start merges"):
node.query(f"SYSTEM START DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
finally:
with Finally("I drop the distributed table"):
node.query(f"DROP TABLE IF EXISTS {table_name}")
@TestSuite
def stop_distributed_moves(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP DISTRIBUTED SENDS` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table0_name = f"table0_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table0_name):
try:
with Given("I have a distributed table"):
node.query(f"CREATE TABLE {table_name} (a UInt64) ENGINE = Distributed(sharded_cluster, default, {table0_name}, rand())")
with Scenario("SYSTEM STOP DISTRIBUTED SENDS without privilege"):
with When("I check the user can't stop merges"):
node.query(f"SYSTEM STOP DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP DISTRIBUTED SENDS with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can stop merges"):
node.query(f"SYSTEM STOP DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP DISTRIBUTED SENDS with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't stop merges"):
node.query(f"SYSTEM STOP DISTRIBUTED SENDS {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
finally:
with Finally("I drop the distributed table"):
node.query(f"DROP TABLE IF EXISTS {table_name}")
@TestFeature
@Name("system sends")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Sends("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM SENDS.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=replicated_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=replicated_privileges_granted_via_role, setup=instrument_clickhouse_server_log)
Suite(run=distributed_privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=distributed_privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,200 @@
import time
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Run checks with privileges granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in check_privilege.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Run checks with privileges granted through a role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in check_privilege.examples
], args=Args(name="privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege",[
("SYSTEM",),
("SYSTEM SHUTDOWN",),
("SHUTDOWN",),
("SYSTEM KILL",),
])
def check_privilege(self, privilege, grant_target_name, user_name, node=None):
"""Run checks for commands that require SYSTEM SHUTDOWN privilege.
"""
if node is None:
node = self.context.node
Suite(test=shutdown, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name)
Suite(test=kill, setup=instrument_clickhouse_server_log)(privilege=privilege, grant_target_name=grant_target_name, user_name=user_name)
@TestSuite
def shutdown(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM SHUTDOWN` when they have the necessary privilege.
"""
cluster = self.context.cluster
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM SHUTDOWN without privilege"):
with When("I check the user can't use SYSTEM SHUTDOWN"):
node.query(f"SYSTEM SHUTDOWN", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("SYSTEM SHUTDOWN with privilege"):
timeout = 60
try:
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use SYSTEM SHUTDOWN"):
node.query(f"SYSTEM SHUTDOWN", settings = [("user", f"{user_name}")])
with And("I close all connections to the node"):
node.close_bashes()
with And("I check that system is down"):
command = f"echo -e \"SELECT 1\" | {cluster.docker_compose} exec -T {node.name} clickhouse client -n"
start_time = time.time()
while True:
r = cluster.bash(None)(command)
if r.exitcode != 0:
break
if time.time() - start_time > timeout:
break
time.sleep(1)
assert r.exitcode != 0, error(r.output)
finally:
with Finally("I relaunch the server"):
node.restart(safe=False)
with Scenario("SYSTEM SHUTDOWN with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use SYSTEM SHUTDOWN"):
node.query(f"SYSTEM SHUTDOWN", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestSuite
def kill(self, privilege, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM KILL` when they have the necessary privilege.
"""
cluster = self.context.cluster
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
with Scenario("SYSTEM KILL without privilege"):
with When("I check the user can't use SYSTEM KILL"):
node.query(f"SYSTEM KILL", settings=[("user",user_name)],
exitcode=exitcode, message=message)
with Scenario("SYSTEM KILL with privilege"):
timeout = 60
try:
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with Then("I check the user can use SYSTEM KILL"):
command = f"echo -e \"SYSTEM KILL\" | clickhouse client -n"
with By("executing command", description=command):
self.context.cluster.bash(node.name).send(command)
with And("I close all connections to the node"):
node.close_bashes()
with And("I check that system is down"):
command = f"echo -e \"SELECT 1\" | {cluster.docker_compose} exec -T {node.name} clickhouse client -n"
start_time = time.time()
while True:
r = cluster.bash(None)(command)
if r.exitcode != 0:
break
if time.time() - start_time > timeout:
break
time.sleep(1)
assert r.exitcode != 0, error(r.output)
finally:
with Finally("I relaunch the server"):
node.restart(safe=False)
with Scenario("SYSTEM KILL with revoked privilege"):
with When(f"I grant {privilege}"):
node.query(f"GRANT {privilege} ON *.* TO {grant_target_name}")
with And(f"I revoke {privilege}"):
node.query(f"REVOKE {privilege} ON *.* FROM {grant_target_name}")
with Then("I check the user cannot use SYSTEM KILL"):
node.query(f"SYSTEM KILL", settings=[("user",user_name)],
exitcode=exitcode, message=message)
@TestFeature
@Name("system shutdown")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_Shutdown("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM SHUTDOWN.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,99 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM SYNC REPLICA` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
Suite(run=sync_replica, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[user_name,user_name]) for row in sync_replica.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM SYNC REPLICA` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=sync_replica, flags=TE,
examples=Examples("privilege on grant_target_name user_name", [
tuple(list(row)+[role_name,user_name]) for row in sync_replica.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM SYNC REPLICA", "table"),
("SYNC REPLICA", "table"),
])
def sync_replica(self, privilege, on, grant_target_name, user_name, node=None):
"""Check that user is only able to execute `SYSTEM SYNCE REPLICA` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
table_name = f"table_name_{getuid()}"
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name, "ReplicatedMergeTree-sharded_cluster"):
with Scenario("SYSTEM SYNC REPLICA without privilege"):
with When("I check the user can't sync replica"):
node.query(f"SYSTEM SYNC REPLICA {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM SYNC REPLICA with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can sync replica"):
node.query(f"SYSTEM SYNC REPLICA {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM SYNC REPLICA with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't sync replica"):
node.query(f"SYSTEM SYNC REPLICA {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system sync replica")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_SyncReplica("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM SYNC REPLICA.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -0,0 +1,150 @@
from testflows.core import *
from testflows.asserts import error
from rbac.requirements import *
from rbac.helper.common import *
import rbac.helper.errors as errors
@TestSuite
def privileges_granted_directly(self, node=None):
"""Check that a user is able to execute `SYSTEM TTL MERGES` commands if and only if
the privilege has been granted directly.
"""
user_name = f"user_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"):
table_name = f"table_name_{getuid()}"
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[user_name,user_name,table_name]) for row in check_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestSuite
def privileges_granted_via_role(self, node=None):
"""Check that a user is able to execute `SYSTEM TTL MERGES` commands if and only if
the privilege has been granted via role.
"""
user_name = f"user_{getuid()}"
role_name = f"role_{getuid()}"
if node is None:
node = self.context.node
with user(node, f"{user_name}"), role(node, f"{role_name}"):
table_name = f"table_name_{getuid()}"
with When("I grant the role to the user"):
node.query(f"GRANT {role_name} TO {user_name}")
Suite(run=check_privilege, flags=TE,
examples=Examples("privilege on grant_target_name user_name table_name", [
tuple(list(row)+[role_name,user_name,table_name]) for row in check_privilege.examples
], args=Args(name="check privilege={privilege}", format_name=True)))
@TestOutline(Suite)
@Examples("privilege on",[
("SYSTEM", "*.*"),
("SYSTEM TTL MERGES", "table"),
("SYSTEM STOP TTL MERGES", "table"),
("SYSTEM START TTL MERGES", "table"),
("START TTL MERGES", "table"),
("STOP TTL MERGES", "table"),
])
def check_privilege(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Run checks for commands that require SYSTEM TTL MERGES privilege.
"""
if node is None:
node = self.context.node
Suite(test=start_ttl_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
Suite(test=stop_ttl_merges, setup=instrument_clickhouse_server_log)(privilege=privilege, on=on, grant_target_name=grant_target_name, user_name=user_name, table_name=table_name)
@TestSuite
def start_ttl_merges(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM START TTL MERGES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name):
with Scenario("SYSTEM START TTL MERGES without privilege"):
with When("I check the user can't start merges"):
node.query(f"SYSTEM START TTL MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM START TTL MERGES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can start merges"):
node.query(f"SYSTEM START TTL MERGES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM START TTL MERGES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't start merges"):
node.query(f"SYSTEM START TTL MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestSuite
def stop_ttl_merges(self, privilege, on, grant_target_name, user_name, table_name, node=None):
"""Check that user is only able to execute `SYSTEM STOP TTL MERGES` when they have privilege.
"""
exitcode, message = errors.not_enough_privileges(name=user_name)
if node is None:
node = self.context.node
on = on.replace("table", f"{table_name}")
with table(node, table_name):
with Scenario("SYSTEM STOP TTL MERGES without privilege"):
with When("I check the user can't stop merges"):
node.query(f"SYSTEM STOP TTL MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
with Scenario("SYSTEM STOP TTL MERGES with privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with Then("I check the user can stop merges"):
node.query(f"SYSTEM STOP TTL MERGES {table_name}", settings = [("user", f"{user_name}")])
with Scenario("SYSTEM STOP TTL MERGES with revoked privilege"):
with When(f"I grant {privilege} on the table"):
node.query(f"GRANT {privilege} ON {on} TO {grant_target_name}")
with And(f"I revoke {privilege} on the table"):
node.query(f"REVOKE {privilege} ON {on} FROM {grant_target_name}")
with Then("I check the user can't stop merges"):
node.query(f"SYSTEM STOP TTL MERGES {table_name}", settings = [("user", f"{user_name}")],
exitcode=exitcode, message=message)
@TestFeature
@Name("system ttl merges")
@Requirements(
RQ_SRS_006_RBAC_Privileges_System_TTLMerges("1.0"),
)
def feature(self, node="clickhouse1"):
"""Check the RBAC functionality of SYSTEM TTL MERGES.
"""
self.context.node = self.context.cluster.node(node)
Suite(run=privileges_granted_directly, setup=instrument_clickhouse_server_log)
Suite(run=privileges_granted_via_role, setup=instrument_clickhouse_server_log)

View File

@ -16,7 +16,8 @@ def regression(self, local, clickhouse_binary_path, stress=None, parallel=None):
# Feature(test=load("example.regression", "regression"))(**args)
# Feature(test=load("ldap.regression", "regression"))(**args)
# Feature(test=load("rbac.regression", "regression"))(**args)
for i in range(10):
Feature(test=load("rbac.regression", "regression"))(**args)
# Feature(test=load("aes_encryption.regression", "regression"))(**args)
if main():