diff --git a/dbms/src/Interpreters/Users.cpp b/dbms/src/Interpreters/Users.cpp index 8d8704165f4..2ca2873e95b 100644 --- a/dbms/src/Interpreters/Users.cpp +++ b/dbms/src/Interpreters/Users.cpp @@ -75,14 +75,15 @@ User::User(const String & name_, const String & config_elem, const Poco::Util::A const auto config_sub_elem = config_elem + ".allow_databases"; if (config.has(config_sub_elem)) { + databases = DatabaseSet(); Poco::Util::AbstractConfiguration::Keys config_keys; config.keys(config_sub_elem, config_keys); - databases.reserve(config_keys.size()); + databases->reserve(config_keys.size()); for (const auto & key : config_keys) { const auto database_name = config.getString(config_sub_elem + "." + key); - databases.insert(database_name); + databases->insert(database_name); } } @@ -90,14 +91,15 @@ User::User(const String & name_, const String & config_elem, const Poco::Util::A const auto config_dictionary_sub_elem = config_elem + ".allow_dictionaries"; if (config.has(config_dictionary_sub_elem)) { + dictionaries = DictionarySet(); Poco::Util::AbstractConfiguration::Keys config_keys; config.keys(config_dictionary_sub_elem, config_keys); - dictionaries.reserve(config_keys.size()); + dictionaries->reserve(config_keys.size()); for (const auto & key : config_keys) { const auto dictionary_name = config.getString(config_dictionary_sub_elem + "." + key); - dictionaries.insert(dictionary_name); + dictionaries->insert(dictionary_name); } } diff --git a/dbms/src/Interpreters/Users.h b/dbms/src/Interpreters/Users.h index a2d4ccece45..e116772855a 100644 --- a/dbms/src/Interpreters/Users.h +++ b/dbms/src/Interpreters/Users.h @@ -36,11 +36,11 @@ struct User /// List of allowed databases. using DatabaseSet = std::unordered_set; - DatabaseSet databases; + std::optional databases; /// List of allowed dictionaries. using DictionarySet = std::unordered_set; - DictionarySet dictionaries; + std::optional dictionaries; /// Table properties. using PropertyMap = std::unordered_map; diff --git a/dbms/src/Interpreters/UsersManager.cpp b/dbms/src/Interpreters/UsersManager.cpp index 50b5d6653a3..5b39193875d 100644 --- a/dbms/src/Interpreters/UsersManager.cpp +++ b/dbms/src/Interpreters/UsersManager.cpp @@ -63,7 +63,7 @@ bool UsersManager::hasAccessToDatabase(const std::string & user_name, const std: throw Exception("Unknown user " + user_name, ErrorCodes::UNKNOWN_USER); auto user = it->second; - return user->databases.empty() || user->databases.count(database_name); + return !user->databases.has_value() || user->databases->count(database_name); } bool UsersManager::hasAccessToDictionary(const std::string & user_name, const std::string & dictionary_name) const @@ -74,6 +74,6 @@ bool UsersManager::hasAccessToDictionary(const std::string & user_name, const st throw Exception("Unknown user " + user_name, ErrorCodes::UNKNOWN_USER); auto user = it->second; - return user->dictionaries.empty() || user->dictionaries.count(dictionary_name); + return !user->dictionaries.has_value() || user->dictionaries->count(dictionary_name); } } diff --git a/dbms/tests/integration/test_user_zero_database_access/__init__.py b/dbms/tests/integration/test_user_zero_database_access/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dbms/tests/integration/test_user_zero_database_access/configs/config.xml b/dbms/tests/integration/test_user_zero_database_access/configs/config.xml new file mode 100644 index 00000000000..00ca74de8a2 --- /dev/null +++ b/dbms/tests/integration/test_user_zero_database_access/configs/config.xml @@ -0,0 +1,31 @@ + + + + trace + /var/log/clickhouse-server/clickhouse-server.log + /var/log/clickhouse-server/clickhouse-server.err.log + 1000M + 10 + + + 9000 + 127.0.0.1 + + + + true + none + + AcceptCertificateHandler + + + + + 500 + 5368709120 + ./clickhouse/ + users.xml + + 1 + 1 + \ No newline at end of file diff --git a/dbms/tests/integration/test_user_zero_database_access/configs/users.xml b/dbms/tests/integration/test_user_zero_database_access/configs/users.xml new file mode 100644 index 00000000000..f800318af16 --- /dev/null +++ b/dbms/tests/integration/test_user_zero_database_access/configs/users.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + ::/0 + + default + default + + + + + + ::/0 + + default + default + + + + + + + ::/0 + + default + default + + test + db1 + + + + + + + + + \ No newline at end of file diff --git a/dbms/tests/integration/test_user_zero_database_access/test_user_zero_database_access.py b/dbms/tests/integration/test_user_zero_database_access/test_user_zero_database_access.py new file mode 100644 index 00000000000..f3d57e2e174 --- /dev/null +++ b/dbms/tests/integration/test_user_zero_database_access/test_user_zero_database_access.py @@ -0,0 +1,64 @@ +import time +import pytest + +from helpers.cluster import ClickHouseCluster + + +cluster = ClickHouseCluster(__file__) +node = cluster.add_instance('node', config_dir="configs") + + +@pytest.fixture(scope="module") +def start_cluster(): + try: + cluster.start() + node.query("CREATE DATABASE test;") + yield cluster + finally: + cluster.shutdown() + + +def test_user_zero_database_access(start_cluster): + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'no_access' --query 'DROP DATABASE test'"], user='root') + assert False, "user with no access rights dropped database test" + except AssertionError: + raise + except Exception as ex: + print ex + + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'has_access' --query 'DROP DATABASE test'"], user='root') + except Exception as ex: + assert False, "user with access rights can't drop database test" + + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'has_access' --query 'CREATE DATABASE test'"], user='root') + except Exception as ex: + assert False, "user with access rights can't create database test" + + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'no_access' --query 'CREATE DATABASE test2'"], user='root') + assert False, "user with no access rights created database test2" + except AssertionError: + raise + except Exception as ex: + print ex + + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'has_access' --query 'CREATE DATABASE test2'"], user='root') + assert False, "user with limited access rights created database test2 which is outside of his scope of rights" + except AssertionError: + raise + except Exception as ex: + print ex + + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'default' --query 'CREATE DATABASE test2'"], user='root') + except Exception as ex: + assert False, "user with full access rights can't create database test2" + + try: + node.exec_in_container(["bash", "-c", "/usr/bin/clickhouse client --user 'default' --query 'DROP DATABASE test2'"], user='root') + except Exception as ex: + assert False, "user with full access rights can't drop database test2" \ No newline at end of file