diff --git a/src/Access/ExtendedRoleSet.cpp b/src/Access/ExtendedRoleSet.cpp index a29ee40380c2360ea2c1303b9518da3f3191122a..a8e674b3722704b605f70f00dcc5a19b44d57550 100644 --- a/src/Access/ExtendedRoleSet.cpp +++ b/src/Access/ExtendedRoleSet.cpp @@ -68,15 +68,27 @@ void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlMa { all = ast.all; - auto name_to_id = [id_mode{ast.id_mode}, manager](const String & name) -> UUID + auto name_to_id = [&ast, manager](const String & name) -> UUID { - if (id_mode) + if (ast.id_mode) return parse(name); assert(manager); - auto id = manager->find(name); - if (id) - return *id; - return manager->getID(name); + if (ast.can_contain_users && ast.can_contain_roles) + { + auto id = manager->find(name); + if (id) + return *id; + return manager->getID(name); + } + else if (ast.can_contain_users) + { + return manager->getID(name); + } + else + { + assert(ast.can_contain_roles); + return manager->getID(name); + } }; if (!ast.names.empty() && !all) diff --git a/src/Interpreters/InterpreterSetRoleQuery.cpp b/src/Interpreters/InterpreterSetRoleQuery.cpp index f8e0167d7482bce6e5df9bc1c8239c82dfbaba91..c627061dd51f17128401d703cb8db611c0ee2339 100644 --- a/src/Interpreters/InterpreterSetRoleQuery.cpp +++ b/src/Interpreters/InterpreterSetRoleQuery.cpp @@ -62,7 +62,7 @@ void InterpreterSetRoleQuery::setRole(const ASTSetRoleQuery & query) void InterpreterSetRoleQuery::setDefaultRole(const ASTSetRoleQuery & query) { - context.checkAccess(AccessType::CREATE_USER | AccessType::DROP_USER); + context.checkAccess(AccessType::ALTER_USER); auto & access_control = context.getAccessControlManager(); std::vector to_users = ExtendedRoleSet{*query.to_users, access_control, context.getUserID()}.getMatchingIDs(access_control); diff --git a/src/Parsers/ASTExtendedRoleSet.h b/src/Parsers/ASTExtendedRoleSet.h index 8d619e5d6a0d2ae8f265ad3a29d11e97e118c80a..656f563bd9a163da4d7d3d8c7a228e8b00eb921f 100644 --- a/src/Parsers/ASTExtendedRoleSet.h +++ b/src/Parsers/ASTExtendedRoleSet.h @@ -15,7 +15,10 @@ public: bool all = false; Strings except_names; bool except_current_user = false; - bool id_mode = false; /// If true then `names` and `except_names` keeps UUIDs, not names. + + bool id_mode = false; /// true if `names` and `except_names` keep UUIDs, not names. + bool can_contain_roles = true; /// true if this set can contain names of roles. + bool can_contain_users = true; /// true if this set can contain names of users. bool empty() const { return names.empty() && !current_user && !all; } void replaceCurrentUserTagWithName(const String & current_user_name); diff --git a/src/Parsers/ParserCreateUserQuery.cpp b/src/Parsers/ParserCreateUserQuery.cpp index 76a06a0282fd649d9c6a86f49a0340fbd174f1f5..a6a007855e2e13269e1407548b1c9e32a5279ce3 100644 --- a/src/Parsers/ParserCreateUserQuery.cpp +++ b/src/Parsers/ParserCreateUserQuery.cpp @@ -227,6 +227,7 @@ namespace return false; default_roles = typeid_cast>(ast); + default_roles->can_contain_users = false; return true; }); } diff --git a/src/Parsers/ParserSetRoleQuery.cpp b/src/Parsers/ParserSetRoleQuery.cpp index e6ff78938911e61dc16cbe67950a00c755d0ad78..a69480f89ebfa6c31709a189cc9ad4aa5c47befa 100644 --- a/src/Parsers/ParserSetRoleQuery.cpp +++ b/src/Parsers/ParserSetRoleQuery.cpp @@ -18,6 +18,7 @@ namespace return false; roles = typeid_cast>(ast); + roles->can_contain_users = false; return true; }); } @@ -34,6 +35,7 @@ namespace return false; to_users = typeid_cast>(ast); + to_users->can_contain_roles = false; return true; }); } diff --git a/tests/integration/test_default_role/__init__.py b/tests/integration/test_default_role/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/integration/test_default_role/test.py b/tests/integration/test_default_role/test.py new file mode 100644 index 0000000000000000000000000000000000000000..2b6b4698b20fe6c22f30b4fa2789ecc1dd328641 --- /dev/null +++ b/tests/integration/test_default_role/test.py @@ -0,0 +1,77 @@ +import pytest +from helpers.cluster import ClickHouseCluster +from helpers.test_tools import TSV +import re + +cluster = ClickHouseCluster(__file__) +instance = cluster.add_instance('instance') + + +@pytest.fixture(scope="module", autouse=True) +def started_cluster(): + try: + cluster.start() + + instance.query("CREATE USER john") + instance.query("CREATE ROLE rx") + instance.query("CREATE ROLE ry") + + yield cluster + + finally: + cluster.shutdown() + + +@pytest.fixture(autouse=True) +def reset_users_and_roles(): + instance.query("CREATE USER OR REPLACE john") + yield + + +def test_set_default_roles(): + assert instance.query("SHOW CURRENT ROLES", user="john") == "" + + instance.query("GRANT rx, ry TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['rx', 0, 1], ['ry', 0, 1]] ) + + instance.query("SET DEFAULT ROLE NONE TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == "" + + instance.query("SET DEFAULT ROLE rx TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['rx', 0, 1]] ) + + instance.query("SET DEFAULT ROLE ry TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['ry', 0, 1]] ) + + instance.query("SET DEFAULT ROLE ALL TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['rx', 0, 1], ['ry', 0, 1]] ) + + instance.query("SET DEFAULT ROLE ALL EXCEPT rx TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['ry', 0, 1]] ) + + +def test_alter_user(): + assert instance.query("SHOW CURRENT ROLES", user="john") == "" + + instance.query("GRANT rx, ry TO john") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['rx', 0, 1], ['ry', 0, 1]] ) + + instance.query("ALTER USER john DEFAULT ROLE NONE") + assert instance.query("SHOW CURRENT ROLES", user="john") == "" + + instance.query("ALTER USER john DEFAULT ROLE rx") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['rx', 0, 1]] ) + + instance.query("ALTER USER john DEFAULT ROLE ALL") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['rx', 0, 1], ['ry', 0, 1]] ) + + instance.query("ALTER USER john DEFAULT ROLE ALL EXCEPT rx") + assert instance.query("SHOW CURRENT ROLES", user="john") == TSV( [['ry', 0, 1]] ) + + +def test_wrong_set_default_role(): + assert "There is no user `rx`" in instance.query_and_get_error("SET DEFAULT ROLE NONE TO rx") + assert "There is no user `ry`" in instance.query_and_get_error("SET DEFAULT ROLE rx TO ry") + assert "There is no role `john`" in instance.query_and_get_error("SET DEFAULT ROLE john TO john") + assert "There is no role `john`" in instance.query_and_get_error("ALTER USER john DEFAULT ROLE john") + assert "There is no role `john`" in instance.query_and_get_error("ALTER USER john DEFAULT ROLE ALL EXCEPT john")