diff --git a/programs/server/config.xml b/programs/server/config.xml index e0d527f9538..f55ab02d903 100644 --- a/programs/server/config.xml +++ b/programs/server/config.xml @@ -128,6 +128,9 @@ /var/lib/clickhouse/user_files/ + + /var/lib/clickhouse/access/ + users.xml diff --git a/programs/server/users.xml b/programs/server/users.xml index d631fbb0f8a..3d95269190b 100644 --- a/programs/server/users.xml +++ b/programs/server/users.xml @@ -83,6 +83,9 @@ default + + + diff --git a/src/Access/AccessControlManager.cpp b/src/Access/AccessControlManager.cpp index b5e06549c28..f8f15e425ed 100644 --- a/src/Access/AccessControlManager.cpp +++ b/src/Access/AccessControlManager.cpp @@ -23,7 +23,10 @@ namespace std::vector> list; list.emplace_back(std::make_unique()); list.emplace_back(std::make_unique()); + +#if 0 /// Memory access storage is disabled. list.emplace_back(std::make_unique()); +#endif return list; } diff --git a/src/Access/AccessFlags.h b/src/Access/AccessFlags.h index 2c5307bbd1a..c8f57fcd419 100644 --- a/src/Access/AccessFlags.h +++ b/src/Access/AccessFlags.h @@ -5,12 +5,19 @@ #include #include #include +#include +#include #include #include namespace DB { +namespace ErrorCodes +{ + extern const int LOGICAL_ERROR; +} + /// Represents a combination of access types which can be granted globally, on databases, tables, columns, etc. /// For example "SELECT, CREATE USER" is an access type. class AccessFlags @@ -175,9 +182,10 @@ public: const Flags & getDictionaryFlags() const { return all_flags_for_target[DICTIONARY]; } private: - enum Target + enum NodeType { - UNKNOWN_TARGET, + UNKNOWN = -2, + GROUP = -1, GLOBAL, DATABASE, TABLE, @@ -186,46 +194,190 @@ private: DICTIONARY, }; - static constexpr size_t NUM_TARGETS = static_cast(DICTIONARY) + 1; - struct Node; using NodePtr = std::unique_ptr; - using Nodes = std::vector; - - template - static Nodes nodes(Args&& ... args) - { - Nodes res; - ext::push_back(res, std::move(args)...); - return res; - } struct Node { - std::string_view keyword; - std::vector aliases; + const String keyword; + NodeType node_type; + AccessType type = AccessType::NONE; + Strings aliases; Flags flags; - Target target = UNKNOWN_TARGET; - Nodes children; + std::vector children; - Node(std::string_view keyword_, size_t flag_, Target target_) - : keyword(keyword_), target(target_) + Node(String keyword_, NodeType node_type_ = UNKNOWN) : keyword(std::move(keyword_)), node_type(node_type_) {} + + void setFlag(size_t flag) { flags.set(flag); } + + void addChild(NodePtr child) { - flags.set(flag_); + flags |= child->flags; + children.push_back(std::move(child)); } - - Node(std::string_view keyword_, Nodes children_) - : keyword(keyword_), children(std::move(children_)) - { - for (const auto & child : children) - flags |= child->flags; - } - - template - Node(std::string_view keyword_, NodePtr first_child, Args &&... other_children) - : Node(keyword_, nodes(std::move(first_child), std::move(other_children)...)) {} }; + static String replaceUnderscoreWithSpace(const std::string_view & str) + { + String res{str}; + boost::replace_all(res, "_", " "); + return res; + } + + static Strings splitAliases(const std::string_view & str) + { + Strings aliases; + boost::split(aliases, str, boost::is_any_of(",")); + for (auto & alias : aliases) + boost::trim(alias); + return aliases; + } + + static void makeFlagsToKeywordTreeNode( + AccessType type, + const std::string_view & name, + const std::string_view & aliases, + NodeType node_type, + const std::string_view & parent_group_name, + std::unordered_map & nodes, + std::unordered_map & owned_nodes, + size_t & next_flag) + { + NodePtr node; + auto keyword = replaceUnderscoreWithSpace(name); + auto it = owned_nodes.find(keyword); + if (it != owned_nodes.end()) + { + node = std::move(it->second); + owned_nodes.erase(it); + } + else + { + if (nodes.contains(keyword)) + throw Exception(keyword + " declared twice", ErrorCodes::LOGICAL_ERROR); + node = std::make_unique(keyword, node_type); + nodes[node->keyword] = node.get(); + } + + node->type = type; + node->node_type = node_type; + node->aliases = splitAliases(aliases); + if (node_type != GROUP) + node->setFlag(next_flag++); + + bool has_parent_group = (parent_group_name != "NONE"); + if (!has_parent_group) + { + std::string_view keyword_as_string_view = node->keyword; + owned_nodes[keyword_as_string_view] = std::move(node); + return; + } + + auto parent_keyword = replaceUnderscoreWithSpace(parent_group_name); + auto it_parent = nodes.find(parent_keyword); + if (it_parent == nodes.end()) + { + auto parent_node = std::make_unique(parent_keyword); + it_parent = nodes.emplace(parent_node->keyword, parent_node.get()).first; + assert(!owned_nodes.contains(parent_node->keyword)); + std::string_view parent_keyword_as_string_view = parent_node->keyword; + owned_nodes[parent_keyword_as_string_view] = std::move(parent_node); + } + it_parent->second->addChild(std::move(node)); + } + + void makeFlagsToKeywordTree() + { + std::unordered_map owned_nodes; + std::unordered_map nodes; + size_t next_flag = 0; + +#define MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE(name, aliases, node_type, parent_group_name) \ + makeFlagsToKeywordTreeNode(AccessType::name, #name, aliases, node_type, #parent_group_name, nodes, owned_nodes, next_flag); + + APPLY_FOR_ACCESS_TYPES(MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE) + +#undef MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE + + if (!owned_nodes.contains("NONE")) + throw Exception("'NONE' not declared", ErrorCodes::LOGICAL_ERROR); + if (!owned_nodes.contains("ALL")) + throw Exception("'ALL' not declared", ErrorCodes::LOGICAL_ERROR); + + flags_to_keyword_tree = std::move(owned_nodes["ALL"]); + none_node = std::move(owned_nodes["NONE"]); + owned_nodes.erase("ALL"); + owned_nodes.erase("NONE"); + + if (!owned_nodes.empty()) + { + const auto & unused_node = *(owned_nodes.begin()->second); + if (unused_node.node_type == UNKNOWN) + throw Exception("Parent group '" + unused_node.keyword + "' not found", ErrorCodes::LOGICAL_ERROR); + else + throw Exception("Access type '" + unused_node.keyword + "' should have parent group", ErrorCodes::LOGICAL_ERROR); + } + } + + void makeKeywordToFlagsMap(Node * start_node = nullptr) + { + if (!start_node) + { + makeKeywordToFlagsMap(none_node.get()); + start_node = flags_to_keyword_tree.get(); + } + + start_node->aliases.emplace_back(start_node->keyword); + for (auto & alias : start_node->aliases) + { + boost::to_upper(alias); + keyword_to_flags_map[alias] = start_node->flags; + } + + for (auto & child : start_node->children) + makeKeywordToFlagsMap(child.get()); + } + + void makeAccessTypeToFlagsMapping(Node * start_node = nullptr) + { + if (!start_node) + { + makeAccessTypeToFlagsMapping(none_node.get()); + start_node = flags_to_keyword_tree.get(); + } + + size_t index = static_cast(start_node->type); + access_type_to_flags_mapping.resize(std::max(index + 1, access_type_to_flags_mapping.size())); + access_type_to_flags_mapping[index] = start_node->flags; + + for (auto & child : start_node->children) + makeAccessTypeToFlagsMapping(child.get()); + } + + void collectAllFlags(const Node * start_node = nullptr) + { + if (!start_node) + { + start_node = flags_to_keyword_tree.get(); + all_flags = start_node->flags; + } + if (start_node->node_type != GROUP) + { + assert(static_cast(start_node->node_type) < std::size(all_flags_for_target)); + all_flags_for_target[start_node->node_type] |= start_node->flags; + } + for (const auto & child : start_node->children) + collectAllFlags(child.get()); + } + + Impl() + { + makeFlagsToKeywordTree(); + makeKeywordToFlagsMap(); + makeAccessTypeToFlagsMapping(); + collectAllFlags(); + } + static void flagsToKeywordsRec(const Flags & flags_, std::vector & keywords, const Node & start_node) { Flags matching_flags = (flags_ & start_node.flags); @@ -243,275 +395,12 @@ private: } } - static NodePtr makeFlagsToKeywordTree() - { - size_t next_flag = 0; - Nodes all; - - auto show_databases = std::make_unique("SHOW DATABASES", next_flag++, DATABASE); - auto show_tables = std::make_unique("SHOW TABLES", next_flag++, TABLE); - auto show_columns = std::make_unique("SHOW COLUMNS", next_flag++, COLUMN); - auto show_dictionaries = std::make_unique("SHOW DICTIONARIES", next_flag++, DICTIONARY); - auto show = std::make_unique("SHOW", std::move(show_databases), std::move(show_tables), std::move(show_columns), std::move(show_dictionaries)); - ext::push_back(all, std::move(show)); - - auto select = std::make_unique("SELECT", next_flag++, COLUMN); - auto insert = std::make_unique("INSERT", next_flag++, COLUMN); - ext::push_back(all, std::move(select), std::move(insert)); - - auto update = std::make_unique("UPDATE", next_flag++, COLUMN); - ext::push_back(update->aliases, "ALTER UPDATE"); - auto delet = std::make_unique("DELETE", next_flag++, TABLE); - ext::push_back(delet->aliases, "ALTER DELETE"); - - auto add_column = std::make_unique("ADD COLUMN", next_flag++, COLUMN); - add_column->aliases.push_back("ALTER ADD COLUMN"); - auto modify_column = std::make_unique("MODIFY COLUMN", next_flag++, COLUMN); - modify_column->aliases.push_back("ALTER MODIFY COLUMN"); - auto drop_column = std::make_unique("DROP COLUMN", next_flag++, COLUMN); - drop_column->aliases.push_back("ALTER DROP COLUMN"); - auto comment_column = std::make_unique("COMMENT COLUMN", next_flag++, COLUMN); - comment_column->aliases.push_back("ALTER COMMENT COLUMN"); - auto clear_column = std::make_unique("CLEAR COLUMN", next_flag++, COLUMN); - clear_column->aliases.push_back("ALTER CLEAR COLUMN"); - auto rename_column = std::make_unique("RENAME COLUMN", next_flag++, COLUMN); - rename_column->aliases.push_back("ALTER RENAME COLUMN"); - - auto alter_column = std::make_unique( - "ALTER COLUMN", - std::move(add_column), - std::move(modify_column), - std::move(drop_column), - std::move(comment_column), - std::move(clear_column), - std::move(rename_column)); - - auto alter_order_by = std::make_unique("ALTER ORDER BY", next_flag++, TABLE); - alter_order_by->aliases.push_back("MODIFY ORDER BY"); - alter_order_by->aliases.push_back("ALTER MODIFY ORDER BY"); - auto add_index = std::make_unique("ADD INDEX", next_flag++, TABLE); - add_index->aliases.push_back("ALTER ADD INDEX"); - auto drop_index = std::make_unique("DROP INDEX", next_flag++, TABLE); - drop_index->aliases.push_back("ALTER DROP INDEX"); - auto materialize_index = std::make_unique("MATERIALIZE INDEX", next_flag++, TABLE); - materialize_index->aliases.push_back("ALTER MATERIALIZE INDEX"); - auto clear_index = std::make_unique("CLEAR INDEX", next_flag++, TABLE); - clear_index->aliases.push_back("ALTER CLEAR INDEX"); - auto index = std::make_unique("INDEX", std::move(alter_order_by), std::move(add_index), std::move(drop_index), std::move(materialize_index), std::move(clear_index)); - index->aliases.push_back("ALTER INDEX"); - - auto add_constraint = std::make_unique("ADD CONSTRAINT", next_flag++, TABLE); - add_constraint->aliases.push_back("ALTER ADD CONSTRAINT"); - auto drop_constraint = std::make_unique("DROP CONSTRAINT", next_flag++, TABLE); - drop_constraint->aliases.push_back("ALTER DROP CONSTRAINT"); - auto alter_constraint = std::make_unique("CONSTRAINT", std::move(add_constraint), std::move(drop_constraint)); - alter_constraint->aliases.push_back("ALTER CONSTRAINT"); - - auto modify_ttl = std::make_unique("MODIFY TTL", next_flag++, TABLE); - modify_ttl->aliases.push_back("ALTER MODIFY TTL"); - auto materialize_ttl = std::make_unique("MATERIALIZE TTL", next_flag++, TABLE); - materialize_ttl->aliases.push_back("ALTER MATERIALIZE TTL"); - - auto modify_setting = std::make_unique("MODIFY SETTING", next_flag++, TABLE); - modify_setting->aliases.push_back("ALTER MODIFY SETTING"); - - auto move_partition = std::make_unique("MOVE PARTITION", next_flag++, TABLE); - ext::push_back(move_partition->aliases, "ALTER MOVE PARTITION", "MOVE PART", "ALTER MOVE PART"); - auto fetch_partition = std::make_unique("FETCH PARTITION", next_flag++, TABLE); - ext::push_back(fetch_partition->aliases, "ALTER FETCH PARTITION"); - auto freeze_partition = std::make_unique("FREEZE PARTITION", next_flag++, TABLE); - ext::push_back(freeze_partition->aliases, "ALTER FREEZE PARTITION"); - - auto alter_table = std::make_unique("ALTER TABLE", std::move(update), std::move(delet), std::move(alter_column), std::move(index), std::move(alter_constraint), std::move(modify_ttl), std::move(materialize_ttl), std::move(modify_setting), std::move(move_partition), std::move(fetch_partition), std::move(freeze_partition)); - - auto refresh_view = std::make_unique("REFRESH VIEW", next_flag++, VIEW); - ext::push_back(refresh_view->aliases, "ALTER LIVE VIEW REFRESH"); - auto modify_view_query = std::make_unique("MODIFY VIEW QUERY", next_flag++, VIEW); - auto alter_view = std::make_unique("ALTER VIEW", std::move(refresh_view), std::move(modify_view_query)); - - auto alter = std::make_unique("ALTER", std::move(alter_table), std::move(alter_view)); - ext::push_back(all, std::move(alter)); - - auto create_database = std::make_unique("CREATE DATABASE", next_flag++, DATABASE); - auto create_table = std::make_unique("CREATE TABLE", next_flag++, TABLE); - auto create_view = std::make_unique("CREATE VIEW", next_flag++, VIEW); - auto create_dictionary = std::make_unique("CREATE DICTIONARY", next_flag++, DICTIONARY); - auto create = std::make_unique("CREATE", std::move(create_database), std::move(create_table), std::move(create_view), std::move(create_dictionary)); - ext::push_back(all, std::move(create)); - - auto create_temporary_table = std::make_unique("CREATE TEMPORARY TABLE", next_flag++, GLOBAL); - ext::push_back(all, std::move(create_temporary_table)); - - auto drop_database = std::make_unique("DROP DATABASE", next_flag++, DATABASE); - auto drop_table = std::make_unique("DROP TABLE", next_flag++, TABLE); - auto drop_view = std::make_unique("DROP VIEW", next_flag++, VIEW); - auto drop_dictionary = std::make_unique("DROP DICTIONARY", next_flag++, DICTIONARY); - auto drop = std::make_unique("DROP", std::move(drop_database), std::move(drop_table), std::move(drop_view), std::move(drop_dictionary)); - ext::push_back(all, std::move(drop)); - - auto truncate_table = std::make_unique("TRUNCATE TABLE", next_flag++, TABLE); - auto truncate_view = std::make_unique("TRUNCATE VIEW", next_flag++, VIEW); - auto truncate = std::make_unique("TRUNCATE", std::move(truncate_table), std::move(truncate_view)); - ext::push_back(all, std::move(truncate)); - - auto optimize = std::make_unique("OPTIMIZE", next_flag++, TABLE); - optimize->aliases.push_back("OPTIMIZE TABLE"); - ext::push_back(all, std::move(optimize)); - - auto kill_query = std::make_unique("KILL QUERY", next_flag++, GLOBAL); - ext::push_back(all, std::move(kill_query)); - - auto create_user = std::make_unique("CREATE USER", next_flag++, GLOBAL); - auto alter_user = std::make_unique("ALTER USER", next_flag++, GLOBAL); - auto drop_user = std::make_unique("DROP USER", next_flag++, GLOBAL); - auto create_role = std::make_unique("CREATE ROLE", next_flag++, GLOBAL); - auto alter_role = std::make_unique("ALTER ROLE", next_flag++, GLOBAL); - auto drop_role = std::make_unique("DROP ROLE", next_flag++, GLOBAL); - auto create_policy = std::make_unique("CREATE POLICY", next_flag++, GLOBAL); - auto alter_policy = std::make_unique("ALTER POLICY", next_flag++, GLOBAL); - auto drop_policy = std::make_unique("DROP POLICY", next_flag++, GLOBAL); - auto create_quota = std::make_unique("CREATE QUOTA", next_flag++, GLOBAL); - auto alter_quota = std::make_unique("ALTER QUOTA", next_flag++, GLOBAL); - auto drop_quota = std::make_unique("DROP QUOTA", next_flag++, GLOBAL); - auto create_profile = std::make_unique("CREATE SETTINGS PROFILE", next_flag++, GLOBAL); - ext::push_back(create_profile->aliases, "CREATE PROFILE"); - auto alter_profile = std::make_unique("ALTER SETTINGS PROFILE", next_flag++, GLOBAL); - ext::push_back(alter_profile->aliases, "ALTER PROFILE"); - auto drop_profile = std::make_unique("DROP SETTINGS PROFILE", next_flag++, GLOBAL); - ext::push_back(drop_profile->aliases, "DROP PROFILE"); - auto role_admin = std::make_unique("ROLE ADMIN", next_flag++, GLOBAL); - ext::push_back(all, std::move(create_user), std::move(alter_user), std::move(drop_user), std::move(create_role), std::move(alter_role), std::move(drop_role), std::move(create_policy), std::move(alter_policy), std::move(drop_policy), std::move(create_quota), std::move(alter_quota), std::move(drop_quota), std::move(create_profile), std::move(alter_profile), std::move(drop_profile), std::move(role_admin)); - - auto shutdown = std::make_unique("SHUTDOWN", next_flag++, GLOBAL); - ext::push_back(shutdown->aliases, "SYSTEM SHUTDOWN", "SYSTEM KILL"); - auto drop_cache = std::make_unique("DROP CACHE", next_flag++, GLOBAL); - ext::push_back(drop_cache->aliases, "SYSTEM DROP CACHE", "DROP DNS CACHE", "SYSTEM DROP DNS CACHE", "DROP MARK CACHE", "SYSTEM DROP MARK CACHE", "DROP UNCOMPRESSED CACHE", "SYSTEM DROP UNCOMPRESSED CACHE", "DROP COMPILED EXPRESSION CACHE", "SYSTEM DROP COMPILED EXPRESSION CACHE"); - auto reload_config = std::make_unique("RELOAD CONFIG", next_flag++, GLOBAL); - ext::push_back(reload_config->aliases, "SYSTEM RELOAD CONFIG"); - auto reload_dictionary = std::make_unique("RELOAD DICTIONARY", next_flag++, GLOBAL); - ext::push_back(reload_dictionary->aliases, "SYSTEM RELOAD DICTIONARY", "RELOAD DICTIONARIES", "SYSTEM RELOAD DICTIONARIES", "RELOAD EMBEDDED DICTIONARIES", "SYSTEM RELOAD EMBEDDED DICTIONARIES"); - auto stop_merges = std::make_unique("STOP MERGES", next_flag++, TABLE); - ext::push_back(stop_merges->aliases, "SYSTEM STOP MERGES", "START MERGES", "SYSTEM START MERGES"); - auto stop_ttl_merges = std::make_unique("STOP TTL MERGES", next_flag++, TABLE); - ext::push_back(stop_ttl_merges->aliases, "SYSTEM STOP TTL MERGES", "START TTL MERGES", "SYSTEM START TTL MERGES"); - auto stop_fetches = std::make_unique("STOP FETCHES", next_flag++, TABLE); - ext::push_back(stop_fetches->aliases, "SYSTEM STOP FETCHES", "START FETCHES", "SYSTEM START FETCHES"); - auto stop_moves = std::make_unique("STOP MOVES", next_flag++, TABLE); - ext::push_back(stop_moves->aliases, "SYSTEM STOP MOVES", "START MOVES", "SYSTEM START MOVES"); - auto stop_distributed_sends = std::make_unique("STOP DISTRIBUTED SENDS", next_flag++, TABLE); - ext::push_back(stop_distributed_sends->aliases, "SYSTEM STOP DISTRIBUTED SENDS", "START DISTRIBUTED SENDS", "SYSTEM START DISTRIBUTED SENDS"); - auto stop_replicated_sends = std::make_unique("STOP REPLICATED SENDS", next_flag++, TABLE); - ext::push_back(stop_replicated_sends->aliases, "SYSTEM STOP REPLICATED SENDS", "START REPLICATED SENDS", "SYSTEM START REPLICATED SENDS"); - auto stop_replication_queues = std::make_unique("STOP REPLICATION QUEUES", next_flag++, TABLE); - ext::push_back(stop_replication_queues->aliases, "SYSTEM STOP REPLICATION QUEUES", "START REPLICATION QUEUES", "SYSTEM START REPLICATION QUEUES"); - auto sync_replica = std::make_unique("SYNC REPLICA", next_flag++, TABLE); - ext::push_back(sync_replica->aliases, "SYSTEM SYNC REPLICA"); - auto restart_replica = std::make_unique("RESTART REPLICA", next_flag++, TABLE); - ext::push_back(restart_replica->aliases, "SYSTEM RESTART REPLICA"); - auto flush_distributed = std::make_unique("FLUSH DISTRIBUTED", next_flag++, TABLE); - ext::push_back(flush_distributed->aliases, "SYSTEM FLUSH DISTRIBUTED"); - auto flush_logs = std::make_unique("FLUSH LOGS", next_flag++, GLOBAL); - ext::push_back(flush_logs->aliases, "SYSTEM FLUSH LOGS"); - auto system = std::make_unique("SYSTEM", std::move(shutdown), std::move(drop_cache), std::move(reload_config), std::move(reload_dictionary), std::move(stop_merges), std::move(stop_ttl_merges), std::move(stop_fetches), std::move(stop_moves), std::move(stop_distributed_sends), std::move(stop_replicated_sends), std::move(stop_replication_queues), std::move(sync_replica), std::move(restart_replica), std::move(flush_distributed), std::move(flush_logs)); - ext::push_back(all, std::move(system)); - - auto dict_get = std::make_unique("dictGet()", next_flag++, DICTIONARY); - dict_get->aliases.push_back("dictHas()"); - dict_get->aliases.push_back("dictGetHierarchy()"); - dict_get->aliases.push_back("dictIsIn()"); - ext::push_back(all, std::move(dict_get)); - - auto address_to_line = std::make_unique("addressToLine()", next_flag++, GLOBAL); - auto address_to_symbol = std::make_unique("addressToSymbol()", next_flag++, GLOBAL); - auto demangle = std::make_unique("demangle()", next_flag++, GLOBAL); - auto introspection = std::make_unique("INTROSPECTION", std::move(address_to_line), std::move(address_to_symbol), std::move(demangle)); - ext::push_back(introspection->aliases, "INTROSPECTION FUNCTIONS"); - ext::push_back(all, std::move(introspection)); - - auto file = std::make_unique("file()", next_flag++, GLOBAL); - auto url = std::make_unique("url()", next_flag++, GLOBAL); - auto input = std::make_unique("input()", next_flag++, GLOBAL); - auto values = std::make_unique("values()", next_flag++, GLOBAL); - auto numbers = std::make_unique("numbers()", next_flag++, GLOBAL); - auto zeros = std::make_unique("zeros()", next_flag++, GLOBAL); - auto merge = std::make_unique("merge()", next_flag++, DATABASE); - auto remote = std::make_unique("remote()", next_flag++, GLOBAL); - ext::push_back(remote->aliases, "remoteSecure()", "cluster()"); - auto mysql = std::make_unique("mysql()", next_flag++, GLOBAL); - auto odbc = std::make_unique("odbc()", next_flag++, GLOBAL); - auto jdbc = std::make_unique("jdbc()", next_flag++, GLOBAL); - auto hdfs = std::make_unique("hdfs()", next_flag++, GLOBAL); - auto s3 = std::make_unique("s3()", next_flag++, GLOBAL); - auto table_functions = std::make_unique("TABLE FUNCTIONS", std::move(file), std::move(url), std::move(input), std::move(values), std::move(numbers), std::move(zeros), std::move(merge), std::move(remote), std::move(mysql), std::move(odbc), std::move(jdbc), std::move(hdfs), std::move(s3)); - ext::push_back(all, std::move(table_functions)); - - auto node_all = std::make_unique("ALL", std::move(all)); - node_all->aliases.push_back("ALL PRIVILEGES"); - return node_all; - } - - void makeKeywordToFlagsMap(Node * start_node = nullptr) - { - if (!start_node) - { - start_node = flags_to_keyword_tree.get(); - keyword_to_flags_map["USAGE"] = {}; - keyword_to_flags_map["NONE"] = {}; - keyword_to_flags_map["NO PRIVILEGES"] = {}; - } - start_node->aliases.emplace_back(start_node->keyword); - for (auto & alias : start_node->aliases) - { - boost::to_upper(alias); - keyword_to_flags_map[alias] = start_node->flags; - } - for (auto & child : start_node->children) - makeKeywordToFlagsMap(child.get()); - } - - void makeAccessTypeToFlagsMapping() - { - access_type_to_flags_mapping.resize(MAX_ACCESS_TYPE); - for (auto access_type : ext::range_with_static_cast(0, MAX_ACCESS_TYPE)) - { - auto str = toKeyword(access_type); - auto it = keyword_to_flags_map.find(str); - if (it == keyword_to_flags_map.end()) - { - String uppercased{str}; - boost::to_upper(uppercased); - it = keyword_to_flags_map.find(uppercased); - } - access_type_to_flags_mapping[static_cast(access_type)] = it->second; - } - } - - void collectAllFlags(const Node * start_node = nullptr) - { - if (!start_node) - { - start_node = flags_to_keyword_tree.get(); - all_flags = start_node->flags; - } - if (start_node->target != UNKNOWN_TARGET) - all_flags_for_target[start_node->target] |= start_node->flags; - for (const auto & child : start_node->children) - collectAllFlags(child.get()); - } - - Impl() - { - flags_to_keyword_tree = makeFlagsToKeywordTree(); - makeKeywordToFlagsMap(); - makeAccessTypeToFlagsMapping(); - collectAllFlags(); - } - - std::unique_ptr flags_to_keyword_tree; + NodePtr flags_to_keyword_tree; + NodePtr none_node; std::unordered_map keyword_to_flags_map; std::vector access_type_to_flags_mapping; Flags all_flags; - Flags all_flags_for_target[NUM_TARGETS]; + Flags all_flags_for_target[static_cast(DICTIONARY) + 1]; }; diff --git a/src/Access/AccessRights.cpp b/src/Access/AccessRights.cpp index 6f94cfac286..9c3b5e36ec8 100644 --- a/src/Access/AccessRights.cpp +++ b/src/Access/AccessRights.cpp @@ -49,10 +49,13 @@ namespace const AccessFlags create_temporary_table_flag = AccessType::CREATE_TEMPORARY_TABLE; const AccessFlags alter_table_flag = AccessType::ALTER_TABLE; const AccessFlags alter_view_flag = AccessType::ALTER_VIEW; - const AccessFlags truncate_table_flag = AccessType::TRUNCATE_TABLE; - const AccessFlags truncate_view_flag = AccessType::TRUNCATE_VIEW; + const AccessFlags truncate_flag = AccessType::TRUNCATE; const AccessFlags drop_table_flag = AccessType::DROP_TABLE; const AccessFlags drop_view_flag = AccessType::DROP_VIEW; + const AccessFlags alter_ttl_flag = AccessType::ALTER_TTL; + const AccessFlags alter_materialize_ttl_flag = AccessType::ALTER_MATERIALIZE_TTL; + const AccessFlags system_reload_dictionary = AccessType::SYSTEM_RELOAD_DICTIONARY; + const AccessFlags system_reload_embedded_dictionaries = AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES; }; std::string_view checkCurrentDatabase(const std::string_view & current_database) @@ -413,8 +416,14 @@ private: implicit_access |= helper.show_tables_flag; } - if ((level == GLOBAL_LEVEL) && ((access | max_access_among_children) & helper.create_table_flag)) - implicit_access |= helper.create_temporary_table_flag; + if (level == GLOBAL_LEVEL) + { + if ((access | max_access_among_children) & helper.create_table_flag) + implicit_access |= helper.create_temporary_table_flag; + + if (access & helper.system_reload_dictionary) + implicit_access |= helper.system_reload_embedded_dictionaries; + } if (level <= TABLE_LEVEL) { @@ -427,8 +436,8 @@ private: if (access & helper.alter_table_flag) implicit_access |= helper.alter_view_flag; - if (access & helper.truncate_table_flag) - implicit_access |= helper.truncate_view_flag; + if (access & helper.alter_ttl_flag) + implicit_access |= helper.alter_materialize_ttl_flag; } final_access = access | implicit_access; diff --git a/src/Access/AccessType.h b/src/Access/AccessType.h index df8839f64ce..d0665a6e55f 100644 --- a/src/Access/AccessType.h +++ b/src/Access/AccessType.h @@ -11,139 +11,162 @@ namespace DB /// Represents an access type which can be granted on databases, tables, columns, etc. enum class AccessType { - NONE, /// no access - ALL, /// full access +/// Macro M should be defined as M(name, aliases, node_type, parent_group_name) +/// where name is identifier with underscores (instead of spaces); +/// aliases is a string containing comma-separated list; +/// node_type either specifies access type's level (GLOBAL/DATABASE/TABLE/DICTIONARY/VIEW/COLUMNS), +/// or specifies that the access type is a GROUP of other access types; +/// parent_group_name is the name of the group containing this access type (or NONE if there is no such group). +#define APPLY_FOR_ACCESS_TYPES(M) \ + M(SHOW_DATABASES, "", DATABASE, SHOW) /* allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE ; + implicitly enabled by any grant on the database */\ + M(SHOW_TABLES, "", TABLE, SHOW) /* allows to execute SHOW TABLES, EXISTS , CHECK
; + implicitly enabled by any grant on the table */\ + M(SHOW_COLUMNS, "", COLUMN, SHOW) /* allows to execute SHOW CREATE TABLE, DESCRIBE; + implicitly enabled with any grant on the column */\ + M(SHOW_DICTIONARIES, "", DICTIONARY, SHOW) /* allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS ; + implicitly enabled by any grant on the dictionary */\ + M(SHOW, "", GROUP, ALL) /* allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE */\ + \ + M(SELECT, "", COLUMN, ALL) \ + M(INSERT, "", COLUMN, ALL) \ + M(ALTER_UPDATE, "UPDATE", COLUMN, ALTER_TABLE) /* allows to execute ALTER UPDATE */\ + M(ALTER_DELETE, "DELETE", COLUMN, ALTER_TABLE) /* allows to execute ALTER DELETE */\ + \ + M(ALTER_ADD_COLUMN, "ADD COLUMN", COLUMN, ALTER_COLUMN) \ + M(ALTER_MODIFY_COLUMN, "MODIFY COLUMN", COLUMN, ALTER_COLUMN) \ + M(ALTER_DROP_COLUMN, "DROP COLUMN", COLUMN, ALTER_COLUMN) \ + M(ALTER_COMMENT_COLUMN, "COMMENT COLUMN", COLUMN, ALTER_COLUMN) \ + M(ALTER_CLEAR_COLUMN, "CLEAR COLUMN", COLUMN, ALTER_COLUMN) \ + M(ALTER_RENAME_COLUMN, "RENAME COLUMN", COLUMN, ALTER_COLUMN) \ + M(ALTER_COLUMN, "", GROUP, ALTER_TABLE) /* allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN */\ + \ + M(ALTER_ORDER_BY, "ALTER MODIFY ORDER BY, MODIFY ORDER BY", TABLE, ALTER_INDEX) \ + M(ALTER_ADD_INDEX, "ADD INDEX", TABLE, ALTER_INDEX) \ + M(ALTER_DROP_INDEX, "DROP INDEX", TABLE, ALTER_INDEX) \ + M(ALTER_MATERIALIZE_INDEX, "MATERIALIZE INDEX", TABLE, ALTER_INDEX) \ + M(ALTER_CLEAR_INDEX, "CLEAR INDEX", TABLE, ALTER_INDEX) \ + M(ALTER_INDEX, "INDEX", GROUP, ALTER_TABLE) /* allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX */\ + \ + M(ALTER_ADD_CONSTRAINT, "ADD CONSTRAINT", TABLE, ALTER_CONSTRAINT) \ + M(ALTER_DROP_CONSTRAINT, "DROP CONSTRAINT", TABLE, ALTER_CONSTRAINT) \ + M(ALTER_CONSTRAINT, "CONSTRAINT", GROUP, ALTER_TABLE) /* allows to execute ALTER {ADD|DROP} CONSTRAINT */\ + \ + M(ALTER_TTL, "ALTER MODIFY TTL, MODIFY TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY TTL */\ + M(ALTER_MATERIALIZE_TTL, "MATERIALIZE TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MATERIALIZE TTL; + enabled implicitly by the grant ALTER_TABLE */\ + M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\ + M(ALTER_MOVE_PARTITION, "ALTER MOVE PART, MOVE PARTITION, MOVE PART", TABLE, ALTER_TABLE) \ + M(ALTER_FETCH_PARTITION, "FETCH PARTITION", TABLE, ALTER_TABLE) \ + M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION", TABLE, ALTER_TABLE) \ + \ + M(ALTER_TABLE, "", GROUP, ALTER) \ + \ + M(ALTER_VIEW_REFRESH, "ALTER LIVE VIEW REFRESH, REFRESH VIEW", VIEW, ALTER_VIEW) \ + M(ALTER_VIEW_MODIFY_QUERY, "ALTER TABLE MODIFY QUERY", VIEW, ALTER_VIEW) \ + M(ALTER_VIEW, "", GROUP, ALTER) /* allows to execute ALTER VIEW REFRESH, ALTER VIEW MODIFY QUERY; + implicitly enabled by the grant ALTER_TABLE */\ + \ + M(ALTER, "", GROUP, ALL) /* allows to execute ALTER {TABLE|LIVE VIEW} */\ + \ + M(CREATE_DATABASE, "", DATABASE, CREATE) /* allows to execute {CREATE|ATTACH} DATABASE */\ + M(CREATE_TABLE, "", TABLE, CREATE) /* allows to execute {CREATE|ATTACH} {TABLE|VIEW} */\ + M(CREATE_VIEW, "", VIEW, CREATE) /* allows to execute {CREATE|ATTACH} VIEW; + implicitly enabled by the grant CREATE_TABLE */\ + M(CREATE_DICTIONARY, "", DICTIONARY, CREATE) /* allows to execute {CREATE|ATTACH} DICTIONARY */\ + M(CREATE_TEMPORARY_TABLE, "", GLOBAL, CREATE) /* allows to create and manipulate temporary tables; + implicitly enabled by the grant CREATE_TABLE on any table */ \ + M(CREATE, "", GROUP, ALL) /* allows to execute {CREATE|ATTACH} */ \ + \ + M(DROP_DATABASE, "", DATABASE, DROP) /* allows to execute {DROP|DETACH} DATABASE */\ + M(DROP_TABLE, "", TABLE, DROP) /* allows to execute {DROP|DETACH} TABLE */\ + M(DROP_VIEW, "", VIEW, DROP) /* allows to execute {DROP|DETACH} TABLE for views; + implicitly enabled by the grant DROP_TABLE */\ + M(DROP_DICTIONARY, "", DICTIONARY, DROP) /* allows to execute {DROP|DETACH} DICTIONARY */\ + M(DROP, "", GROUP, ALL) /* allows to execute {DROP|DETACH} */\ + \ + M(TRUNCATE, "TRUNCATE TABLE", TABLE, ALL) \ + M(OPTIMIZE, "OPTIMIZE TABLE", TABLE, ALL) \ + \ + M(KILL_QUERY, "", GLOBAL, ALL) /* allows to kill a query started by another user + (anyone can kill his own queries) */\ + \ + M(CREATE_USER, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(ALTER_USER, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(DROP_USER, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(CREATE_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(ALTER_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(DROP_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(ROLE_ADMIN, "", GLOBAL, ACCESS_MANAGEMENT) /* allows to grant and revoke the roles which are not granted to the current user with admin option */\ + M(CREATE_ROW_POLICY, "CREATE POLICY", GLOBAL, ACCESS_MANAGEMENT) \ + M(ALTER_ROW_POLICY, "ALTER POLICY", GLOBAL, ACCESS_MANAGEMENT) \ + M(DROP_ROW_POLICY, "DROP POLICY", GLOBAL, ACCESS_MANAGEMENT) \ + M(CREATE_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(ALTER_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(DROP_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \ + M(CREATE_SETTINGS_PROFILE, "CREATE PROFILE", GLOBAL, ACCESS_MANAGEMENT) \ + M(ALTER_SETTINGS_PROFILE, "ALTER PROFILE", GLOBAL, ACCESS_MANAGEMENT) \ + M(DROP_SETTINGS_PROFILE, "DROP PROFILE", GLOBAL, ACCESS_MANAGEMENT) \ + M(SHOW_USERS, "SHOW CREATE USER", GLOBAL, SHOW_ACCESS) \ + M(SHOW_ROLES, "SHOW CREATE ROLE", GLOBAL, SHOW_ACCESS) \ + M(SHOW_ROW_POLICIES, "SHOW POLICIES, SHOW CREATE ROW POLICY, SHOW CREATE POLICY", GLOBAL, SHOW_ACCESS) \ + M(SHOW_QUOTAS, "SHOW CREATE QUOTA", GLOBAL, SHOW_ACCESS) \ + M(SHOW_SETTINGS_PROFILES, "SHOW PROFILES, SHOW CREATE SETTINGS PROFILE, SHOW CREATE PROFILE", GLOBAL, SHOW_ACCESS) \ + M(SHOW_ACCESS, "", GROUP, ACCESS_MANAGEMENT) \ + M(ACCESS_MANAGEMENT, "", GROUP, ALL) \ + \ + M(SYSTEM_SHUTDOWN, "SYSTEM KILL, SHUTDOWN", GLOBAL, SYSTEM) \ + M(SYSTEM_DROP_DNS_CACHE, "SYSTEM DROP DNS, DROP DNS CACHE, DROP DNS", GLOBAL, SYSTEM_DROP_CACHE) \ + M(SYSTEM_DROP_MARK_CACHE, "SYSTEM DROP MARK, DROP MARK CACHE, DROP MARKS", GLOBAL, SYSTEM_DROP_CACHE) \ + M(SYSTEM_DROP_UNCOMPRESSED_CACHE, "SYSTEM DROP UNCOMPRESSED, DROP UNCOMPRESSED CACHE, DROP UNCOMPRESSED", GLOBAL, SYSTEM_DROP_CACHE) \ + M(SYSTEM_DROP_COMPILED_EXPRESSION_CACHE, "SYSTEM DROP COMPILED EXPRESSION, DROP COMPILED EXPRESSION CACHE, DROP COMPILED EXPRESSIONS", GLOBAL, SYSTEM_DROP_CACHE) \ + M(SYSTEM_DROP_CACHE, "DROP CACHE", GROUP, SYSTEM) \ + M(SYSTEM_RELOAD_CONFIG, "RELOAD CONFIG", GLOBAL, SYSTEM_RELOAD) \ + M(SYSTEM_RELOAD_DICTIONARY, "SYSTEM RELOAD DICTIONARIES, RELOAD DICTIONARY, RELOAD DICTIONARIES", GLOBAL, SYSTEM_RELOAD) \ + M(SYSTEM_RELOAD_EMBEDDED_DICTIONARIES, "RELOAD EMBEDDED DICTIONARIES", GLOBAL, SYSTEM_RELOAD) /* implicitly enabled by the grant SYSTEM_RELOAD_DICTIONARY ON *.* */\ + M(SYSTEM_RELOAD, "", GROUP, SYSTEM) \ + M(SYSTEM_MERGES, "SYSTEM STOP MERGES, SYSTEM START MERGES, STOP_MERGES, START MERGES", TABLE, SYSTEM) \ + M(SYSTEM_TTL_MERGES, "SYSTEM STOP TTL MERGES, SYSTEM START TTL MERGES, STOP TTL MERGES, START TTL MERGES", TABLE, SYSTEM) \ + M(SYSTEM_FETCHES, "SYSTEM STOP FETCHES, SYSTEM START FETCHES, STOP FETCHES, START FETCHES", TABLE, SYSTEM) \ + M(SYSTEM_MOVES, "SYSTEM STOP MOVES, SYSTEM START MOVES, STOP MOVES, START MOVES", TABLE, SYSTEM) \ + M(SYSTEM_DISTRIBUTED_SENDS, "SYSTEM STOP DISTRIBUTED SENDS, SYSTEM START DISTRIBUTED SENDS, STOP DISTRIBUTED SENDS, START DISTRIBUTED SENDS", TABLE, SYSTEM_SENDS) \ + M(SYSTEM_REPLICATED_SENDS, "SYSTEM STOP REPLICATED SENDS, SYSTEM START REPLICATED SENDS, STOP_REPLICATED_SENDS, START REPLICATED SENDS", TABLE, SYSTEM_SENDS) \ + M(SYSTEM_SENDS, "SYSTEM STOP SENDS, SYSTEM START SENDS, STOP SENDS, START SENDS", GROUP, SYSTEM) \ + M(SYSTEM_REPLICATION_QUEUES, "SYSTEM STOP REPLICATION QUEUES, SYSTEM START REPLICATION QUEUES, STOP_REPLICATION_QUEUES, START REPLICATION QUEUES", TABLE, SYSTEM) \ + M(SYSTEM_SYNC_REPLICA, "SYNC REPLICA", TABLE, SYSTEM) \ + M(SYSTEM_RESTART_REPLICA, "RESTART REPLICA", TABLE, SYSTEM) \ + M(SYSTEM_FLUSH_DISTRIBUTED, "FLUSH DISTRIBUTED", TABLE, SYSTEM_FLUSH) \ + M(SYSTEM_FLUSH_LOGS, "FLUSH LOGS", GLOBAL, SYSTEM_FLUSH) \ + M(SYSTEM_FLUSH, "", GROUP, SYSTEM) \ + M(SYSTEM, "", GROUP, ALL) /* allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...} */ \ + \ + M(dictGet, "dictHas, dictGetHierarchy, dictIsIn", DICTIONARY, ALL) /* allows to execute functions dictGet(), dictHas(), dictGetHierarchy(), dictIsIn() */\ + \ + M(addressToLine, "", GLOBAL, INTROSPECTION) /* allows to execute function addressToLine() */\ + M(addressToSymbol, "", GLOBAL, INTROSPECTION) /* allows to execute function addressToSymbol() */\ + M(demangle, "", GLOBAL, INTROSPECTION) /* allows to execute function demangle() */\ + M(INTROSPECTION, "INTROSPECTION FUNCTIONS", GROUP, ALL) /* allows to execute functions addressToLine(), addressToSymbol(), demangle()*/\ + \ + M(FILE, "", GLOBAL, SOURCES) \ + M(URL, "", GLOBAL, SOURCES) \ + M(REMOTE, "", GLOBAL, SOURCES) \ + M(MYSQL, "", GLOBAL, SOURCES) \ + M(ODBC, "", GLOBAL, SOURCES) \ + M(JDBC, "", GLOBAL, SOURCES) \ + M(HDFS, "", GLOBAL, SOURCES) \ + M(S3, "", GLOBAL, SOURCES) \ + M(SOURCES, "", GROUP, ALL) \ + \ + M(ALL, "ALL PRIVILEGES", GROUP, NONE) /* full access */ \ + M(NONE, "USAGE, NO PRIVILEGES", GROUP, NONE) /* no access */ - SHOW_DATABASES, /// allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE - SHOW_TABLES, /// allows to execute SHOW TABLES, EXISTS
, CHECK
- SHOW_COLUMNS, /// allows to execute SHOW CREATE TABLE, DESCRIBE - SHOW_DICTIONARIES, /// allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS - SHOW, /// allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE +#define DECLARE_ACCESS_TYPE_ENUM_CONST(name, aliases, node_type, parent_group_name) \ + name, - SELECT, - INSERT, - UPDATE, /// allows to execute ALTER UPDATE - DELETE, /// allows to execute ALTER DELETE - - ADD_COLUMN, - DROP_COLUMN, - MODIFY_COLUMN, - COMMENT_COLUMN, - CLEAR_COLUMN, - RENAME_COLUMN, - ALTER_COLUMN, /// allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN - - ALTER_ORDER_BY, - ADD_INDEX, - DROP_INDEX, - MATERIALIZE_INDEX, - CLEAR_INDEX, - INDEX, /// allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX - - ADD_CONSTRAINT, - DROP_CONSTRAINT, - ALTER_CONSTRAINT, /// allows to execute ALTER {ADD|DROP} CONSTRAINT - - MODIFY_TTL, /// allows to execute ALTER MODIFY TTL - MATERIALIZE_TTL, /// allows to execute ALTER MATERIALIZE TTL - MODIFY_SETTING, /// allows to execute ALTER MODIFY SETTING - - MOVE_PARTITION, - FETCH_PARTITION, - FREEZE_PARTITION, - - ALTER_TABLE, /// allows to execute ALTER TABLE ... - - REFRESH_VIEW, /// allows to execute ALTER LIVE VIEW REFRESH - MODIFY_VIEW_QUERY, /// allows to execute ALTER TABLE MODIFY QUERY - ALTER_VIEW, /// allows to execute ALTER LIVE VIEW REFRESH, ALTER TABLE MODIFY QUERY - - ALTER, /// allows to execute ALTER {TABLE|LIVE VIEW} ... - - CREATE_DATABASE, /// allows to execute {CREATE|ATTACH} DATABASE - CREATE_TABLE, /// allows to execute {CREATE|ATTACH} TABLE - CREATE_VIEW, /// allows to execute {CREATE|ATTACH} VIEW - CREATE_DICTIONARY, /// allows to execute {CREATE|ATTACH} DICTIONARY - CREATE_TEMPORARY_TABLE, /// allows to create and manipulate temporary tables and views. - CREATE, /// allows to execute {CREATE|ATTACH} [TEMPORARY] {DATABASE|TABLE|VIEW|DICTIONARY} - - DROP_DATABASE, - DROP_TABLE, - DROP_VIEW, - DROP_DICTIONARY, - DROP, /// allows to execute DROP {DATABASE|TABLE|VIEW|DICTIONARY} - - TRUNCATE_TABLE, - TRUNCATE_VIEW, - TRUNCATE, /// allows to execute TRUNCATE {TABLE|VIEW} - - OPTIMIZE, /// allows to execute OPTIMIZE TABLE - - KILL_QUERY, /// allows to kill a query started by another user (anyone can kill his own queries) - - CREATE_USER, - ALTER_USER, - DROP_USER, - CREATE_ROLE, - ALTER_ROLE, - DROP_ROLE, - CREATE_POLICY, - ALTER_POLICY, - DROP_POLICY, - CREATE_QUOTA, - ALTER_QUOTA, - DROP_QUOTA, - CREATE_SETTINGS_PROFILE, - ALTER_SETTINGS_PROFILE, - DROP_SETTINGS_PROFILE, - - ROLE_ADMIN, /// allows to grant and revoke any roles. - - SHUTDOWN, - DROP_CACHE, - RELOAD_CONFIG, - RELOAD_DICTIONARY, - STOP_MERGES, - STOP_TTL_MERGES, - STOP_FETCHES, - STOP_MOVES, - STOP_DISTRIBUTED_SENDS, - STOP_REPLICATED_SENDS, - STOP_REPLICATION_QUEUES, - SYNC_REPLICA, - RESTART_REPLICA, - FLUSH_DISTRIBUTED, - FLUSH_LOGS, - SYSTEM, /// allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...} - - dictGet, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn - dictHas, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn - dictGetHierarchy, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn - dictIsIn, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn - - addressToLine, /// allows to execute function addressToLine - addressToSymbol, /// allows to execute function addressToSymbol - demangle, /// allows to execute function demangle - INTROSPECTION, /// allows to execute functions addressToLine, addressToSymbol, demangle - - file, - url, - input, - values, - numbers, - zeros, - merge, - remote, - mysql, - odbc, - jdbc, - hdfs, - s3, - TABLE_FUNCTIONS, /// allows to execute any table function + APPLY_FOR_ACCESS_TYPES(DECLARE_ACCESS_TYPE_ENUM_CONST) +#undef DECLARE_ACCESS_TYPE_ENUM_CONST }; -constexpr size_t MAX_ACCESS_TYPE = static_cast(AccessType::TABLE_FUNCTIONS) + 1; - std::string_view toString(AccessType type); @@ -165,153 +188,26 @@ namespace impl } private: - void addToMapping(AccessType type, const std::string_view & str) + AccessTypeToKeywordConverter() + { +#define INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING(name, aliases, node_type, parent_group_name) \ + insertToMapping(AccessType::name, #name); + + APPLY_FOR_ACCESS_TYPES(INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING) + +#undef INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING + } + + void insertToMapping(AccessType type, const std::string_view & str) { String str2{str}; boost::replace_all(str2, "_", " "); - if (islower(str2[0])) - str2 += "()"; - access_type_to_keyword_mapping[static_cast(type)] = str2; + size_t index = static_cast(type); + access_type_to_keyword_mapping.resize(std::max(index + 1, access_type_to_keyword_mapping.size())); + access_type_to_keyword_mapping[index] = str2; } - AccessTypeToKeywordConverter() - { -#define ACCESS_TYPE_TO_KEYWORD_CASE(type) \ - addToMapping(AccessType::type, #type) - - ACCESS_TYPE_TO_KEYWORD_CASE(NONE); - ACCESS_TYPE_TO_KEYWORD_CASE(ALL); - - ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_DATABASES); - ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_TABLES); - ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_COLUMNS); - ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_DICTIONARIES); - ACCESS_TYPE_TO_KEYWORD_CASE(SHOW); - - ACCESS_TYPE_TO_KEYWORD_CASE(SELECT); - ACCESS_TYPE_TO_KEYWORD_CASE(INSERT); - ACCESS_TYPE_TO_KEYWORD_CASE(UPDATE); - ACCESS_TYPE_TO_KEYWORD_CASE(DELETE); - - ACCESS_TYPE_TO_KEYWORD_CASE(ADD_COLUMN); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_COLUMN); - ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_COLUMN); - ACCESS_TYPE_TO_KEYWORD_CASE(COMMENT_COLUMN); - ACCESS_TYPE_TO_KEYWORD_CASE(CLEAR_COLUMN); - ACCESS_TYPE_TO_KEYWORD_CASE(RENAME_COLUMN); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_COLUMN); - - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_ORDER_BY); - ACCESS_TYPE_TO_KEYWORD_CASE(ADD_INDEX); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_INDEX); - ACCESS_TYPE_TO_KEYWORD_CASE(MATERIALIZE_INDEX); - ACCESS_TYPE_TO_KEYWORD_CASE(CLEAR_INDEX); - ACCESS_TYPE_TO_KEYWORD_CASE(INDEX); - - ACCESS_TYPE_TO_KEYWORD_CASE(ADD_CONSTRAINT); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_CONSTRAINT); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_CONSTRAINT); - - ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_TTL); - ACCESS_TYPE_TO_KEYWORD_CASE(MATERIALIZE_TTL); - ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_SETTING); - - ACCESS_TYPE_TO_KEYWORD_CASE(MOVE_PARTITION); - ACCESS_TYPE_TO_KEYWORD_CASE(FETCH_PARTITION); - ACCESS_TYPE_TO_KEYWORD_CASE(FREEZE_PARTITION); - - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_TABLE); - - ACCESS_TYPE_TO_KEYWORD_CASE(REFRESH_VIEW); - ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_VIEW_QUERY); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_VIEW); - - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER); - - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_DATABASE); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_TABLE); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_VIEW); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_DICTIONARY); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_TEMPORARY_TABLE); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE); - - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_DATABASE); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_TABLE); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_VIEW); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_DICTIONARY); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP); - - ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE_TABLE); - ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE_VIEW); - ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE); - - ACCESS_TYPE_TO_KEYWORD_CASE(OPTIMIZE); - - ACCESS_TYPE_TO_KEYWORD_CASE(KILL_QUERY); - - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_USER); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_USER); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_USER); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_ROLE); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_ROLE); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_ROLE); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_POLICY); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_POLICY); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_POLICY); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_QUOTA); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_QUOTA); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_QUOTA); - ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_SETTINGS_PROFILE); - ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_SETTINGS_PROFILE); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_SETTINGS_PROFILE); - ACCESS_TYPE_TO_KEYWORD_CASE(ROLE_ADMIN); - - ACCESS_TYPE_TO_KEYWORD_CASE(SHUTDOWN); - ACCESS_TYPE_TO_KEYWORD_CASE(DROP_CACHE); - ACCESS_TYPE_TO_KEYWORD_CASE(RELOAD_CONFIG); - ACCESS_TYPE_TO_KEYWORD_CASE(RELOAD_DICTIONARY); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_MERGES); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_TTL_MERGES); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_FETCHES); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_MOVES); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_DISTRIBUTED_SENDS); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_REPLICATED_SENDS); - ACCESS_TYPE_TO_KEYWORD_CASE(STOP_REPLICATION_QUEUES); - ACCESS_TYPE_TO_KEYWORD_CASE(SYNC_REPLICA); - ACCESS_TYPE_TO_KEYWORD_CASE(RESTART_REPLICA); - ACCESS_TYPE_TO_KEYWORD_CASE(FLUSH_DISTRIBUTED); - ACCESS_TYPE_TO_KEYWORD_CASE(FLUSH_LOGS); - ACCESS_TYPE_TO_KEYWORD_CASE(SYSTEM); - - ACCESS_TYPE_TO_KEYWORD_CASE(dictGet); - ACCESS_TYPE_TO_KEYWORD_CASE(dictHas); - ACCESS_TYPE_TO_KEYWORD_CASE(dictGetHierarchy); - ACCESS_TYPE_TO_KEYWORD_CASE(dictIsIn); - - ACCESS_TYPE_TO_KEYWORD_CASE(addressToLine); - ACCESS_TYPE_TO_KEYWORD_CASE(addressToSymbol); - ACCESS_TYPE_TO_KEYWORD_CASE(demangle); - ACCESS_TYPE_TO_KEYWORD_CASE(INTROSPECTION); - - ACCESS_TYPE_TO_KEYWORD_CASE(file); - ACCESS_TYPE_TO_KEYWORD_CASE(url); - ACCESS_TYPE_TO_KEYWORD_CASE(input); - ACCESS_TYPE_TO_KEYWORD_CASE(values); - ACCESS_TYPE_TO_KEYWORD_CASE(numbers); - ACCESS_TYPE_TO_KEYWORD_CASE(zeros); - ACCESS_TYPE_TO_KEYWORD_CASE(merge); - ACCESS_TYPE_TO_KEYWORD_CASE(remote); - ACCESS_TYPE_TO_KEYWORD_CASE(mysql); - ACCESS_TYPE_TO_KEYWORD_CASE(odbc); - ACCESS_TYPE_TO_KEYWORD_CASE(jdbc); - ACCESS_TYPE_TO_KEYWORD_CASE(hdfs); - ACCESS_TYPE_TO_KEYWORD_CASE(s3); - ACCESS_TYPE_TO_KEYWORD_CASE(TABLE_FUNCTIONS); - -#undef ACCESS_TYPE_TO_KEYWORD_CASE - } - - std::array access_type_to_keyword_mapping; + Strings access_type_to_keyword_mapping; }; } diff --git a/src/Access/AllowedClientHosts.h b/src/Access/AllowedClientHosts.h index 9e89c2b92a1..2baafb2e04a 100644 --- a/src/Access/AllowedClientHosts.h +++ b/src/Access/AllowedClientHosts.h @@ -91,7 +91,7 @@ public: /// Allows IP addresses or host names using LIKE pattern. /// This pattern can contain % and _ wildcard characters. - /// For example, addLikePattern("@") will allow all addresses. + /// For example, addLikePattern("%") will allow all addresses. void addLikePattern(const String & pattern); void removeLikePattern(const String & like_pattern); const std::vector & getLikePatterns() const { return like_patterns; } @@ -298,7 +298,7 @@ inline void AllowedClientHosts::addLikePattern(const String & pattern) { if (boost::iequals(pattern, "localhost") || (pattern == "127.0.0.1") || (pattern == "::1")) local_host = true; - else if ((pattern == "@") || (pattern == "0.0.0.0/0") || (pattern == "::/0")) + else if ((pattern == "%") || (pattern == "0.0.0.0/0") || (pattern == "::/0")) any_host = true; else if (boost::range::find(like_patterns, pattern) == name_regexps.end()) like_patterns.push_back(pattern); @@ -308,7 +308,7 @@ inline void AllowedClientHosts::removeLikePattern(const String & pattern) { if (boost::iequals(pattern, "localhost") || (pattern == "127.0.0.1") || (pattern == "::1")) local_host = false; - else if ((pattern == "@") || (pattern == "0.0.0.0/0") || (pattern == "::/0")) + else if ((pattern == "%") || (pattern == "0.0.0.0/0") || (pattern == "::/0")) any_host = false; else boost::range::remove_erase(like_patterns, pattern); diff --git a/src/Access/ContextAccess.cpp b/src/Access/ContextAccess.cpp index 4c690956358..14775f7a4de 100644 --- a/src/Access/ContextAccess.cpp +++ b/src/Access/ContextAccess.cpp @@ -404,23 +404,19 @@ boost::shared_ptr ContextAccess::calculateResultAccess(bool static const AccessFlags table_ddl = AccessType::CREATE_DATABASE | AccessType::CREATE_TABLE | AccessType::CREATE_VIEW | AccessType::ALTER_TABLE | AccessType::ALTER_VIEW | AccessType::DROP_DATABASE | AccessType::DROP_TABLE | AccessType::DROP_VIEW | AccessType::TRUNCATE; + static const AccessFlags dictionary_ddl = AccessType::CREATE_DICTIONARY | AccessType::DROP_DICTIONARY; static const AccessFlags table_and_dictionary_ddl = table_ddl | dictionary_ddl; static const AccessFlags write_table_access = AccessType::INSERT | AccessType::OPTIMIZE; - static const AccessFlags all_dcl = AccessType::CREATE_USER | AccessType::CREATE_ROLE | AccessType::CREATE_POLICY - | AccessType::CREATE_QUOTA | AccessType::CREATE_SETTINGS_PROFILE | AccessType::ALTER_USER | AccessType::ALTER_ROLE - | AccessType::ALTER_POLICY | AccessType::ALTER_QUOTA | AccessType::ALTER_SETTINGS_PROFILE | AccessType::DROP_USER - | AccessType::DROP_ROLE | AccessType::DROP_POLICY | AccessType::DROP_QUOTA | AccessType::DROP_SETTINGS_PROFILE - | AccessType::ROLE_ADMIN; if (readonly_) - merged_access->revoke(write_table_access | all_dcl | table_and_dictionary_ddl | AccessType::SYSTEM | AccessType::KILL_QUERY); + merged_access->revoke(write_table_access | table_and_dictionary_ddl | AccessType::SYSTEM | AccessType::KILL_QUERY | AccessType::ACCESS_MANAGEMENT); if (readonly_ == 1) { /// Table functions are forbidden in readonly mode. /// For example, for readonly = 2 - allowed. - merged_access->revoke(AccessType::CREATE_TEMPORARY_TABLE | AccessType::TABLE_FUNCTIONS); + merged_access->revoke(AccessType::CREATE_TEMPORARY_TABLE); } if (!allow_ddl_ && !grant_option) diff --git a/src/Access/ExtendedRoleSet.cpp b/src/Access/ExtendedRoleSet.cpp index b59dc7ac232..eed475bc3cc 100644 --- a/src/Access/ExtendedRoleSet.cpp +++ b/src/Access/ExtendedRoleSet.cpp @@ -51,25 +51,25 @@ ExtendedRoleSet::ExtendedRoleSet(const boost::container::flat_set & ids_) ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast) { - init(ast, nullptr, nullptr); + init(ast, nullptr); } -ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const UUID & current_user_id) +ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional & current_user_id) { - init(ast, nullptr, ¤t_user_id); + init(ast, nullptr, current_user_id); } ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager) { - init(ast, &manager, nullptr); + init(ast, &manager); } -ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const UUID & current_user_id) +ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional & current_user_id) { - init(ast, &manager, ¤t_user_id); + init(ast, &manager, current_user_id); } -void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const UUID * current_user_id) +void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const std::optional & current_user_id) { all = ast.all; diff --git a/src/Access/ExtendedRoleSet.h b/src/Access/ExtendedRoleSet.h index 61a4db6e0ae..486b4277337 100644 --- a/src/Access/ExtendedRoleSet.h +++ b/src/Access/ExtendedRoleSet.h @@ -32,9 +32,9 @@ struct ExtendedRoleSet /// The constructor from AST requires the AccessControlManager if `ast.id_mode == false`. ExtendedRoleSet(const ASTExtendedRoleSet & ast); - ExtendedRoleSet(const ASTExtendedRoleSet & ast, const UUID & current_user_id); + ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional & current_user_id); ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager); - ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const UUID & current_user_id); + ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional & current_user_id); std::shared_ptr toAST() const; String toString() const; @@ -69,7 +69,7 @@ struct ExtendedRoleSet boost::container::flat_set except_ids; private: - void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const UUID * current_user_id = nullptr); + void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const std::optional & current_user_id = {}); }; } diff --git a/src/Access/UsersConfigAccessStorage.cpp b/src/Access/UsersConfigAccessStorage.cpp index 13102528108..0842839dec8 100644 --- a/src/Access/UsersConfigAccessStorage.cpp +++ b/src/Access/UsersConfigAccessStorage.cpp @@ -168,7 +168,14 @@ namespace user->access.grant(AccessFlags::allDictionaryFlags(), IDictionary::NO_DATABASE_TAG, dictionary); } - user->access_with_grant_option = user->access; + user->access_with_grant_option = user->access; /// By default the user can grant everything he has. + + bool access_management = config.getBool(user_config + ".access_management", false); + if (!access_management) + { + user->access.revoke(AccessType::ACCESS_MANAGEMENT); + user->access_with_grant_option.clear(); + } return user; } diff --git a/src/Common/XDBCBridgeHelper.h b/src/Common/XDBCBridgeHelper.h index 613d1bed8d7..b9d1f2cdcdf 100644 --- a/src/Common/XDBCBridgeHelper.h +++ b/src/Common/XDBCBridgeHelper.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -230,6 +231,10 @@ struct JDBCBridgeMixin { return "JDBC"; } + static AccessType getSourceAccessType() + { + return AccessType::JDBC; + } static std::unique_ptr startBridge(const Poco::Util::AbstractConfiguration &, const Poco::Logger *, const Poco::Timespan &) { @@ -253,6 +258,10 @@ struct ODBCBridgeMixin { return "ODBC"; } + static AccessType getSourceAccessType() + { + return AccessType::ODBC; + } static std::unique_ptr startBridge(const Poco::Util::AbstractConfiguration & config, Poco::Logger * log, const Poco::Timespan & http_timeout) { diff --git a/src/Functions/FunctionsExternalDictionaries.h b/src/Functions/FunctionsExternalDictionaries.h index e1c89dd7d53..fc3c2c583a9 100644 --- a/src/Functions/FunctionsExternalDictionaries.h +++ b/src/Functions/FunctionsExternalDictionaries.h @@ -128,7 +128,7 @@ private: auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); - context.checkAccess(AccessType::dictHas, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName()); + context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName()); if (!executeDispatchSimple(block, arguments, result, dict_ptr) && !executeDispatchSimple(block, arguments, result, dict_ptr) && @@ -1652,7 +1652,7 @@ private: auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); - context.checkAccess(AccessType::dictGetHierarchy, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName()); + context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName()); if (!executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr) && @@ -1816,7 +1816,7 @@ private: auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue()); const auto dict_ptr = dict.get(); - context.checkAccess(AccessType::dictIsIn, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName()); + context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName()); if (!executeDispatch(block, arguments, result, dict_ptr) && !executeDispatch(block, arguments, result, dict_ptr) diff --git a/src/Interpreters/Context.cpp b/src/Interpreters/Context.cpp index 4dc72948f8a..5e98a0267ca 100644 --- a/src/Interpreters/Context.cpp +++ b/src/Interpreters/Context.cpp @@ -665,12 +665,10 @@ String Context::getUserName() const return access->getUserName(); } -UUID Context::getUserID() const +std::optional Context::getUserID() const { auto lock = getLock(); - if (!user_id) - throw Exception("No current user", ErrorCodes::LOGICAL_ERROR); - return *user_id; + return user_id; } diff --git a/src/Interpreters/Context.h b/src/Interpreters/Context.h index e5b33e43614..b34a0e0c542 100644 --- a/src/Interpreters/Context.h +++ b/src/Interpreters/Context.h @@ -233,7 +233,7 @@ public: UserPtr getUser() const; String getUserName() const; - UUID getUserID() const; + std::optional getUserID() const; void setCurrentRoles(const std::vector & current_roles_); void setCurrentRolesDefault(); diff --git a/src/Interpreters/DDLWorker.cpp b/src/Interpreters/DDLWorker.cpp index eaee356264d..4a39cc6b8a1 100644 --- a/src/Interpreters/DDLWorker.cpp +++ b/src/Interpreters/DDLWorker.cpp @@ -1377,4 +1377,9 @@ BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & cont } +BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & context) +{ + return executeDDLQueryOnCluster(query_ptr_, context, {}); +} + } diff --git a/src/Interpreters/DDLWorker.h b/src/Interpreters/DDLWorker.h index 32b7cd5f172..62eba97032e 100644 --- a/src/Interpreters/DDLWorker.h +++ b/src/Interpreters/DDLWorker.h @@ -24,6 +24,7 @@ struct DDLTask; /// Pushes distributed DDL query to the queue BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context, AccessRightsElements && query_required_access); +BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context); class DDLWorker diff --git a/src/Interpreters/InterpreterAlterQuery.cpp b/src/Interpreters/InterpreterAlterQuery.cpp index 7411537601f..7c6b9678325 100644 --- a/src/Interpreters/InterpreterAlterQuery.cpp +++ b/src/Interpreters/InterpreterAlterQuery.cpp @@ -149,35 +149,35 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS { case ASTAlterCommand::UPDATE: { - required_access.emplace_back(AccessType::UPDATE, database, table, column_names_from_update_assignments()); + required_access.emplace_back(AccessType::ALTER_UPDATE, database, table, column_names_from_update_assignments()); break; } case ASTAlterCommand::DELETE: { - required_access.emplace_back(AccessType::DELETE, database, table); + required_access.emplace_back(AccessType::ALTER_DELETE, database, table); break; } case ASTAlterCommand::ADD_COLUMN: { - required_access.emplace_back(AccessType::ADD_COLUMN, database, table, column_name_from_col_decl()); + required_access.emplace_back(AccessType::ALTER_ADD_COLUMN, database, table, column_name_from_col_decl()); break; } case ASTAlterCommand::DROP_COLUMN: { if (command.clear_column) - required_access.emplace_back(AccessType::CLEAR_COLUMN, database, table, column_name()); + required_access.emplace_back(AccessType::ALTER_CLEAR_COLUMN, database, table, column_name()); else - required_access.emplace_back(AccessType::DROP_COLUMN, database, table, column_name()); + required_access.emplace_back(AccessType::ALTER_DROP_COLUMN, database, table, column_name()); break; } case ASTAlterCommand::MODIFY_COLUMN: { - required_access.emplace_back(AccessType::MODIFY_COLUMN, database, table, column_name_from_col_decl()); + required_access.emplace_back(AccessType::ALTER_MODIFY_COLUMN, database, table, column_name_from_col_decl()); break; } case ASTAlterCommand::COMMENT_COLUMN: { - required_access.emplace_back(AccessType::COMMENT_COLUMN, database, table, column_name()); + required_access.emplace_back(AccessType::ALTER_COMMENT_COLUMN, database, table, column_name()); break; } case ASTAlterCommand::MODIFY_ORDER_BY: @@ -187,45 +187,45 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS } case ASTAlterCommand::ADD_INDEX: { - required_access.emplace_back(AccessType::ADD_INDEX, database, table); + required_access.emplace_back(AccessType::ALTER_ADD_INDEX, database, table); break; } case ASTAlterCommand::DROP_INDEX: { if (command.clear_index) - required_access.emplace_back(AccessType::CLEAR_INDEX, database, table); + required_access.emplace_back(AccessType::ALTER_CLEAR_INDEX, database, table); else - required_access.emplace_back(AccessType::DROP_INDEX, database, table); + required_access.emplace_back(AccessType::ALTER_DROP_INDEX, database, table); break; } case ASTAlterCommand::MATERIALIZE_INDEX: { - required_access.emplace_back(AccessType::MATERIALIZE_INDEX, database, table); + required_access.emplace_back(AccessType::ALTER_MATERIALIZE_INDEX, database, table); break; } case ASTAlterCommand::ADD_CONSTRAINT: { - required_access.emplace_back(AccessType::ADD_CONSTRAINT, database, table); + required_access.emplace_back(AccessType::ALTER_ADD_CONSTRAINT, database, table); break; } case ASTAlterCommand::DROP_CONSTRAINT: { - required_access.emplace_back(AccessType::DROP_CONSTRAINT, database, table); + required_access.emplace_back(AccessType::ALTER_DROP_CONSTRAINT, database, table); break; } case ASTAlterCommand::MODIFY_TTL: { - required_access.emplace_back(AccessType::MODIFY_TTL, database, table); + required_access.emplace_back(AccessType::ALTER_TTL, database, table); break; } case ASTAlterCommand::MATERIALIZE_TTL: { - required_access.emplace_back(AccessType::MATERIALIZE_TTL, database, table); + required_access.emplace_back(AccessType::ALTER_MATERIALIZE_TTL, database, table); break; } case ASTAlterCommand::MODIFY_SETTING: { - required_access.emplace_back(AccessType::MODIFY_SETTING, database, table); + required_access.emplace_back(AccessType::ALTER_SETTINGS, database, table); break; } case ASTAlterCommand::ATTACH_PARTITION: @@ -236,7 +236,7 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS case ASTAlterCommand::DROP_PARTITION: [[fallthrough]]; case ASTAlterCommand::DROP_DETACHED_PARTITION: { - required_access.emplace_back(AccessType::DELETE, database, table); + required_access.emplace_back(AccessType::ALTER_DELETE, database, table); break; } case ASTAlterCommand::MOVE_PARTITION: @@ -244,11 +244,11 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS if ((command.move_destination_type == PartDestinationType::DISK) || (command.move_destination_type == PartDestinationType::VOLUME)) { - required_access.emplace_back(AccessType::MOVE_PARTITION, database, table); + required_access.emplace_back(AccessType::ALTER_MOVE_PARTITION, database, table); } else if (command.move_destination_type == PartDestinationType::TABLE) { - required_access.emplace_back(AccessType::SELECT | AccessType::DELETE, database, table); + required_access.emplace_back(AccessType::SELECT | AccessType::ALTER_DELETE, database, table); required_access.emplace_back(AccessType::INSERT, command.to_database, command.to_table); } break; @@ -256,33 +256,33 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS case ASTAlterCommand::REPLACE_PARTITION: { required_access.emplace_back(AccessType::SELECT, command.from_database, command.from_table); - required_access.emplace_back(AccessType::DELETE | AccessType::INSERT, database, table); + required_access.emplace_back(AccessType::ALTER_DELETE | AccessType::INSERT, database, table); break; } case ASTAlterCommand::FETCH_PARTITION: { - required_access.emplace_back(AccessType::FETCH_PARTITION, database, table); + required_access.emplace_back(AccessType::ALTER_FETCH_PARTITION, database, table); break; } case ASTAlterCommand::FREEZE_PARTITION: [[fallthrough]]; case ASTAlterCommand::FREEZE_ALL: { - required_access.emplace_back(AccessType::FREEZE_PARTITION, database, table); + required_access.emplace_back(AccessType::ALTER_FREEZE_PARTITION, database, table); break; } case ASTAlterCommand::MODIFY_QUERY: { - required_access.emplace_back(AccessType::MODIFY_VIEW_QUERY, database, table); + required_access.emplace_back(AccessType::ALTER_VIEW_MODIFY_QUERY, database, table); break; } case ASTAlterCommand::LIVE_VIEW_REFRESH: { - required_access.emplace_back(AccessType::REFRESH_VIEW, database, table); + required_access.emplace_back(AccessType::ALTER_VIEW_REFRESH, database, table); break; } case ASTAlterCommand::RENAME_COLUMN: { - required_access.emplace_back(AccessType::RENAME_COLUMN, database, table, column_name()); + required_access.emplace_back(AccessType::ALTER_RENAME_COLUMN, database, table, column_name()); break; } case ASTAlterCommand::NO_TYPE: break; diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index f15796688e1..b605ce85bc2 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -765,7 +765,14 @@ AccessRightsElements InterpreterCreateQuery::getRequiredAccess() const } if (!create.to_table.empty()) - required_access.emplace_back(AccessType::INSERT, create.to_database, create.to_table); + required_access.emplace_back(AccessType::SELECT | AccessType::INSERT, create.to_database, create.to_table); + + if (create.storage && create.storage->engine) + { + auto source_access_type = StorageFactory::instance().getSourceAccessType(create.storage->engine->name); + if (source_access_type != AccessType::NONE) + required_access.emplace_back(source_access_type); + } return required_access; } diff --git a/src/Interpreters/InterpreterCreateQuotaQuery.cpp b/src/Interpreters/InterpreterCreateQuotaQuery.cpp index 4b64615dd36..13e772965ff 100644 --- a/src/Interpreters/InterpreterCreateQuotaQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuotaQuery.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -76,10 +77,16 @@ void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query, BlockIO InterpreterCreateQuotaQuery::execute() { - const auto & query = query_ptr->as(); + auto & query = query_ptr->as(); auto & access_control = context.getAccessControlManager(); context.checkAccess(query.alter ? AccessType::ALTER_QUOTA : AccessType::CREATE_QUOTA); + if (!query.cluster.empty()) + { + query.replaceCurrentUserTagWithName(context.getUserName()); + return executeDDLQueryOnCluster(query_ptr, context); + } + std::optional roles_from_query; if (query.roles) roles_from_query = ExtendedRoleSet{*query.roles, access_control, context.getUserID()}; diff --git a/src/Interpreters/InterpreterCreateRoleQuery.cpp b/src/Interpreters/InterpreterCreateRoleQuery.cpp index f64462d443b..ed9135b2bb6 100644 --- a/src/Interpreters/InterpreterCreateRoleQuery.cpp +++ b/src/Interpreters/InterpreterCreateRoleQuery.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,9 @@ BlockIO InterpreterCreateRoleQuery::execute() else context.checkAccess(AccessType::CREATE_ROLE); + if (!query.cluster.empty()) + return executeDDLQueryOnCluster(query_ptr, context); + std::optional settings_from_query; if (query.settings) settings_from_query = SettingsProfileElements{*query.settings, access_control}; diff --git a/src/Interpreters/InterpreterCreateRowPolicyQuery.cpp b/src/Interpreters/InterpreterCreateRowPolicyQuery.cpp index 9ea47aba7bb..c3de3876c46 100644 --- a/src/Interpreters/InterpreterCreateRowPolicyQuery.cpp +++ b/src/Interpreters/InterpreterCreateRowPolicyQuery.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -63,9 +64,15 @@ namespace BlockIO InterpreterCreateRowPolicyQuery::execute() { - const auto & query = query_ptr->as(); + auto & query = query_ptr->as(); auto & access_control = context.getAccessControlManager(); - context.checkAccess(query.alter ? AccessType::ALTER_POLICY : AccessType::CREATE_POLICY); + context.checkAccess(query.alter ? AccessType::ALTER_ROW_POLICY : AccessType::CREATE_ROW_POLICY); + + if (!query.cluster.empty()) + { + query.replaceCurrentUserTagWithName(context.getUserName()); + return executeDDLQueryOnCluster(query_ptr, context); + } std::optional roles_from_query; if (query.roles) diff --git a/src/Interpreters/InterpreterCreateSettingsProfileQuery.cpp b/src/Interpreters/InterpreterCreateSettingsProfileQuery.cpp index 9d110a69516..cb0b5587bdc 100644 --- a/src/Interpreters/InterpreterCreateSettingsProfileQuery.cpp +++ b/src/Interpreters/InterpreterCreateSettingsProfileQuery.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -49,13 +51,19 @@ namespace BlockIO InterpreterCreateSettingsProfileQuery::execute() { - const auto & query = query_ptr->as(); + auto & query = query_ptr->as(); auto & access_control = context.getAccessControlManager(); if (query.alter) context.checkAccess(AccessType::ALTER_SETTINGS_PROFILE); else context.checkAccess(AccessType::CREATE_SETTINGS_PROFILE); + if (!query.cluster.empty()) + { + query.replaceCurrentUserTagWithName(context.getUserName()); + return executeDDLQueryOnCluster(query_ptr, context); + } + std::optional settings_from_query; if (query.settings) settings_from_query = SettingsProfileElements{*query.settings, access_control}; diff --git a/src/Interpreters/InterpreterCreateUserQuery.cpp b/src/Interpreters/InterpreterCreateUserQuery.cpp index 5dba1fefc9c..78c7cc222ae 100644 --- a/src/Interpreters/InterpreterCreateUserQuery.cpp +++ b/src/Interpreters/InterpreterCreateUserQuery.cpp @@ -1,10 +1,11 @@ #include #include #include +#include #include +#include #include #include -#include #include #include @@ -67,7 +68,7 @@ namespace BlockIO InterpreterCreateUserQuery::execute() { - const auto & query = query_ptr->as(); + auto & query = query_ptr->as(); auto & access_control = context.getAccessControlManager(); auto access = context.getAccess(); access->checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER); @@ -83,6 +84,9 @@ BlockIO InterpreterCreateUserQuery::execute() } } + if (!query.cluster.empty()) + return executeDDLQueryOnCluster(query_ptr, context); + std::optional settings_from_query; if (query.settings) settings_from_query = SettingsProfileElements{*query.settings, access_control}; diff --git a/src/Interpreters/InterpreterDropAccessEntityQuery.cpp b/src/Interpreters/InterpreterDropAccessEntityQuery.cpp index 12f33250188..e67e0659796 100644 --- a/src/Interpreters/InterpreterDropAccessEntityQuery.cpp +++ b/src/Interpreters/InterpreterDropAccessEntityQuery.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ namespace case Kind::USER: return AccessType::DROP_USER; case Kind::ROLE: return AccessType::DROP_ROLE; case Kind::QUOTA: return AccessType::DROP_QUOTA; - case Kind::ROW_POLICY: return AccessType::DROP_POLICY; + case Kind::ROW_POLICY: return AccessType::DROP_ROW_POLICY; case Kind::SETTINGS_PROFILE: return AccessType::DROP_SETTINGS_PROFILE; } __builtin_unreachable(); @@ -52,6 +53,9 @@ BlockIO InterpreterDropAccessEntityQuery::execute() std::type_index type = getType(query.kind); context.checkAccess(getRequiredAccessType(query.kind)); + if (!query.cluster.empty()) + return executeDDLQueryOnCluster(query_ptr, context); + if (query.kind == Kind::ROW_POLICY) { Strings full_names; diff --git a/src/Interpreters/InterpreterDropQuery.cpp b/src/Interpreters/InterpreterDropQuery.cpp index 42d9528abd5..e3f5d467f38 100644 --- a/src/Interpreters/InterpreterDropQuery.cpp +++ b/src/Interpreters/InterpreterDropQuery.cpp @@ -99,7 +99,7 @@ BlockIO InterpreterDropQuery::executeToTable( } else if (kind == ASTDropQuery::Kind::Truncate) { - context.checkAccess(table->isView() ? AccessType::TRUNCATE_VIEW : AccessType::TRUNCATE_TABLE, table_id); + context.checkAccess(AccessType::TRUNCATE, table_id); table->checkTableCanBeDropped(); /// If table was already dropped by anyone, an exception will be thrown @@ -316,7 +316,7 @@ AccessRightsElements InterpreterDropQuery::getRequiredAccessForDDLOnCluster() co if (drop.kind == ASTDropQuery::Kind::Drop) required_access.emplace_back(AccessType::DROP_TABLE | AccessType::DROP_VIEW, drop.database, drop.table); else if (drop.kind == ASTDropQuery::Kind::Truncate) - required_access.emplace_back(AccessType::TRUNCATE_TABLE | AccessType::TRUNCATE_VIEW, drop.database, drop.table); + required_access.emplace_back(AccessType::TRUNCATE, drop.database, drop.table); else if (drop.kind == ASTDropQuery::Kind::Detach) required_access.emplace_back(AccessType::DROP_TABLE | AccessType::DROP_VIEW, drop.database, drop.table); } diff --git a/src/Interpreters/InterpreterGrantQuery.cpp b/src/Interpreters/InterpreterGrantQuery.cpp index 5d215ff3a93..a5f13dbbbfe 100644 --- a/src/Interpreters/InterpreterGrantQuery.cpp +++ b/src/Interpreters/InterpreterGrantQuery.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -59,7 +61,7 @@ namespace BlockIO InterpreterGrantQuery::execute() { - const auto & query = query_ptr->as(); + auto & query = query_ptr->as(); auto & access_control = context.getAccessControlManager(); auto access = context.getAccess(); access->checkGrantOption(query.access_rights_elements); @@ -72,6 +74,12 @@ BlockIO InterpreterGrantQuery::execute() access->checkAdminOption(role_from_query); } + if (!query.cluster.empty()) + { + query.replaceCurrentUserTagWithName(context.getUserName()); + return executeDDLQueryOnCluster(query_ptr, context); + } + std::vector to_roles = ExtendedRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingIDs(access_control); String current_database = context.getCurrentDatabase(); diff --git a/src/Interpreters/InterpreterKillQueryQuery.cpp b/src/Interpreters/InterpreterKillQueryQuery.cpp index 196b2b4eef1..b23d88524e1 100644 --- a/src/Interpreters/InterpreterKillQueryQuery.cpp +++ b/src/Interpreters/InterpreterKillQueryQuery.cpp @@ -319,7 +319,7 @@ AccessRightsElements InterpreterKillQueryQuery::getRequiredAccessForDDLOnCluster if (query.type == ASTKillQueryQuery::Type::Query) required_access.emplace_back(AccessType::KILL_QUERY); else if (query.type == ASTKillQueryQuery::Type::Mutation) - required_access.emplace_back(AccessType::UPDATE | AccessType::DELETE | AccessType::MATERIALIZE_INDEX | AccessType::MATERIALIZE_TTL); + required_access.emplace_back(AccessType::ALTER_UPDATE | AccessType::ALTER_DELETE | AccessType::ALTER_MATERIALIZE_INDEX | AccessType::ALTER_MATERIALIZE_TTL); return required_access; } diff --git a/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp b/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp index 52126b0507e..d2f435106a8 100644 --- a/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp +++ b/src/Interpreters/InterpreterShowCreateAccessEntityQuery.cpp @@ -256,6 +256,7 @@ BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl() ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const { const auto & access_control = context.getAccessControlManager(); + context.checkAccess(getRequiredAccess()); if (show_query.current_user) { @@ -281,6 +282,22 @@ ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreat } +AccessRightsElements InterpreterShowCreateAccessEntityQuery::getRequiredAccess() const +{ + const auto & show_query = query_ptr->as(); + AccessRightsElements res; + switch (show_query.kind) + { + case Kind::USER: res.emplace_back(AccessType::SHOW_USERS); break; + case Kind::ROLE: res.emplace_back(AccessType::SHOW_ROLES); break; + case Kind::ROW_POLICY: res.emplace_back(AccessType::SHOW_ROW_POLICIES); break; + case Kind::SETTINGS_PROFILE: res.emplace_back(AccessType::SHOW_SETTINGS_PROFILES); break; + case Kind::QUOTA: res.emplace_back(AccessType::SHOW_QUOTAS); break; + } + return res; +} + + ASTPtr InterpreterShowCreateAccessEntityQuery::getAttachQuery(const IAccessEntity & entity) { return getCreateQueryImpl(entity, nullptr, true); diff --git a/src/Interpreters/InterpreterShowCreateAccessEntityQuery.h b/src/Interpreters/InterpreterShowCreateAccessEntityQuery.h index 92025bedb6c..0183c59766f 100644 --- a/src/Interpreters/InterpreterShowCreateAccessEntityQuery.h +++ b/src/Interpreters/InterpreterShowCreateAccessEntityQuery.h @@ -9,6 +9,7 @@ namespace DB { class Context; class ASTShowCreateAccessEntityQuery; +class AccessRightsElements; struct IAccessEntity; @@ -30,6 +31,7 @@ public: private: BlockInputStreamPtr executeImpl(); ASTPtr getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const; + AccessRightsElements getRequiredAccess() const; ASTPtr query_ptr; const Context & context; diff --git a/src/Interpreters/InterpreterSystemQuery.cpp b/src/Interpreters/InterpreterSystemQuery.cpp index 9a7d6ae7c5a..056959d372c 100644 --- a/src/Interpreters/InterpreterSystemQuery.cpp +++ b/src/Interpreters/InterpreterSystemQuery.cpp @@ -102,19 +102,19 @@ void executeCommandsAndThrowIfError(Callables && ... commands) AccessType getRequiredAccessType(StorageActionBlockType action_type) { if (action_type == ActionLocks::PartsMerge) - return AccessType::STOP_MERGES; + return AccessType::SYSTEM_MERGES; else if (action_type == ActionLocks::PartsFetch) - return AccessType::STOP_FETCHES; + return AccessType::SYSTEM_FETCHES; else if (action_type == ActionLocks::PartsSend) - return AccessType::STOP_REPLICATED_SENDS; + return AccessType::SYSTEM_REPLICATED_SENDS; else if (action_type == ActionLocks::ReplicationQueue) - return AccessType::STOP_REPLICATION_QUEUES; + return AccessType::SYSTEM_REPLICATION_QUEUES; else if (action_type == ActionLocks::DistributedSend) - return AccessType::STOP_DISTRIBUTED_SENDS; + return AccessType::SYSTEM_DISTRIBUTED_SENDS; else if (action_type == ActionLocks::PartsTTLMerge) - return AccessType::STOP_TTL_MERGES; + return AccessType::SYSTEM_TTL_MERGES; else if (action_type == ActionLocks::PartsMove) - return AccessType::STOP_MOVES; + return AccessType::SYSTEM_MOVES; else throw Exception("Unknown action type: " + std::to_string(action_type), ErrorCodes::LOGICAL_ERROR); } @@ -183,42 +183,42 @@ BlockIO InterpreterSystemQuery::execute() switch (query.type) { case Type::SHUTDOWN: - context.checkAccess(AccessType::SHUTDOWN); + context.checkAccess(AccessType::SYSTEM_SHUTDOWN); if (kill(0, SIGTERM)) throwFromErrno("System call kill(0, SIGTERM) failed", ErrorCodes::CANNOT_KILL); break; case Type::KILL: - context.checkAccess(AccessType::SHUTDOWN); + context.checkAccess(AccessType::SYSTEM_SHUTDOWN); if (kill(0, SIGKILL)) throwFromErrno("System call kill(0, SIGKILL) failed", ErrorCodes::CANNOT_KILL); break; case Type::DROP_DNS_CACHE: - context.checkAccess(AccessType::DROP_CACHE); + context.checkAccess(AccessType::SYSTEM_DROP_DNS_CACHE); DNSResolver::instance().dropCache(); /// Reinitialize clusters to update their resolved_addresses system_context.reloadClusterConfig(); break; case Type::DROP_MARK_CACHE: - context.checkAccess(AccessType::DROP_CACHE); + context.checkAccess(AccessType::SYSTEM_DROP_MARK_CACHE); system_context.dropMarkCache(); break; case Type::DROP_UNCOMPRESSED_CACHE: - context.checkAccess(AccessType::DROP_CACHE); + context.checkAccess(AccessType::SYSTEM_DROP_UNCOMPRESSED_CACHE); system_context.dropUncompressedCache(); break; #if USE_EMBEDDED_COMPILER case Type::DROP_COMPILED_EXPRESSION_CACHE: - context.checkAccess(AccessType::DROP_CACHE); + context.checkAccess(AccessType::SYSTEM_DROP_COMPILED_EXPRESSION_CACHE); system_context.dropCompiledExpressionCache(); break; #endif case Type::RELOAD_DICTIONARY: - context.checkAccess(AccessType::RELOAD_DICTIONARY); + context.checkAccess(AccessType::SYSTEM_RELOAD_DICTIONARY); system_context.getExternalDictionariesLoader().loadOrReload(query.target_dictionary); ExternalDictionariesLoader::resetAll(); break; case Type::RELOAD_DICTIONARIES: - context.checkAccess(AccessType::RELOAD_DICTIONARY); + context.checkAccess(AccessType::SYSTEM_RELOAD_DICTIONARY); executeCommandsAndThrowIfError( [&] () { system_context.getExternalDictionariesLoader().reloadAllTriedToLoad(); }, [&] () { system_context.getEmbeddedDictionaries().reload(); } @@ -226,11 +226,11 @@ BlockIO InterpreterSystemQuery::execute() ExternalDictionariesLoader::resetAll(); break; case Type::RELOAD_EMBEDDED_DICTIONARIES: - context.checkAccess(AccessType::RELOAD_DICTIONARY); + context.checkAccess(AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES); system_context.getEmbeddedDictionaries().reload(); break; case Type::RELOAD_CONFIG: - context.checkAccess(AccessType::RELOAD_CONFIG); + context.checkAccess(AccessType::SYSTEM_RELOAD_CONFIG); system_context.reloadConfig(); break; case Type::STOP_MERGES: @@ -290,7 +290,7 @@ BlockIO InterpreterSystemQuery::execute() ErrorCodes::BAD_ARGUMENTS); break; case Type::FLUSH_LOGS: - context.checkAccess(AccessType::FLUSH_LOGS); + context.checkAccess(AccessType::SYSTEM_FLUSH_LOGS); executeCommandsAndThrowIfError( [&] () { if (auto query_log = context.getQueryLog()) query_log->flush(); }, [&] () { if (auto part_log = context.getPartLog("")) part_log->flush(); }, @@ -313,7 +313,7 @@ BlockIO InterpreterSystemQuery::execute() StoragePtr InterpreterSystemQuery::tryRestartReplica(const StorageID & replica, Context & system_context, bool need_ddl_guard) { - context.checkAccess(AccessType::RESTART_REPLICA, replica); + context.checkAccess(AccessType::SYSTEM_RESTART_REPLICA, replica); auto table_ddl_guard = need_ddl_guard ? DatabaseCatalog::instance().getDDLGuard(replica.getDatabaseName(), replica.getTableName()) : nullptr; auto [database, table] = DatabaseCatalog::instance().tryGetDatabaseAndTable(replica); @@ -387,7 +387,7 @@ void InterpreterSystemQuery::restartReplicas(Context & system_context) void InterpreterSystemQuery::syncReplica(ASTSystemQuery &) { - context.checkAccess(AccessType::SYNC_REPLICA, table_id); + context.checkAccess(AccessType::SYSTEM_SYNC_REPLICA, table_id); StoragePtr table = DatabaseCatalog::instance().getTable(table_id); if (auto storage_replicated = dynamic_cast(table.get())) @@ -408,7 +408,7 @@ void InterpreterSystemQuery::syncReplica(ASTSystemQuery &) void InterpreterSystemQuery::flushDistributed(ASTSystemQuery &) { - context.checkAccess(AccessType::FLUSH_DISTRIBUTED, table_id); + context.checkAccess(AccessType::SYSTEM_FLUSH_DISTRIBUTED, table_id); if (auto storage_distributed = dynamic_cast(DatabaseCatalog::instance().getTable(table_id).get())) storage_distributed->flushClusterNodesAllData(); @@ -427,7 +427,7 @@ AccessRightsElements InterpreterSystemQuery::getRequiredAccessForDDLOnCluster() case Type::SHUTDOWN: [[fallthrough]]; case Type::KILL: { - required_access.emplace_back(AccessType::SHUTDOWN); + required_access.emplace_back(AccessType::SYSTEM_SHUTDOWN); break; } case Type::DROP_DNS_CACHE: [[fallthrough]]; @@ -437,107 +437,107 @@ AccessRightsElements InterpreterSystemQuery::getRequiredAccessForDDLOnCluster() #endif case Type::DROP_UNCOMPRESSED_CACHE: { - required_access.emplace_back(AccessType::DROP_CACHE); + required_access.emplace_back(AccessType::SYSTEM_DROP_CACHE); break; } case Type::RELOAD_DICTIONARY: [[fallthrough]]; case Type::RELOAD_DICTIONARIES: [[fallthrough]]; case Type::RELOAD_EMBEDDED_DICTIONARIES: { - required_access.emplace_back(AccessType::RELOAD_DICTIONARY); + required_access.emplace_back(AccessType::SYSTEM_RELOAD_DICTIONARY); break; } case Type::RELOAD_CONFIG: { - required_access.emplace_back(AccessType::RELOAD_CONFIG); + required_access.emplace_back(AccessType::SYSTEM_RELOAD_CONFIG); break; } case Type::STOP_MERGES: [[fallthrough]]; case Type::START_MERGES: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_MERGES); + required_access.emplace_back(AccessType::SYSTEM_MERGES); else - required_access.emplace_back(AccessType::STOP_MERGES, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_MERGES, query.database, query.table); break; } case Type::STOP_TTL_MERGES: [[fallthrough]]; case Type::START_TTL_MERGES: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_TTL_MERGES); + required_access.emplace_back(AccessType::SYSTEM_TTL_MERGES); else - required_access.emplace_back(AccessType::STOP_TTL_MERGES, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_TTL_MERGES, query.database, query.table); break; } case Type::STOP_MOVES: [[fallthrough]]; case Type::START_MOVES: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_MOVES); + required_access.emplace_back(AccessType::SYSTEM_MOVES); else - required_access.emplace_back(AccessType::STOP_MOVES, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_MOVES, query.database, query.table); break; } case Type::STOP_FETCHES: [[fallthrough]]; case Type::START_FETCHES: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_FETCHES); + required_access.emplace_back(AccessType::SYSTEM_FETCHES); else - required_access.emplace_back(AccessType::STOP_FETCHES, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_FETCHES, query.database, query.table); break; } case Type::STOP_DISTRIBUTED_SENDS: [[fallthrough]]; case Type::START_DISTRIBUTED_SENDS: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_DISTRIBUTED_SENDS); + required_access.emplace_back(AccessType::SYSTEM_DISTRIBUTED_SENDS); else - required_access.emplace_back(AccessType::STOP_DISTRIBUTED_SENDS, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_DISTRIBUTED_SENDS, query.database, query.table); break; } case Type::STOP_REPLICATED_SENDS: [[fallthrough]]; case Type::START_REPLICATED_SENDS: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_REPLICATED_SENDS); + required_access.emplace_back(AccessType::SYSTEM_REPLICATED_SENDS); else - required_access.emplace_back(AccessType::STOP_REPLICATED_SENDS, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_REPLICATED_SENDS, query.database, query.table); break; } case Type::STOP_REPLICATION_QUEUES: [[fallthrough]]; case Type::START_REPLICATION_QUEUES: { if (query.table.empty()) - required_access.emplace_back(AccessType::STOP_REPLICATION_QUEUES); + required_access.emplace_back(AccessType::SYSTEM_REPLICATION_QUEUES); else - required_access.emplace_back(AccessType::STOP_REPLICATION_QUEUES, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_REPLICATION_QUEUES, query.database, query.table); break; } case Type::SYNC_REPLICA: { - required_access.emplace_back(AccessType::SYNC_REPLICA, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_SYNC_REPLICA, query.database, query.table); break; } case Type::RESTART_REPLICA: { - required_access.emplace_back(AccessType::RESTART_REPLICA, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_RESTART_REPLICA, query.database, query.table); break; } case Type::RESTART_REPLICAS: { - required_access.emplace_back(AccessType::RESTART_REPLICA); + required_access.emplace_back(AccessType::SYSTEM_RESTART_REPLICA); break; } case Type::FLUSH_DISTRIBUTED: { - required_access.emplace_back(AccessType::FLUSH_DISTRIBUTED, query.database, query.table); + required_access.emplace_back(AccessType::SYSTEM_FLUSH_DISTRIBUTED, query.database, query.table); break; } case Type::FLUSH_LOGS: { - required_access.emplace_back(AccessType::FLUSH_LOGS); + required_access.emplace_back(AccessType::SYSTEM_FLUSH_LOGS); break; } case Type::STOP_LISTEN_QUERIES: break; diff --git a/src/Parsers/ASTCreateQuotaQuery.cpp b/src/Parsers/ASTCreateQuotaQuery.cpp index 7613fce6167..8fa0dbb0d31 100644 --- a/src/Parsers/ASTCreateQuotaQuery.cpp +++ b/src/Parsers/ASTCreateQuotaQuery.cpp @@ -135,6 +135,8 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat settings.ostr << " " << backQuoteIfNeed(name); + formatOnCluster(settings); + if (!new_name.empty()) formatRenameTo(new_name, settings); @@ -146,4 +148,12 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat if (roles && (!roles->empty() || alter)) formatToRoles(*roles, settings); } + + +void ASTCreateQuotaQuery::replaceCurrentUserTagWithName(const String & current_user_name) +{ + if (roles) + roles->replaceCurrentUserTagWithName(current_user_name); +} + } diff --git a/src/Parsers/ASTCreateQuotaQuery.h b/src/Parsers/ASTCreateQuotaQuery.h index 2968c2cc607..09ceaea9825 100644 --- a/src/Parsers/ASTCreateQuotaQuery.h +++ b/src/Parsers/ASTCreateQuotaQuery.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -25,7 +26,7 @@ class ASTExtendedRoleSet; * UNSET TRACKING} [,...]] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] */ -class ASTCreateQuotaQuery : public IAST +class ASTCreateQuotaQuery : public IAST, public ASTQueryWithOnCluster { public: bool alter = false; @@ -58,5 +59,7 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; + void replaceCurrentUserTagWithName(const String & current_user_name); + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ASTCreateRoleQuery.cpp b/src/Parsers/ASTCreateRoleQuery.cpp index 3d69e4dac59..f3873f7a3eb 100644 --- a/src/Parsers/ASTCreateRoleQuery.cpp +++ b/src/Parsers/ASTCreateRoleQuery.cpp @@ -54,6 +54,8 @@ void ASTCreateRoleQuery::formatImpl(const FormatSettings & format, FormatState & format.ostr << " " << backQuoteIfNeed(name); + formatOnCluster(format); + if (!new_name.empty()) formatRenameTo(new_name, format); diff --git a/src/Parsers/ASTCreateRoleQuery.h b/src/Parsers/ASTCreateRoleQuery.h index 69bb9896fa3..ab306dd5dec 100644 --- a/src/Parsers/ASTCreateRoleQuery.h +++ b/src/Parsers/ASTCreateRoleQuery.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace DB @@ -15,7 +16,7 @@ class ASTSettingsProfileElements; * [RENAME TO new_name] * [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] */ -class ASTCreateRoleQuery : public IAST +class ASTCreateRoleQuery : public IAST, public ASTQueryWithOnCluster { public: bool alter = false; @@ -33,5 +34,6 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override; + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ASTCreateRowPolicyQuery.cpp b/src/Parsers/ASTCreateRowPolicyQuery.cpp index ac3d859e66f..9b36f5500c1 100644 --- a/src/Parsers/ASTCreateRowPolicyQuery.cpp +++ b/src/Parsers/ASTCreateRowPolicyQuery.cpp @@ -122,7 +122,7 @@ namespace String ASTCreateRowPolicyQuery::getID(char) const { - return "CREATE POLICY or ALTER POLICY query"; + return "CREATE ROW POLICY or ALTER ROW POLICY query"; } @@ -136,11 +136,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format { if (attach) { - settings.ostr << (settings.hilite ? hilite_keyword : "") << "ATTACH POLICY"; + settings.ostr << (settings.hilite ? hilite_keyword : "") << "ATTACH ROW POLICY"; } else { - settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER POLICY" : "CREATE POLICY") + settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER ROW POLICY" : "CREATE ROW POLICY") << (settings.hilite ? hilite_none : ""); } @@ -157,6 +157,8 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format settings.ostr << " " << backQuoteIfNeed(policy_name) << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".") << table_name; + formatOnCluster(settings); + if (!new_policy_name.empty()) formatRenameTo(new_policy_name, settings); @@ -168,4 +170,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format if (roles && (!roles->empty() || alter)) formatToRoles(*roles, settings); } + + +void ASTCreateRowPolicyQuery::replaceCurrentUserTagWithName(const String & current_user_name) +{ + if (roles) + roles->replaceCurrentUserTagWithName(current_user_name); +} } diff --git a/src/Parsers/ASTCreateRowPolicyQuery.h b/src/Parsers/ASTCreateRowPolicyQuery.h index e58ed0ec46c..85ba674eeb0 100644 --- a/src/Parsers/ASTCreateRowPolicyQuery.h +++ b/src/Parsers/ASTCreateRowPolicyQuery.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -25,7 +26,7 @@ class ASTExtendedRoleSet; * [WITH CHECK {condition | NONE}] [,...] * [TO {role [,...] | ALL | ALL EXCEPT role [,...]}] */ -class ASTCreateRowPolicyQuery : public IAST +class ASTCreateRowPolicyQuery : public IAST, public ASTQueryWithOnCluster { public: bool alter = false; @@ -47,5 +48,7 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; + void replaceCurrentUserTagWithName(const String & current_user_name); + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ASTCreateSettingsProfileQuery.cpp b/src/Parsers/ASTCreateSettingsProfileQuery.cpp index a5a5556baf3..8db82b0e1cb 100644 --- a/src/Parsers/ASTCreateSettingsProfileQuery.cpp +++ b/src/Parsers/ASTCreateSettingsProfileQuery.cpp @@ -61,6 +61,8 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo format.ostr << " " << backQuoteIfNeed(name); + formatOnCluster(format); + if (!new_name.empty()) formatRenameTo(new_name, format); @@ -71,4 +73,10 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo formatToRoles(*to_roles, format); } + +void ASTCreateSettingsProfileQuery::replaceCurrentUserTagWithName(const String & current_user_name) +{ + if (to_roles) + to_roles->replaceCurrentUserTagWithName(current_user_name); +} } diff --git a/src/Parsers/ASTCreateSettingsProfileQuery.h b/src/Parsers/ASTCreateSettingsProfileQuery.h index b3a60853e57..cc133397db4 100644 --- a/src/Parsers/ASTCreateSettingsProfileQuery.h +++ b/src/Parsers/ASTCreateSettingsProfileQuery.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace DB @@ -16,7 +17,7 @@ class ASTExtendedRoleSet; * [RENAME TO new_name] * [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] */ -class ASTCreateSettingsProfileQuery : public IAST +class ASTCreateSettingsProfileQuery : public IAST, public ASTQueryWithOnCluster { public: bool alter = false; @@ -36,5 +37,7 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override; + void replaceCurrentUserTagWithName(const String & current_user_name); + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ASTCreateUserQuery.cpp b/src/Parsers/ASTCreateUserQuery.cpp index 0631d08ae74..d901ed8f5a1 100644 --- a/src/Parsers/ASTCreateUserQuery.cpp +++ b/src/Parsers/ASTCreateUserQuery.cpp @@ -184,6 +184,8 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState & format.ostr << " " << backQuoteIfNeed(name); + formatOnCluster(format); + if (!new_name.empty()) formatRenameTo(new_name, format); @@ -195,7 +197,7 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState & if (add_hosts) formatHosts("ADD", *add_hosts, format); if (remove_hosts) - formatHosts("REMOVE", *remove_hosts, format); + formatHosts("DROP", *remove_hosts, format); if (default_roles) formatDefaultRoles(*default_roles, format); diff --git a/src/Parsers/ASTCreateUserQuery.h b/src/Parsers/ASTCreateUserQuery.h index fc2aa0121ed..5a5cc0d9550 100644 --- a/src/Parsers/ASTCreateUserQuery.h +++ b/src/Parsers/ASTCreateUserQuery.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -19,11 +20,11 @@ class ASTSettingsProfileElements; * ALTER USER [IF EXISTS] name * [RENAME TO new_name] * [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}] - * [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] + * [[ADD|DROP] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] * [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ] * [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] */ -class ASTCreateUserQuery : public IAST +class ASTCreateUserQuery : public IAST, public ASTQueryWithOnCluster { public: bool alter = false; @@ -49,5 +50,6 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override; + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ASTDropAccessEntityQuery.cpp b/src/Parsers/ASTDropAccessEntityQuery.cpp index 3896128ceb5..06a820bfbb5 100644 --- a/src/Parsers/ASTDropAccessEntityQuery.cpp +++ b/src/Parsers/ASTDropAccessEntityQuery.cpp @@ -75,5 +75,7 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma settings.ostr << ' ' << backQuoteIfNeed(name); } } + + formatOnCluster(settings); } } diff --git a/src/Parsers/ASTDropAccessEntityQuery.h b/src/Parsers/ASTDropAccessEntityQuery.h index 5f0b46bd896..a3b358dcfb9 100644 --- a/src/Parsers/ASTDropAccessEntityQuery.h +++ b/src/Parsers/ASTDropAccessEntityQuery.h @@ -2,6 +2,7 @@ #include #include +#include namespace DB @@ -13,7 +14,7 @@ namespace DB * DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] * DROP [SETTINGS] PROFILE [IF EXISTS] name [,...] */ -class ASTDropAccessEntityQuery : public IAST +class ASTDropAccessEntityQuery : public IAST, public ASTQueryWithOnCluster { public: enum class Kind @@ -34,5 +35,6 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ASTExtendedRoleSet.cpp b/src/Parsers/ASTExtendedRoleSet.cpp index 3ac1052897d..9eb06a6a101 100644 --- a/src/Parsers/ASTExtendedRoleSet.cpp +++ b/src/Parsers/ASTExtendedRoleSet.cpp @@ -72,4 +72,21 @@ void ASTExtendedRoleSet::formatImpl(const FormatSettings & settings, FormatState } } } + + +void ASTExtendedRoleSet::replaceCurrentUserTagWithName(const String & current_user_name) +{ + if (current_user) + { + names.push_back(current_user_name); + current_user = false; + } + + if (except_current_user) + { + except_names.push_back(current_user_name); + except_current_user = false; + } +} + } diff --git a/src/Parsers/ASTExtendedRoleSet.h b/src/Parsers/ASTExtendedRoleSet.h index 84190211087..8d619e5d6a0 100644 --- a/src/Parsers/ASTExtendedRoleSet.h +++ b/src/Parsers/ASTExtendedRoleSet.h @@ -18,6 +18,7 @@ public: bool id_mode = false; /// If true then `names` and `except_names` keeps UUIDs, not names. bool empty() const { return names.empty() && !current_user && !all; } + void replaceCurrentUserTagWithName(const String & current_user_name); String getID(char) const override { return "ExtendedRoleSet"; } ASTPtr clone() const override { return std::make_shared(*this); } diff --git a/src/Parsers/ASTGrantQuery.cpp b/src/Parsers/ASTGrantQuery.cpp index 94521d790f2..f91a5416011 100644 --- a/src/Parsers/ASTGrantQuery.cpp +++ b/src/Parsers/ASTGrantQuery.cpp @@ -122,19 +122,22 @@ ASTPtr ASTGrantQuery::clone() const void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const { settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << (attach ? "ATTACH " : "") << ((kind == Kind::GRANT) ? "GRANT" : "REVOKE") - << (settings.hilite ? IAST::hilite_none : "") << " "; + << (settings.hilite ? IAST::hilite_none : ""); + + formatOnCluster(settings); if (kind == Kind::REVOKE) { if (grant_option) - settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : ""); + settings.ostr << (settings.hilite ? hilite_keyword : "") << " GRANT OPTION FOR" << (settings.hilite ? hilite_none : ""); else if (admin_option) - settings.ostr << (settings.hilite ? hilite_keyword : "") << "ADMIN OPTION FOR " << (settings.hilite ? hilite_none : ""); + settings.ostr << (settings.hilite ? hilite_keyword : "") << " ADMIN OPTION FOR" << (settings.hilite ? hilite_none : ""); } if ((!!roles + !access_rights_elements.empty()) != 1) throw Exception("Either roles or access rights elements should be set", ErrorCodes::LOGICAL_ERROR); + settings.ostr << " "; if (roles) roles->format(settings); else @@ -150,4 +153,11 @@ void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, F settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH ADMIN OPTION" << (settings.hilite ? hilite_none : ""); } } + + +void ASTGrantQuery::replaceCurrentUserTagWithName(const String & current_user_name) +{ + if (to_roles) + to_roles->replaceCurrentUserTagWithName(current_user_name); +} } diff --git a/src/Parsers/ASTGrantQuery.h b/src/Parsers/ASTGrantQuery.h index 95b5f0b8448..e1ad8dc5dc5 100644 --- a/src/Parsers/ASTGrantQuery.h +++ b/src/Parsers/ASTGrantQuery.h @@ -2,6 +2,7 @@ #include #include +#include namespace DB @@ -15,7 +16,7 @@ class ASTExtendedRoleSet; * GRANT role [,...] TO {user_name | role_name | CURRENT_USER} [,...] [WITH ADMIN OPTION] * REVOKE [ADMIN OPTION FOR] role [,...] FROM {user_name | role_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...] */ -class ASTGrantQuery : public IAST +class ASTGrantQuery : public IAST, public ASTQueryWithOnCluster { public: enum class Kind @@ -34,5 +35,7 @@ public: String getID(char) const override; ASTPtr clone() const override; void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override; + void replaceCurrentUserTagWithName(const String & current_user_name); + ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster(clone()); } }; } diff --git a/src/Parsers/ParserCreateQuotaQuery.cpp b/src/Parsers/ParserCreateQuotaQuery.cpp index 9a6afec6941..66e72ee4968 100644 --- a/src/Parsers/ParserCreateQuotaQuery.cpp +++ b/src/Parsers/ParserCreateQuotaQuery.cpp @@ -238,6 +238,13 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe if (!parseIdentifierOrStringLiteral(pos, expected, name)) return false; + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + String new_name; std::optional key_type; std::vector all_limits; @@ -266,6 +273,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe query->if_exists = if_exists; query->if_not_exists = if_not_exists; query->or_replace = or_replace; + query->cluster = std::move(cluster); query->name = std::move(name); query->new_name = std::move(new_name); query->key_type = key_type; diff --git a/src/Parsers/ParserCreateRoleQuery.cpp b/src/Parsers/ParserCreateRoleQuery.cpp index e2b42c976b4..05143108480 100644 --- a/src/Parsers/ParserCreateRoleQuery.cpp +++ b/src/Parsers/ParserCreateRoleQuery.cpp @@ -80,6 +80,13 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec if (!parseRoleName(pos, expected, name)) return false; + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + String new_name; std::shared_ptr settings; while (true) @@ -101,6 +108,7 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec query->if_exists = if_exists; query->if_not_exists = if_not_exists; query->or_replace = or_replace; + query->cluster = std::move(cluster); query->name = std::move(name); query->new_name = std::move(new_name); query->settings = std::move(settings); diff --git a/src/Parsers/ParserCreateRowPolicyQuery.cpp b/src/Parsers/ParserCreateRowPolicyQuery.cpp index ab0fbc87e12..8bfe54b87b2 100644 --- a/src/Parsers/ParserCreateRowPolicyQuery.cpp +++ b/src/Parsers/ParserCreateRowPolicyQuery.cpp @@ -243,6 +243,13 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & || !parseDatabaseAndTableName(pos, expected, database, table_name)) return false; + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + String new_policy_name; std::optional is_restrictive; std::vector> conditions; @@ -272,6 +279,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & query->if_exists = if_exists; query->if_not_exists = if_not_exists; query->or_replace = or_replace; + query->cluster = std::move(cluster); query->name_parts = std::move(name_parts); query->new_policy_name = std::move(new_policy_name); query->is_restrictive = is_restrictive; diff --git a/src/Parsers/ParserCreateSettingsProfileQuery.cpp b/src/Parsers/ParserCreateSettingsProfileQuery.cpp index c7c9e064f6c..4d3ed2f6e63 100644 --- a/src/Parsers/ParserCreateSettingsProfileQuery.cpp +++ b/src/Parsers/ParserCreateSettingsProfileQuery.cpp @@ -96,6 +96,13 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec if (!parseIdentifierOrStringLiteral(pos, expected, name)) return false; + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + String new_name; std::shared_ptr settings; while (true) @@ -120,6 +127,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec query->if_exists = if_exists; query->if_not_exists = if_not_exists; query->or_replace = or_replace; + query->cluster = std::move(cluster); query->name = std::move(name); query->new_name = std::move(new_name); query->settings = std::move(settings); diff --git a/src/Parsers/ParserCreateUserQuery.cpp b/src/Parsers/ParserCreateUserQuery.cpp index 57f50c34116..3968c26d42e 100644 --- a/src/Parsers/ParserCreateUserQuery.cpp +++ b/src/Parsers/ParserCreateUserQuery.cpp @@ -23,7 +23,7 @@ namespace ErrorCodes namespace { - bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, String & new_host_pattern) + bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, std::optional & new_host_pattern) { return IParserBase::wrapParseImpl(pos, [&] { @@ -286,12 +286,19 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec } String name; - String host_pattern; + std::optional host_pattern; if (!parseUserName(pos, expected, name, host_pattern)) return false; + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + String new_name; - String new_host_pattern; + std::optional new_host_pattern; std::optional authentication; std::optional hosts; std::optional add_hosts; @@ -318,7 +325,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec if (new_name.empty() && parseRenameTo(pos, expected, new_name, new_host_pattern)) continue; - if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "REMOVE", remove_hosts)) + if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "DROP", remove_hosts)) continue; } @@ -327,10 +334,10 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec if (!hosts) { - if (!alter) - hosts.emplace().addLikePattern(host_pattern); - else if (alter && !new_name.empty()) - hosts.emplace().addLikePattern(new_host_pattern); + if (!alter && host_pattern) + hosts.emplace().addLikePattern(*host_pattern); + else if (alter && new_host_pattern) + hosts.emplace().addLikePattern(*new_host_pattern); } auto query = std::make_shared(); @@ -341,6 +348,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec query->if_exists = if_exists; query->if_not_exists = if_not_exists; query->or_replace = or_replace; + query->cluster = std::move(cluster); query->name = std::move(name); query->new_name = std::move(new_name); query->authentication = std::move(authentication); diff --git a/src/Parsers/ParserCreateUserQuery.h b/src/Parsers/ParserCreateUserQuery.h index bd6ab74d53f..4b2af34c003 100644 --- a/src/Parsers/ParserCreateUserQuery.h +++ b/src/Parsers/ParserCreateUserQuery.h @@ -14,7 +14,7 @@ namespace DB * ALTER USER [IF EXISTS] name * [RENAME TO new_name] * [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}] - * [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] + * [[ADD|DROP] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE] * [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...] */ class ParserCreateUserQuery : public IParserBase diff --git a/src/Parsers/ParserDropAccessEntityQuery.cpp b/src/Parsers/ParserDropAccessEntityQuery.cpp index 23e18d7d32c..ecda1691240 100644 --- a/src/Parsers/ParserDropAccessEntityQuery.cpp +++ b/src/Parsers/ParserDropAccessEntityQuery.cpp @@ -117,10 +117,18 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & return false; } + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + auto query = std::make_shared(kind); node = query; query->if_exists = if_exists; + query->cluster = std::move(cluster); query->names = std::move(names); query->row_policies_names = std::move(row_policies_names); diff --git a/src/Parsers/ParserGrantQuery.cpp b/src/Parsers/ParserGrantQuery.cpp index f8533c27d88..f6eecbe5dba 100644 --- a/src/Parsers/ParserGrantQuery.cpp +++ b/src/Parsers/ParserGrantQuery.cpp @@ -17,15 +17,6 @@ namespace ErrorCodes namespace { - bool parseRoundBrackets(IParser::Pos & pos, Expected & expected) - { - return IParserBase::wrapParseImpl(pos, [&] - { - return ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected) - && ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected); - }); - } - bool parseAccessFlags(IParser::Pos & pos, Expected & expected, AccessFlags & access_flags) { static constexpr auto is_one_of_access_type_words = [](IParser::Pos & pos_) @@ -63,7 +54,6 @@ namespace return false; } - parseRoundBrackets(pos, expected); return true; }); } @@ -269,6 +259,13 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) else return false; + String cluster; + if (ParserKeyword{"ON"}.ignore(pos, expected)) + { + if (!ASTQueryWithOnCluster::parse(pos, cluster, expected)) + return false; + } + bool grant_option = false; bool admin_option = false; if (kind == Kind::REVOKE) @@ -306,6 +303,7 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) query->kind = kind; query->attach = attach; + query->cluster = std::move(cluster); query->access_rights_elements = std::move(elements); query->roles = std::move(roles); query->to_roles = std::move(to_roles); diff --git a/src/Parsers/parseUserName.cpp b/src/Parsers/parseUserName.cpp index 3993935e386..e6b91ba4af3 100644 --- a/src/Parsers/parseUserName.cpp +++ b/src/Parsers/parseUserName.cpp @@ -3,48 +3,39 @@ #include #include + namespace DB { -namespace +bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, std::optional & host_like_pattern) { - bool parseUserNameImpl(IParser::Pos & pos, Expected & expected, String & user_name, String * host_like_pattern) + String name; + if (!parseIdentifierOrStringLiteral(pos, expected, name)) + return false; + + boost::algorithm::trim(name); + + std::optional pattern; + if (ParserToken{TokenType::At}.ignore(pos, expected)) { - String name; - if (!parseIdentifierOrStringLiteral(pos, expected, name)) + if (!parseIdentifierOrStringLiteral(pos, expected, pattern.emplace())) return false; - boost::algorithm::trim(name); - - String pattern = "@"; - - if (ParserToken{TokenType::At}.ignore(pos, expected)) - { - if (!parseIdentifierOrStringLiteral(pos, expected, pattern)) - return false; - - boost::algorithm::trim(pattern); - } - - if (pattern != "@") - name += '@' + pattern; - - user_name = std::move(name); - if (host_like_pattern) - *host_like_pattern = std::move(pattern); - return true; + boost::algorithm::trim(*pattern); } + + if (pattern && (pattern != "%")) + name += '@' + *pattern; + + user_name = std::move(name); + host_like_pattern = std::move(pattern); + return true; } bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name) { - return parseUserNameImpl(pos, expected, user_name, nullptr); -} - - -bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, String & host_like_pattern) -{ - return parseUserNameImpl(pos, expected, user_name, &host_like_pattern); + std::optional unused_pattern; + return parseUserName(pos, expected, user_name, unused_pattern); } diff --git a/src/Parsers/parseUserName.h b/src/Parsers/parseUserName.h index c3556f4dc59..641aa09d1f3 100644 --- a/src/Parsers/parseUserName.h +++ b/src/Parsers/parseUserName.h @@ -10,7 +10,7 @@ namespace DB /// The `host` can be an ip address, ip subnet, or a host name. /// The % and _ wildcard characters are permitted in `host`. /// These have the same meaning as for pattern-matching operations performed with the LIKE operator. -bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, String & host_like_pattern); +bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, std::optional & host_like_pattern); bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name); /// Parses either a user name or the 'CURRENT_USER' keyword (or some of the aliases). diff --git a/src/Storages/StorageDistributed.cpp b/src/Storages/StorageDistributed.cpp index 410aee748f7..2790d6e9bce 100644 --- a/src/Storages/StorageDistributed.cpp +++ b/src/Storages/StorageDistributed.cpp @@ -810,6 +810,9 @@ void registerStorageDistributed(StorageFactory & factory) storage_policy, args.relative_data_path, args.attach); + }, + { + .source_access_type = AccessType::REMOTE, }); } diff --git a/src/Storages/StorageFactory.cpp b/src/Storages/StorageFactory.cpp index 9fb548c3893..0a8ceb4b8e5 100644 --- a/src/Storages/StorageFactory.cpp +++ b/src/Storages/StorageFactory.cpp @@ -189,4 +189,13 @@ StorageFactory & StorageFactory::instance() return ret; } + +AccessType StorageFactory::getSourceAccessType(const String & table_engine) const +{ + auto it = storages.find(table_engine); + if (it == storages.end()) + return AccessType::NONE; + return it->second.features.source_access_type; +} + } diff --git a/src/Storages/StorageFactory.h b/src/Storages/StorageFactory.h index e64d8647dd8..de9060769cb 100644 --- a/src/Storages/StorageFactory.h +++ b/src/Storages/StorageFactory.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -54,6 +55,7 @@ public: bool supports_ttl = false; bool supports_replication = false; bool supports_deduplication = false; + AccessType source_access_type = AccessType::NONE; }; using CreatorFn = std::function; @@ -83,6 +85,7 @@ public: .supports_ttl = false, .supports_replication = false, .supports_deduplication = false, + .source_access_type = AccessType::NONE, }); const Storages & getAllStorages() const @@ -108,6 +111,7 @@ public: return result; } + AccessType getSourceAccessType(const String & table_engine) const; private: Storages storages; diff --git a/src/Storages/StorageFile.cpp b/src/Storages/StorageFile.cpp index 48341ce918d..d1332016150 100644 --- a/src/Storages/StorageFile.cpp +++ b/src/Storages/StorageFile.cpp @@ -541,67 +541,71 @@ void StorageFile::truncate(const ASTPtr & /*query*/, const Context & /* context void registerStorageFile(StorageFactory & factory) { - factory.registerStorage("File", [](const StorageFactory::Arguments & args) - { - ASTs & engine_args = args.engine_args; - - if (!(engine_args.size() >= 1 && engine_args.size() <= 3)) // NOLINT - throw Exception( - "Storage File requires from 1 to 3 arguments: name of used format, source and compression_method.", - ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - - engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[0], args.local_context); - String format_name = engine_args[0]->as().value.safeGet(); - - String compression_method; - StorageFile::CommonArguments common_args{args.table_id, format_name, compression_method, - args.columns, args.constraints, args.context}; - - if (engine_args.size() == 1) /// Table in database - return StorageFile::create(args.relative_data_path, common_args); - - /// Will use FD if engine_args[1] is int literal or identifier with std* name - int source_fd = -1; - String source_path; - - if (auto opt_name = tryGetIdentifierName(engine_args[1])) + factory.registerStorage( + "File", + [](const StorageFactory::Arguments & args) { - if (*opt_name == "stdin") - source_fd = STDIN_FILENO; - else if (*opt_name == "stdout") - source_fd = STDOUT_FILENO; - else if (*opt_name == "stderr") - source_fd = STDERR_FILENO; + ASTs & engine_args = args.engine_args; + + if (!(engine_args.size() >= 1 && engine_args.size() <= 3)) // NOLINT + throw Exception( + "Storage File requires from 1 to 3 arguments: name of used format, source and compression_method.", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); + + engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[0], args.local_context); + String format_name = engine_args[0]->as().value.safeGet(); + + String compression_method; + StorageFile::CommonArguments common_args{ + args.table_id, format_name, compression_method, args.columns, args.constraints, args.context}; + + if (engine_args.size() == 1) /// Table in database + return StorageFile::create(args.relative_data_path, common_args); + + /// Will use FD if engine_args[1] is int literal or identifier with std* name + int source_fd = -1; + String source_path; + + if (auto opt_name = tryGetIdentifierName(engine_args[1])) + { + if (*opt_name == "stdin") + source_fd = STDIN_FILENO; + else if (*opt_name == "stdout") + source_fd = STDOUT_FILENO; + else if (*opt_name == "stderr") + source_fd = STDERR_FILENO; + else + throw Exception( + "Unknown identifier '" + *opt_name + "' in second arg of File storage constructor", ErrorCodes::UNKNOWN_IDENTIFIER); + } + else if (const auto * literal = engine_args[1]->as()) + { + auto type = literal->value.getType(); + if (type == Field::Types::Int64) + source_fd = static_cast(literal->value.get()); + else if (type == Field::Types::UInt64) + source_fd = static_cast(literal->value.get()); + else if (type == Field::Types::String) + source_path = literal->value.get(); + else + throw Exception("Second argument must be path or file descriptor", ErrorCodes::BAD_ARGUMENTS); + } + + if (engine_args.size() == 3) + { + engine_args[2] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[2], args.local_context); + compression_method = engine_args[2]->as().value.safeGet(); + } else - throw Exception("Unknown identifier '" + *opt_name + "' in second arg of File storage constructor", - ErrorCodes::UNKNOWN_IDENTIFIER); - } - else if (const auto * literal = engine_args[1]->as()) + compression_method = "auto"; + + if (0 <= source_fd) /// File descriptor + return StorageFile::create(source_fd, common_args); + else /// User's file + return StorageFile::create(source_path, args.context.getUserFilesPath(), common_args); + }, { - auto type = literal->value.getType(); - if (type == Field::Types::Int64) - source_fd = static_cast(literal->value.get()); - else if (type == Field::Types::UInt64) - source_fd = static_cast(literal->value.get()); - else if (type == Field::Types::String) - source_path = literal->value.get(); - else - throw Exception("Second argument must be path or file descriptor", ErrorCodes::BAD_ARGUMENTS); - } - - if (engine_args.size() == 3) - { - engine_args[2] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[2], args.local_context); - compression_method = engine_args[2]->as().value.safeGet(); - } - else - compression_method = "auto"; - - if (0 <= source_fd) /// File descriptor - return StorageFile::create(source_fd, common_args); - else /// User's file - return StorageFile::create(source_path, args.context.getUserFilesPath(), common_args); - }); + .source_access_type = AccessType::FILE, + }); } - } diff --git a/src/Storages/StorageHDFS.cpp b/src/Storages/StorageHDFS.cpp index 192fb658154..c9c41cf9d54 100644 --- a/src/Storages/StorageHDFS.cpp +++ b/src/Storages/StorageHDFS.cpp @@ -339,6 +339,9 @@ void registerStorageHDFS(StorageFactory & factory) } else compression_method = "auto"; return StorageHDFS::create(url, args.table_id, format_name, args.columns, args.constraints, args.context, compression_method); + }, + { + .source_access_type = AccessType::HDFS, }); } diff --git a/src/Storages/StorageMySQL.cpp b/src/Storages/StorageMySQL.cpp index 6645b41376a..055e3f8f264 100644 --- a/src/Storages/StorageMySQL.cpp +++ b/src/Storages/StorageMySQL.cpp @@ -248,6 +248,9 @@ void registerStorageMySQL(StorageFactory & factory) args.columns, args.constraints, args.context); + }, + { + .source_access_type = AccessType::MYSQL, }); } diff --git a/src/Storages/StorageS3.cpp b/src/Storages/StorageS3.cpp index 4c359cafda7..679f343d0da 100644 --- a/src/Storages/StorageS3.cpp +++ b/src/Storages/StorageS3.cpp @@ -348,6 +348,9 @@ void registerStorageS3(StorageFactory & factory) compression_method = "auto"; return StorageS3::create(s3_uri, access_key_id, secret_access_key, args.table_id, format_name, min_upload_part_size, args.columns, args.constraints, args.context); + }, + { + .source_access_type = AccessType::S3, }); } diff --git a/src/Storages/StorageURL.cpp b/src/Storages/StorageURL.cpp index aaccccebef3..6c6f79b50e7 100644 --- a/src/Storages/StorageURL.cpp +++ b/src/Storages/StorageURL.cpp @@ -252,6 +252,9 @@ void registerStorageURL(StorageFactory & factory) format_name, args.columns, args.constraints, args.context, compression_method); + }, + { + .source_access_type = AccessType::URL, }); } } diff --git a/src/Storages/StorageXDBC.cpp b/src/Storages/StorageXDBC.cpp index cedd2abf38f..dd449e490aa 100644 --- a/src/Storages/StorageXDBC.cpp +++ b/src/Storages/StorageXDBC.cpp @@ -134,6 +134,9 @@ namespace args.context, bridge_helper); + }, + { + .source_access_type = BridgeHelperMixin::getSourceAccessType(), }); } } diff --git a/src/Storages/System/StorageSystemQuotaUsage.cpp b/src/Storages/System/StorageSystemQuotaUsage.cpp index 53afb1d563a..1f943d02446 100644 --- a/src/Storages/System/StorageSystemQuotaUsage.cpp +++ b/src/Storages/System/StorageSystemQuotaUsage.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -40,7 +41,9 @@ NamesAndTypesList StorageSystemQuotaUsage::getNamesAndTypes() void StorageSystemQuotaUsage::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const { + context.checkAccess(AccessType::SHOW_QUOTAS); const auto & access_control = context.getAccessControlManager(); + for (const auto & info : access_control.getQuotaUsageInfo()) { for (const auto & interval : info.intervals) diff --git a/src/Storages/System/StorageSystemQuotas.cpp b/src/Storages/System/StorageSystemQuotas.cpp index 228339ea305..a22bb11bbc3 100644 --- a/src/Storages/System/StorageSystemQuotas.cpp +++ b/src/Storages/System/StorageSystemQuotas.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -54,6 +55,8 @@ NamesAndTypesList StorageSystemQuotas::getNamesAndTypes() void StorageSystemQuotas::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const { + context.checkAccess(AccessType::SHOW_QUOTAS); + size_t i = 0; auto & name_column = *res_columns[i++]; auto & id_column = *res_columns[i++]; diff --git a/src/Storages/System/StorageSystemRowPolicies.cpp b/src/Storages/System/StorageSystemRowPolicies.cpp index bd302cba3cf..12221cc52de 100644 --- a/src/Storages/System/StorageSystemRowPolicies.cpp +++ b/src/Storages/System/StorageSystemRowPolicies.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -33,6 +34,7 @@ NamesAndTypesList StorageSystemRowPolicies::getNamesAndTypes() void StorageSystemRowPolicies::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const { + context.checkAccess(AccessType::SHOW_ROW_POLICIES); const auto & access_control = context.getAccessControlManager(); std::vector ids = access_control.findAll(); diff --git a/src/TableFunctions/ITableFunction.cpp b/src/TableFunctions/ITableFunction.cpp index 233da7495d8..6a784c062da 100644 --- a/src/TableFunctions/ITableFunction.cpp +++ b/src/TableFunctions/ITableFunction.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include @@ -13,6 +16,7 @@ namespace DB StoragePtr ITableFunction::execute(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const { ProfileEvents::increment(ProfileEvents::TableFunctionExecute); + context.checkAccess(AccessType::CREATE_TEMPORARY_TABLE | StorageFactory::instance().getSourceAccessType(getStorageTypeName())); return executeImpl(ast_function, context, table_name); } diff --git a/src/TableFunctions/ITableFunction.h b/src/TableFunctions/ITableFunction.h index 9a9525d5887..0bbd7e787a5 100644 --- a/src/TableFunctions/ITableFunction.h +++ b/src/TableFunctions/ITableFunction.h @@ -38,6 +38,7 @@ public: private: virtual StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const = 0; + virtual const char * getStorageTypeName() const = 0; }; using TableFunctionPtr = std::shared_ptr; diff --git a/src/TableFunctions/ITableFunctionFileLike.cpp b/src/TableFunctions/ITableFunctionFileLike.cpp index eca507a4003..46a64cef785 100644 --- a/src/TableFunctions/ITableFunctionFileLike.cpp +++ b/src/TableFunctions/ITableFunctionFileLike.cpp @@ -10,8 +10,6 @@ #include -#include - #include #include @@ -65,8 +63,6 @@ StoragePtr ITableFunctionFileLike::executeImpl(const ASTPtr & ast_function, cons if (args.size() == 4) compression_method = args[3]->as().value.safeGet(); - context.checkAccess(getRequiredAccessType()); - /// Create table StoragePtr storage = getStorage(filename, format, columns, const_cast(context), table_name, compression_method); diff --git a/src/TableFunctions/ITableFunctionFileLike.h b/src/TableFunctions/ITableFunctionFileLike.h index e80bf158f8e..a18ca8ea4c8 100644 --- a/src/TableFunctions/ITableFunctionFileLike.h +++ b/src/TableFunctions/ITableFunctionFileLike.h @@ -5,7 +5,6 @@ namespace DB { -enum class AccessType; class ColumnsDescription; /* @@ -17,6 +16,5 @@ private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; virtual StoragePtr getStorage( const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const String & compression_method) const = 0; - virtual AccessType getRequiredAccessType() const = 0; }; } diff --git a/src/TableFunctions/ITableFunctionXDBC.cpp b/src/TableFunctions/ITableFunctionXDBC.cpp index 50236b65445..adf0c9240bc 100644 --- a/src/TableFunctions/ITableFunctionXDBC.cpp +++ b/src/TableFunctions/ITableFunctionXDBC.cpp @@ -60,8 +60,6 @@ StoragePtr ITableFunctionXDBC::executeImpl(const ASTPtr & ast_function, const Co remote_table_name = args[1]->as().value.safeGet(); } - context.checkAccess(getRequiredAccessType()); - /* Infer external table structure */ /// Have to const_cast, because bridges store their commands inside context BridgeHelperPtr helper = createBridgeHelper(const_cast(context), context.getSettingsRef().http_receive_timeout.value, connection_string); diff --git a/src/TableFunctions/ITableFunctionXDBC.h b/src/TableFunctions/ITableFunctionXDBC.h index 211bac281c8..262c237bac2 100644 --- a/src/TableFunctions/ITableFunctionXDBC.h +++ b/src/TableFunctions/ITableFunctionXDBC.h @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -22,8 +21,6 @@ private: virtual BridgeHelperPtr createBridgeHelper(Context & context, const Poco::Timespan & http_timeout_, const std::string & connection_string_) const = 0; - - virtual AccessType getRequiredAccessType() const = 0; }; class TableFunctionJDBC : public ITableFunctionXDBC @@ -43,7 +40,7 @@ private: return std::make_shared>(context, http_timeout_, connection_string_); } - AccessType getRequiredAccessType() const override { return AccessType::jdbc; } + const char * getStorageTypeName() const override { return "JDBC"; } }; class TableFunctionODBC : public ITableFunctionXDBC @@ -63,6 +60,6 @@ private: return std::make_shared>(context, http_timeout_, connection_string_); } - AccessType getRequiredAccessType() const override { return AccessType::odbc; } + const char * getStorageTypeName() const override { return "ODBC"; } }; } diff --git a/src/TableFunctions/TableFunctionFile.cpp b/src/TableFunctions/TableFunctionFile.cpp index c27999e6199..0a68ed59aa2 100644 --- a/src/TableFunctions/TableFunctionFile.cpp +++ b/src/TableFunctions/TableFunctionFile.cpp @@ -15,11 +15,6 @@ StoragePtr TableFunctionFile::getStorage( return StorageFile::create(source, global_context.getUserFilesPath(), args); } -AccessType TableFunctionFile::getRequiredAccessType() const -{ - return AccessType::file; -} - void registerTableFunctionFile(TableFunctionFactory & factory) { factory.registerFunction(); diff --git a/src/TableFunctions/TableFunctionFile.h b/src/TableFunctions/TableFunctionFile.h index 558d5305674..ead924f6828 100644 --- a/src/TableFunctions/TableFunctionFile.h +++ b/src/TableFunctions/TableFunctionFile.h @@ -24,6 +24,5 @@ public: private: StoragePtr getStorage( const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const std::string & compression_method) const override; - AccessType getRequiredAccessType() const override; -}; -} + const char * getStorageTypeName() const override { return "File"; } +};} diff --git a/src/TableFunctions/TableFunctionGenerateRandom.h b/src/TableFunctions/TableFunctionGenerateRandom.h index 042a5c59dbe..b0919608737 100644 --- a/src/TableFunctions/TableFunctionGenerateRandom.h +++ b/src/TableFunctions/TableFunctionGenerateRandom.h @@ -15,6 +15,7 @@ public: std::string getName() const override { return name; } private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "GenerateRandom"; } }; diff --git a/src/TableFunctions/TableFunctionHDFS.cpp b/src/TableFunctions/TableFunctionHDFS.cpp index 8af41b2e772..3bd6cd3ed76 100644 --- a/src/TableFunctions/TableFunctionHDFS.cpp +++ b/src/TableFunctions/TableFunctionHDFS.cpp @@ -4,7 +4,6 @@ #if USE_HDFS #include #include -#include #include #include @@ -22,10 +21,6 @@ StoragePtr TableFunctionHDFS::getStorage( compression_method); } -AccessType TableFunctionHDFS::getRequiredAccessType() const -{ - return AccessType::hdfs; -} #if USE_HDFS void registerTableFunctionHDFS(TableFunctionFactory & factory) diff --git a/src/TableFunctions/TableFunctionHDFS.h b/src/TableFunctions/TableFunctionHDFS.h index 4bdb6703d31..443ce0aa93b 100644 --- a/src/TableFunctions/TableFunctionHDFS.h +++ b/src/TableFunctions/TableFunctionHDFS.h @@ -25,7 +25,7 @@ public: private: StoragePtr getStorage( const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const String & compression_method) const override; - AccessType getRequiredAccessType() const override; + const char * getStorageTypeName() const override { return "HDFS"; } }; } diff --git a/src/TableFunctions/TableFunctionInput.cpp b/src/TableFunctions/TableFunctionInput.cpp index 41bb292c2b2..e8f3453da06 100644 --- a/src/TableFunctions/TableFunctionInput.cpp +++ b/src/TableFunctions/TableFunctionInput.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "registerTableFunctions.h" @@ -37,8 +36,6 @@ StoragePtr TableFunctionInput::executeImpl(const ASTPtr & ast_function, const Co throw Exception("Table function '" + getName() + "' requires exactly 1 argument: structure", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - context.checkAccess(AccessType::input); - String structure = evaluateConstantExpressionOrIdentifierAsLiteral(args[0], context)->as().value.safeGet(); auto columns = parseColumnsListFromString(structure, context); StoragePtr storage = StorageInput::create(StorageID(getDatabaseName(), table_name), columns); diff --git a/src/TableFunctions/TableFunctionInput.h b/src/TableFunctions/TableFunctionInput.h index 24e5c5b2118..92c2e3a6e54 100644 --- a/src/TableFunctions/TableFunctionInput.h +++ b/src/TableFunctions/TableFunctionInput.h @@ -16,5 +16,6 @@ public: private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "Input"; } }; } diff --git a/src/TableFunctions/TableFunctionMerge.cpp b/src/TableFunctions/TableFunctionMerge.cpp index 1ced074761b..cd924270f7c 100644 --- a/src/TableFunctions/TableFunctionMerge.cpp +++ b/src/TableFunctions/TableFunctionMerge.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -68,8 +67,6 @@ StoragePtr TableFunctionMerge::executeImpl(const ASTPtr & ast_function, const Co String source_database = args[0]->as().value.safeGet(); String table_name_regexp = args[1]->as().value.safeGet(); - context.checkAccess(AccessType::merge, source_database); - auto res = StorageMerge::create( StorageID(getDatabaseName(), table_name), ColumnsDescription{chooseColumns(source_database, table_name_regexp, context)}, diff --git a/src/TableFunctions/TableFunctionMerge.h b/src/TableFunctions/TableFunctionMerge.h index 43d4b692bc8..b11a9551d34 100644 --- a/src/TableFunctions/TableFunctionMerge.h +++ b/src/TableFunctions/TableFunctionMerge.h @@ -17,6 +17,7 @@ public: std::string getName() const override { return name; } private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "Merge"; } }; diff --git a/src/TableFunctions/TableFunctionMySQL.cpp b/src/TableFunctions/TableFunctionMySQL.cpp index 11f797d4ecf..be707c3520d 100644 --- a/src/TableFunctions/TableFunctionMySQL.cpp +++ b/src/TableFunctions/TableFunctionMySQL.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -57,8 +56,6 @@ StoragePtr TableFunctionMySQL::executeImpl(const ASTPtr & ast_function, const Co std::string user_name = args[3]->as().value.safeGet(); std::string password = args[4]->as().value.safeGet(); - context.checkAccess(AccessType::mysql); - bool replace_query = false; std::string on_duplicate_clause; if (args.size() >= 6) diff --git a/src/TableFunctions/TableFunctionMySQL.h b/src/TableFunctions/TableFunctionMySQL.h index fd5b0219df6..850affc5887 100644 --- a/src/TableFunctions/TableFunctionMySQL.h +++ b/src/TableFunctions/TableFunctionMySQL.h @@ -20,6 +20,7 @@ public: } private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "MySQL"; } }; } diff --git a/src/TableFunctions/TableFunctionNumbers.cpp b/src/TableFunctions/TableFunctionNumbers.cpp index bb414f4783f..c8c0fe96092 100644 --- a/src/TableFunctions/TableFunctionNumbers.cpp +++ b/src/TableFunctions/TableFunctionNumbers.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include "registerTableFunctions.h" @@ -33,8 +32,6 @@ StoragePtr TableFunctionNumbers::executeImpl(const ASTPtr & ast_f UInt64 offset = arguments.size() == 2 ? evaluateArgument(context, arguments[0]) : 0; UInt64 length = arguments.size() == 2 ? evaluateArgument(context, arguments[1]) : evaluateArgument(context, arguments[0]); - context.checkAccess(AccessType::numbers); - auto res = StorageSystemNumbers::create(StorageID(getDatabaseName(), table_name), multithreaded, length, offset, false); res->startup(); return res; diff --git a/src/TableFunctions/TableFunctionNumbers.h b/src/TableFunctions/TableFunctionNumbers.h index e5ab38ccad8..c3efbc426ef 100644 --- a/src/TableFunctions/TableFunctionNumbers.h +++ b/src/TableFunctions/TableFunctionNumbers.h @@ -19,6 +19,7 @@ public: std::string getName() const override { return name; } private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "SystemNumbers"; } UInt64 evaluateArgument(const Context & context, ASTPtr & argument) const; }; diff --git a/src/TableFunctions/TableFunctionRemote.cpp b/src/TableFunctions/TableFunctionRemote.cpp index 202f8be4703..cfeb3907136 100644 --- a/src/TableFunctions/TableFunctionRemote.cpp +++ b/src/TableFunctions/TableFunctionRemote.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -132,8 +131,6 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C if (arg_num < args.size()) throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - context.checkAccess(AccessType::remote); - /// ExpressionAnalyzer will be created in InterpreterSelectQuery that will meet these `Identifier` when processing the request. /// We need to mark them as the name of the database or table, because the default value is column. for (auto ast : args) diff --git a/src/TableFunctions/TableFunctionRemote.h b/src/TableFunctions/TableFunctionRemote.h index ef2e5cf190c..2dd58a8a6a7 100644 --- a/src/TableFunctions/TableFunctionRemote.h +++ b/src/TableFunctions/TableFunctionRemote.h @@ -22,6 +22,7 @@ public: private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "Distributed"; } std::string name; bool is_cluster_function; diff --git a/src/TableFunctions/TableFunctionS3.cpp b/src/TableFunctions/TableFunctionS3.cpp index 73121d342e2..0cf9914ed2b 100644 --- a/src/TableFunctions/TableFunctionS3.cpp +++ b/src/TableFunctions/TableFunctionS3.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include #include @@ -64,8 +63,6 @@ StoragePtr TableFunctionS3::executeImpl(const ASTPtr & ast_function, const Conte else compression_method = "auto"; - context.checkAccess(AccessType::s3); - ColumnsDescription columns = parseColumnsListFromString(structure, context); /// Create table diff --git a/src/TableFunctions/TableFunctionS3.h b/src/TableFunctions/TableFunctionS3.h index a49033da1b4..aef4e28ca76 100644 --- a/src/TableFunctions/TableFunctionS3.h +++ b/src/TableFunctions/TableFunctionS3.h @@ -38,6 +38,8 @@ private: Context & global_context, const std::string & table_name, const String & compression_method); + + const char * getStorageTypeName() const override { return "S3"; } }; } diff --git a/src/TableFunctions/TableFunctionURL.cpp b/src/TableFunctions/TableFunctionURL.cpp index a78ac2f2114..59978ae08b1 100644 --- a/src/TableFunctions/TableFunctionURL.cpp +++ b/src/TableFunctions/TableFunctionURL.cpp @@ -16,11 +16,6 @@ StoragePtr TableFunctionURL::getStorage( return StorageURL::create(uri, StorageID(getDatabaseName(), table_name), format, columns, ConstraintsDescription{}, global_context, compression_method); } -AccessType TableFunctionURL::getRequiredAccessType() const -{ - return AccessType::url; -} - void registerTableFunctionURL(TableFunctionFactory & factory) { factory.registerFunction(); diff --git a/src/TableFunctions/TableFunctionURL.h b/src/TableFunctions/TableFunctionURL.h index ea0ca842b48..61dca561f0c 100644 --- a/src/TableFunctions/TableFunctionURL.h +++ b/src/TableFunctions/TableFunctionURL.h @@ -20,6 +20,6 @@ public: private: StoragePtr getStorage( const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const String & compression_method) const override; - AccessType getRequiredAccessType() const override; + const char * getStorageTypeName() const override { return "URL"; } }; } diff --git a/src/TableFunctions/TableFunctionValues.cpp b/src/TableFunctions/TableFunctionValues.cpp index 6f568fbea60..4e166b10d8f 100644 --- a/src/TableFunctions/TableFunctionValues.cpp +++ b/src/TableFunctions/TableFunctionValues.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -75,8 +74,6 @@ StoragePtr TableFunctionValues::executeImpl(const ASTPtr & ast_function, const C throw Exception("Table function '" + getName() + "' requires 2 or more arguments: structure and values.", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); - context.checkAccess(AccessType::values); - /// Parsing first argument as table structure and creating a sample block std::string structure = args[0]->as().value.safeGet(); diff --git a/src/TableFunctions/TableFunctionValues.h b/src/TableFunctions/TableFunctionValues.h index f02dc69162f..3cc3687dab5 100644 --- a/src/TableFunctions/TableFunctionValues.h +++ b/src/TableFunctions/TableFunctionValues.h @@ -14,6 +14,7 @@ public: std::string getName() const override { return name; } private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "Values"; } }; diff --git a/src/TableFunctions/TableFunctionZeros.cpp b/src/TableFunctions/TableFunctionZeros.cpp index d69e533c0d9..13436f04e1c 100644 --- a/src/TableFunctions/TableFunctionZeros.cpp +++ b/src/TableFunctions/TableFunctionZeros.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include "registerTableFunctions.h" @@ -32,8 +31,6 @@ StoragePtr TableFunctionZeros::executeImpl(const ASTPtr & ast_fun UInt64 length = evaluateArgument(context, arguments[0]); - context.checkAccess(AccessType::zeros); - auto res = StorageSystemZeros::create(StorageID(getDatabaseName(), table_name), multithreaded, length); res->startup(); return res; diff --git a/src/TableFunctions/TableFunctionZeros.h b/src/TableFunctions/TableFunctionZeros.h index c8f3cbabc0e..71570c23a89 100644 --- a/src/TableFunctions/TableFunctionZeros.h +++ b/src/TableFunctions/TableFunctionZeros.h @@ -19,6 +19,7 @@ public: std::string getName() const override { return name; } private: StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override; + const char * getStorageTypeName() const override { return "SystemZeros"; } UInt64 evaluateArgument(const Context & context, ASTPtr & argument) const; }; diff --git a/tests/integration/test_access_control_on_cluster/__init__.py b/tests/integration/test_access_control_on_cluster/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/integration/test_access_control_on_cluster/configs/config.d/clusters.xml b/tests/integration/test_access_control_on_cluster/configs/config.d/clusters.xml new file mode 100644 index 00000000000..741f862d162 --- /dev/null +++ b/tests/integration/test_access_control_on_cluster/configs/config.d/clusters.xml @@ -0,0 +1,22 @@ + + + + + + ch1 + 9000 + + + ch2 + 9000 + + + + + ch3 + 9000 + + + + + diff --git a/tests/integration/test_access_control_on_cluster/configs/users.d/access_management.xml b/tests/integration/test_access_control_on_cluster/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_access_control_on_cluster/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_access_control_on_cluster/test.py b/tests/integration/test_access_control_on_cluster/test.py new file mode 100644 index 00000000000..6ca4ac15398 --- /dev/null +++ b/tests/integration/test_access_control_on_cluster/test.py @@ -0,0 +1,41 @@ +import time +import pytest +from helpers.cluster import ClickHouseCluster +from helpers.client import QueryRuntimeException + +cluster = ClickHouseCluster(__file__) +ch1 = cluster.add_instance('ch1', config_dir="configs", with_zookeeper=True) +ch2 = cluster.add_instance('ch2', config_dir="configs", with_zookeeper=True) +ch3 = cluster.add_instance('ch3', config_dir="configs", with_zookeeper=True) + +@pytest.fixture(scope="module", autouse=True) +def started_cluster(): + try: + cluster.start() + yield cluster + + finally: + cluster.shutdown() + + +def test_access_control_on_cluster(): + ch1.query("CREATE USER Alex ON CLUSTER 'cluster'") + assert ch1.query("SHOW CREATE USER Alex") == "CREATE USER Alex\n" + assert ch2.query("SHOW CREATE USER Alex") == "CREATE USER Alex\n" + assert ch3.query("SHOW CREATE USER Alex") == "CREATE USER Alex\n" + + ch2.query("GRANT ON CLUSTER 'cluster' SELECT ON *.* TO Alex") + assert ch1.query("SHOW GRANTS FOR Alex") == "GRANT SELECT ON *.* TO Alex\n" + assert ch2.query("SHOW GRANTS FOR Alex") == "GRANT SELECT ON *.* TO Alex\n" + assert ch3.query("SHOW GRANTS FOR Alex") == "GRANT SELECT ON *.* TO Alex\n" + + ch3.query("REVOKE ON CLUSTER 'cluster' SELECT ON *.* FROM Alex") + assert ch1.query("SHOW GRANTS FOR Alex") == "" + assert ch2.query("SHOW GRANTS FOR Alex") == "" + assert ch3.query("SHOW GRANTS FOR Alex") == "" + + ch2.query("DROP USER Alex ON CLUSTER 'cluster'") + assert "User `Alex` not found" in ch1.query_and_get_error("SHOW CREATE USER Alex") + assert "User `Alex` not found" in ch2.query_and_get_error("SHOW CREATE USER Alex") + assert "User `Alex` not found" in ch3.query_and_get_error("SHOW CREATE USER Alex") + diff --git a/tests/integration/test_authentication/configs/users.d/access_management.xml b/tests/integration/test_authentication/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_authentication/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_authentication/test.py b/tests/integration/test_authentication/test.py index 483b59813e5..b7ffd1ed35b 100644 --- a/tests/integration/test_authentication/test.py +++ b/tests/integration/test_authentication/test.py @@ -2,7 +2,7 @@ import pytest from helpers.cluster import ClickHouseCluster cluster = ClickHouseCluster(__file__) -instance = cluster.add_instance('instance') +instance = cluster.add_instance('instance', config_dir="configs") @pytest.fixture(scope="module", autouse=True) diff --git a/tests/integration/test_disk_access_storage/configs/access_control_path.xml b/tests/integration/test_disk_access_storage/configs/access_control_path.xml deleted file mode 100644 index 7814472ee9b..00000000000 --- a/tests/integration/test_disk_access_storage/configs/access_control_path.xml +++ /dev/null @@ -1,4 +0,0 @@ - - -/var/lib/clickhouse/access - diff --git a/tests/integration/test_disk_access_storage/configs/users.d/access_management.xml b/tests/integration/test_disk_access_storage/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_disk_access_storage/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_disk_access_storage/test.py b/tests/integration/test_disk_access_storage/test.py index d5e1f283167..1f6577b9dd1 100644 --- a/tests/integration/test_disk_access_storage/test.py +++ b/tests/integration/test_disk_access_storage/test.py @@ -2,7 +2,7 @@ import pytest from helpers.cluster import ClickHouseCluster cluster = ClickHouseCluster(__file__) -instance = cluster.add_instance('instance', config_dir='configs', main_configs=['configs/access_control_path.xml'], stay_alive=True) +instance = cluster.add_instance('instance', config_dir='configs', stay_alive=True) @pytest.fixture(scope="module", autouse=True) @@ -40,7 +40,7 @@ def test_create(): def check(): assert instance.query("SHOW CREATE USER u1") == "CREATE USER u1 SETTINGS PROFILE s1\n" assert instance.query("SHOW CREATE USER u2") == "CREATE USER u2 HOST LOCAL DEFAULT ROLE rx\n" - assert instance.query("SHOW CREATE ROW POLICY p ON mydb.mytable") == "CREATE POLICY p ON mydb.mytable FOR SELECT USING a < 1000 TO u1, u2\n" + assert instance.query("SHOW CREATE ROW POLICY p ON mydb.mytable") == "CREATE ROW POLICY p ON mydb.mytable FOR SELECT USING a < 1000 TO u1, u2\n" assert instance.query("SHOW CREATE QUOTA q") == "CREATE QUOTA q KEYED BY \\'none\\' FOR INTERVAL 1 HOUR MAX QUERIES = 100 TO ALL EXCEPT rx\n" assert instance.query("SHOW GRANTS FOR u1") == "" assert instance.query("SHOW GRANTS FOR u2") == "GRANT rx TO u2\n" diff --git a/tests/integration/test_grant_and_revoke/configs/users.d/access_management.xml b/tests/integration/test_grant_and_revoke/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_grant_and_revoke/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_grant_and_revoke/configs/users.xml b/tests/integration/test_grant_and_revoke/configs/users.xml deleted file mode 100644 index fd40c6a4003..00000000000 --- a/tests/integration/test_grant_and_revoke/configs/users.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - ::/0 - - default - - - diff --git a/tests/integration/test_quota/configs/users.d/access_management.xml b/tests/integration/test_quota/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_quota/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_quota/configs/users.xml b/tests/integration/test_quota/configs/users.xml index 15a5364449b..4412345a731 100644 --- a/tests/integration/test_quota/configs/users.xml +++ b/tests/integration/test_quota/configs/users.xml @@ -12,7 +12,6 @@ default myQuota - true diff --git a/tests/integration/test_row_policy/configs/users.d/access_management.xml b/tests/integration/test_row_policy/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_row_policy/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_row_policy/configs/users.xml b/tests/integration/test_row_policy/configs/users.xml index 313d8084884..ce29b7f7308 100644 --- a/tests/integration/test_row_policy/configs/users.xml +++ b/tests/integration/test_row_policy/configs/users.xml @@ -13,7 +13,6 @@ default default - true diff --git a/tests/integration/test_row_policy/test.py b/tests/integration/test_row_policy/test.py index 6db24f5799e..7087e6aafae 100644 --- a/tests/integration/test_row_policy/test.py +++ b/tests/integration/test_row_policy/test.py @@ -228,22 +228,22 @@ def test_dcl_introspection(): assert instance.query("SHOW POLICIES") == "another ON mydb.filtered_table1\nanother ON mydb.filtered_table2\nanother ON mydb.filtered_table3\nanother ON mydb.local\ndefault ON mydb.filtered_table1\ndefault ON mydb.filtered_table2\ndefault ON mydb.filtered_table3\ndefault ON mydb.local\n" assert instance.query("SHOW POLICIES CURRENT") == "default ON mydb.filtered_table1\ndefault ON mydb.filtered_table2\ndefault ON mydb.filtered_table3\ndefault ON mydb.local\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table1") == "CREATE POLICY default ON mydb.filtered_table1 FOR SELECT USING a = 1 TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table2") == "CREATE POLICY default ON mydb.filtered_table2 FOR SELECT USING ((a + b) < 1) OR ((c - d) > 5) TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table3") == "CREATE POLICY default ON mydb.filtered_table3 FOR SELECT USING c = 1 TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.local") == "CREATE POLICY default ON mydb.local FOR SELECT USING 1 TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table1") == "CREATE ROW POLICY default ON mydb.filtered_table1 FOR SELECT USING a = 1 TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table2") == "CREATE ROW POLICY default ON mydb.filtered_table2 FOR SELECT USING ((a + b) < 1) OR ((c - d) > 5) TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table3") == "CREATE ROW POLICY default ON mydb.filtered_table3 FOR SELECT USING c = 1 TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.local") == "CREATE ROW POLICY default ON mydb.local FOR SELECT USING 1 TO default\n" copy_policy_xml('all_rows.xml') assert instance.query("SHOW POLICIES CURRENT") == "default ON mydb.filtered_table1\ndefault ON mydb.filtered_table2\ndefault ON mydb.filtered_table3\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table1") == "CREATE POLICY default ON mydb.filtered_table1 FOR SELECT USING 1 TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table2") == "CREATE POLICY default ON mydb.filtered_table2 FOR SELECT USING 1 TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table3") == "CREATE POLICY default ON mydb.filtered_table3 FOR SELECT USING 1 TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table1") == "CREATE ROW POLICY default ON mydb.filtered_table1 FOR SELECT USING 1 TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table2") == "CREATE ROW POLICY default ON mydb.filtered_table2 FOR SELECT USING 1 TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table3") == "CREATE ROW POLICY default ON mydb.filtered_table3 FOR SELECT USING 1 TO default\n" copy_policy_xml('no_rows.xml') assert instance.query("SHOW POLICIES CURRENT") == "default ON mydb.filtered_table1\ndefault ON mydb.filtered_table2\ndefault ON mydb.filtered_table3\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table1") == "CREATE POLICY default ON mydb.filtered_table1 FOR SELECT USING NULL TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table2") == "CREATE POLICY default ON mydb.filtered_table2 FOR SELECT USING NULL TO default\n" - assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table3") == "CREATE POLICY default ON mydb.filtered_table3 FOR SELECT USING NULL TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table1") == "CREATE ROW POLICY default ON mydb.filtered_table1 FOR SELECT USING NULL TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table2") == "CREATE ROW POLICY default ON mydb.filtered_table2 FOR SELECT USING NULL TO default\n" + assert instance.query("SHOW CREATE POLICY default ON mydb.filtered_table3") == "CREATE ROW POLICY default ON mydb.filtered_table3 FOR SELECT USING NULL TO default\n" copy_policy_xml('no_filters.xml') assert instance.query("SHOW POLICIES") == "" @@ -268,7 +268,7 @@ def test_dcl_management(): instance.query("ALTER POLICY pA ON mydb.filtered_table1 RENAME TO pB") assert instance.query("SELECT * FROM mydb.filtered_table1") == "1\t0\n" assert instance.query("SHOW POLICIES CURRENT ON mydb.filtered_table1") == "pB\n" - assert instance.query("SHOW CREATE POLICY pB ON mydb.filtered_table1") == "CREATE POLICY pB ON mydb.filtered_table1 FOR SELECT USING a > b TO default\n" + assert instance.query("SHOW CREATE POLICY pB ON mydb.filtered_table1") == "CREATE ROW POLICY pB ON mydb.filtered_table1 FOR SELECT USING a > b TO default\n" instance.query("DROP POLICY pB ON mydb.filtered_table1") assert instance.query("SELECT * FROM mydb.filtered_table1") == "0\t0\n0\t1\n1\t0\n1\t1\n" diff --git a/tests/integration/test_settings_constraints_distributed/configs/remote_servers.xml b/tests/integration/test_settings_constraints_distributed/configs/config.d/remote_servers.xml similarity index 100% rename from tests/integration/test_settings_constraints_distributed/configs/remote_servers.xml rename to tests/integration/test_settings_constraints_distributed/configs/config.d/remote_servers.xml diff --git a/tests/integration/test_settings_constraints_distributed/configs/users.d/access_management.xml b/tests/integration/test_settings_constraints_distributed/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_settings_constraints_distributed/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_settings_constraints_distributed/test.py b/tests/integration/test_settings_constraints_distributed/test.py index b23b130b270..a58c037a2fc 100644 --- a/tests/integration/test_settings_constraints_distributed/test.py +++ b/tests/integration/test_settings_constraints_distributed/test.py @@ -8,9 +8,9 @@ from helpers.test_tools import assert_eq_with_retry cluster = ClickHouseCluster(__file__) -node1 = cluster.add_instance('node1') -node2 = cluster.add_instance('node2') -distributed = cluster.add_instance('distributed', main_configs=['configs/remote_servers.xml']) +node1 = cluster.add_instance('node1', config_dir="configs") +node2 = cluster.add_instance('node2', config_dir="configs") +distributed = cluster.add_instance('distributed', config_dir="configs") @pytest.fixture(scope="module") diff --git a/tests/integration/test_settings_profile/configs/users.d/access_management.xml b/tests/integration/test_settings_profile/configs/users.d/access_management.xml new file mode 100644 index 00000000000..7e799cb7b10 --- /dev/null +++ b/tests/integration/test_settings_profile/configs/users.d/access_management.xml @@ -0,0 +1,7 @@ + + + + 1 + + + diff --git a/tests/integration/test_settings_profile/test.py b/tests/integration/test_settings_profile/test.py index 7f18327c66a..6866c6b3901 100644 --- a/tests/integration/test_settings_profile/test.py +++ b/tests/integration/test_settings_profile/test.py @@ -2,7 +2,7 @@ import pytest from helpers.cluster import ClickHouseCluster cluster = ClickHouseCluster(__file__) -instance = cluster.add_instance('instance') +instance = cluster.add_instance('instance', config_dir="configs") @pytest.fixture(scope="module", autouse=True) diff --git a/tests/queries/0_stateless/01073_grant_and_revoke.reference b/tests/queries/0_stateless/01073_grant_and_revoke.reference index 4aad0ca65f1..d7d97fa28fe 100644 --- a/tests/queries/0_stateless/01073_grant_and_revoke.reference +++ b/tests/queries/0_stateless/01073_grant_and_revoke.reference @@ -1,11 +1,11 @@ CREATE USER test_user_01073 A B -GRANT DELETE, INSERT ON *.* TO test_user_01073 +GRANT ALTER DELETE, INSERT ON *.* TO test_user_01073 GRANT SELECT ON db1.* TO test_user_01073 GRANT SELECT ON db2.table TO test_user_01073 GRANT SELECT(col1) ON db3.table TO test_user_01073 GRANT SELECT(col1, col2) ON db4.table TO test_user_01073 C -GRANT DELETE ON *.* TO test_user_01073 +GRANT ALTER DELETE ON *.* TO test_user_01073 GRANT SELECT(col1) ON db4.table TO test_user_01073 diff --git a/tests/queries/0_stateless/01075_allowed_client_hosts.sql b/tests/queries/0_stateless/01075_allowed_client_hosts.sql index 77a16a9f62a..e0b1c0f9905 100644 --- a/tests/queries/0_stateless/01075_allowed_client_hosts.sql +++ b/tests/queries/0_stateless/01075_allowed_client_hosts.sql @@ -21,10 +21,10 @@ SHOW CREATE USER test_user_01075; ALTER USER test_user_01075 ADD HOST IP '127.0.0.1'; SHOW CREATE USER test_user_01075; -ALTER USER test_user_01075 REMOVE HOST IP '2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d'; +ALTER USER test_user_01075 DROP HOST IP '2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d'; SHOW CREATE USER test_user_01075; -ALTER USER test_user_01075 REMOVE HOST NAME 'localhost'; +ALTER USER test_user_01075 DROP HOST NAME 'localhost'; SHOW CREATE USER test_user_01075; ALTER USER test_user_01075 HOST LIKE '@.somesite.com'; @@ -47,7 +47,7 @@ DROP USER test_user_01075; CREATE USER test_user_01075_x@localhost; SHOW CREATE USER test_user_01075_x@localhost; -ALTER USER test_user_01075_x@localhost RENAME TO test_user_01075_x@'@'; +ALTER USER test_user_01075_x@localhost RENAME TO test_user_01075_x@'%'; SHOW CREATE USER test_user_01075_x; ALTER USER test_user_01075_x RENAME TO test_user_01075_x@'192.168.23.15'; diff --git a/tests/queries/server.py b/tests/queries/server.py index 185b694619e..d1ffe9099b5 100644 --- a/tests/queries/server.py +++ b/tests/queries/server.py @@ -118,6 +118,7 @@ ServerThread.DEFAULT_SERVER_CONFIG = \ {tmp_dir}/data/ {tmp_dir}/tmp/ + {tmp_dir}/data/access/ users.xml 5368709120 @@ -193,6 +194,8 @@ ServerThread.DEFAULT_USERS_CONFIG = \ default default + + 1 diff --git a/tests/server-test.xml b/tests/server-test.xml index d9e547b4d55..c2356ec1ba0 100644 --- a/tests/server-test.xml +++ b/tests/server-test.xml @@ -47,6 +47,7 @@ /tmp/clickhouse/data/ /tmp/clickhouse/tmp/ users.xml + /tmp/clickhouse/data/access/ 5368709120 default default