mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
Improve behaviour of row policies, now it applies for a table always when defined for that table (even for another user).
This commit is contained in:
parent
5849dd2236
commit
6cac4a919b
@ -111,13 +111,10 @@ namespace
|
||||
ASTPtr getResult() &&
|
||||
{
|
||||
/// Process permissive conditions.
|
||||
if (!permissions.empty())
|
||||
restrictions.push_back(applyFunctionOR(std::move(permissions)));
|
||||
restrictions.push_back(applyFunctionOR(std::move(permissions)));
|
||||
|
||||
/// Process restrictive conditions.
|
||||
if (!restrictions.empty())
|
||||
return applyFunctionAND(std::move(restrictions));
|
||||
return nullptr;
|
||||
return applyFunctionAND(std::move(restrictions));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -276,10 +273,10 @@ void RowPolicyContextFactory::mixConditionsForContext(RowPolicyContext & context
|
||||
|
||||
for (const auto & [policy_id, info] : all_policies)
|
||||
{
|
||||
const auto & policy = *info.policy;
|
||||
auto & mixers = map_of_mixers[std::pair{policy.getDatabase(), policy.getTableName()}];
|
||||
if (info.canUseWithContext(context))
|
||||
{
|
||||
const auto & policy = *info.policy;
|
||||
auto & mixers = map_of_mixers[std::pair{policy.getDatabase(), policy.getTableName()}];
|
||||
mixers.policy_ids.push_back(policy_id);
|
||||
for (auto index : ext::range(0, MAX_CONDITION_INDEX))
|
||||
if (info.parsed_conditions[index])
|
||||
|
@ -265,63 +265,70 @@ namespace
|
||||
|
||||
std::vector<AccessEntityPtr> parseRowPolicies(const Poco::Util::AbstractConfiguration & config, Poco::Logger * log)
|
||||
{
|
||||
std::vector<AccessEntityPtr> policies;
|
||||
std::map<std::pair<String /* database */, String /* table */>, std::unordered_map<String /* user */, String /* filter */>> all_filters_map;
|
||||
Poco::Util::AbstractConfiguration::Keys user_names;
|
||||
config.keys("users", user_names);
|
||||
|
||||
for (const String & user_name : user_names)
|
||||
try
|
||||
{
|
||||
const String databases_config = "users." + user_name + ".databases";
|
||||
if (config.has(databases_config))
|
||||
config.keys("users", user_names);
|
||||
for (const String & user_name : user_names)
|
||||
{
|
||||
Poco::Util::AbstractConfiguration::Keys databases;
|
||||
config.keys(databases_config, databases);
|
||||
|
||||
/// Read tables within databases
|
||||
for (const String & database : databases)
|
||||
const String databases_config = "users." + user_name + ".databases";
|
||||
if (config.has(databases_config))
|
||||
{
|
||||
const String database_config = databases_config + "." + database;
|
||||
Poco::Util::AbstractConfiguration::Keys keys_in_database_config;
|
||||
config.keys(database_config, keys_in_database_config);
|
||||
Poco::Util::AbstractConfiguration::Keys databases;
|
||||
config.keys(databases_config, databases);
|
||||
|
||||
/// Read table properties
|
||||
for (const String & key_in_database_config : keys_in_database_config)
|
||||
/// Read tables within databases
|
||||
for (const String & database : databases)
|
||||
{
|
||||
String table_name = key_in_database_config;
|
||||
String filter_config = database_config + "." + table_name + ".filter";
|
||||
const String database_config = databases_config + "." + database;
|
||||
Poco::Util::AbstractConfiguration::Keys keys_in_database_config;
|
||||
config.keys(database_config, keys_in_database_config);
|
||||
|
||||
if (key_in_database_config.starts_with("table["))
|
||||
/// Read table properties
|
||||
for (const String & key_in_database_config : keys_in_database_config)
|
||||
{
|
||||
const auto table_name_config = database_config + "." + table_name + "[@name]";
|
||||
if (config.has(table_name_config))
|
||||
{
|
||||
table_name = config.getString(table_name_config);
|
||||
filter_config = database_config + ".table[@name='" + table_name + "']";
|
||||
}
|
||||
}
|
||||
String table_name = key_in_database_config;
|
||||
String filter_config = database_config + "." + table_name + ".filter";
|
||||
|
||||
if (config.has(filter_config))
|
||||
{
|
||||
try
|
||||
if (key_in_database_config.starts_with("table["))
|
||||
{
|
||||
auto policy = std::make_shared<RowPolicy>();
|
||||
policy->setFullName(database, table_name, user_name);
|
||||
policy->conditions[RowPolicy::SELECT_FILTER] = config.getString(filter_config);
|
||||
policy->roles.add(generateID(typeid(User), user_name));
|
||||
policies.push_back(policy);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException(
|
||||
log,
|
||||
"Could not parse row policy " + backQuote(user_name) + " on table " + backQuoteIfNeed(database) + "."
|
||||
+ backQuoteIfNeed(table_name));
|
||||
const auto table_name_config = database_config + "." + table_name + "[@name]";
|
||||
if (config.has(table_name_config))
|
||||
{
|
||||
table_name = config.getString(table_name_config);
|
||||
filter_config = database_config + ".table[@name='" + table_name + "']";
|
||||
}
|
||||
}
|
||||
|
||||
all_filters_map[{database, table_name}][user_name] = config.getString(filter_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException(log, "Could not parse row policies");
|
||||
}
|
||||
|
||||
std::vector<AccessEntityPtr> policies;
|
||||
for (auto & [database_and_table_name, user_to_filters] : all_filters_map)
|
||||
{
|
||||
const auto & [database, table_name] = database_and_table_name;
|
||||
for (const String & user_name : user_names)
|
||||
{
|
||||
auto it = user_to_filters.find(user_name);
|
||||
String filter = (it != user_to_filters.end()) ? it->second : "1";
|
||||
|
||||
auto policy = std::make_shared<RowPolicy>();
|
||||
policy->setFullName(database, table_name, user_name);
|
||||
policy->conditions[RowPolicy::SELECT_FILTER] = filter;
|
||||
policy->roles.add(generateID(typeid(User), user_name));
|
||||
policies.push_back(policy);
|
||||
}
|
||||
}
|
||||
return policies;
|
||||
}
|
||||
}
|
||||
|
@ -209,35 +209,38 @@ def test_introspection():
|
||||
assert instance.query("SELECT currentRowPolicies('mydb', 'filtered_table1')") == "['default']\n"
|
||||
assert instance.query("SELECT currentRowPolicies('mydb', 'filtered_table2')") == "['default']\n"
|
||||
assert instance.query("SELECT currentRowPolicies('mydb', 'filtered_table3')") == "['default']\n"
|
||||
assert instance.query("SELECT arraySort(currentRowPolicies())") == "[('mydb','filtered_table1','default'),('mydb','filtered_table2','default'),('mydb','filtered_table3','default')]\n"
|
||||
assert instance.query("SELECT arraySort(currentRowPolicies())") == "[('mydb','filtered_table1','default'),('mydb','filtered_table2','default'),('mydb','filtered_table3','default'),('mydb','local','default')]\n"
|
||||
|
||||
policy1 = "mydb\tfiltered_table1\tdefault\tdefault ON mydb.filtered_table1\t9e8a8f62-4965-2b5e-8599-57c7b99b3549\tusers.xml\t0\ta = 1\t\t\t\t\n"
|
||||
policy2 = "mydb\tfiltered_table2\tdefault\tdefault ON mydb.filtered_table2\tcffae79d-b9bf-a2ef-b798-019c18470b25\tusers.xml\t0\ta + b < 1 or c - d > 5\t\t\t\t\n"
|
||||
policy3 = "mydb\tfiltered_table3\tdefault\tdefault ON mydb.filtered_table3\t12fc5cef-e3da-3940-ec79-d8be3911f42b\tusers.xml\t0\tc = 1\t\t\t\t\n"
|
||||
policy4 = "mydb\tlocal\tanother\tanother ON mydb.local\t5b23c389-7e18-06bf-a6bc-dd1afbbc0a97\tusers.xml\t0\ta = 1\t\t\t\t\n"
|
||||
policy4 = "mydb\tlocal\tdefault\tdefault ON mydb.local\tcdacaeb5-1d97-f99d-2bb0-4574f290629c\tusers.xml\t0\t1\t\t\t\t\n"
|
||||
assert instance.query("SELECT * from system.row_policies WHERE has(currentRowPolicyIDs('mydb', 'filtered_table1'), id) ORDER BY table, name") == policy1
|
||||
assert instance.query("SELECT * from system.row_policies WHERE has(currentRowPolicyIDs('mydb', 'filtered_table2'), id) ORDER BY table, name") == policy2
|
||||
assert instance.query("SELECT * from system.row_policies WHERE has(currentRowPolicyIDs('mydb', 'filtered_table3'), id) ORDER BY table, name") == policy3
|
||||
assert instance.query("SELECT * from system.row_policies ORDER BY table, name") == policy1 + policy2 + policy3 + policy4
|
||||
assert instance.query("SELECT * from system.row_policies WHERE has(currentRowPolicyIDs(), id) ORDER BY table, name") == policy1 + policy2 + policy3
|
||||
assert instance.query("SELECT * from system.row_policies WHERE has(currentRowPolicyIDs('mydb', 'local'), id) ORDER BY table, name") == policy4
|
||||
assert instance.query("SELECT * from system.row_policies WHERE has(currentRowPolicyIDs(), id) ORDER BY table, name") == policy1 + policy2 + policy3 + policy4
|
||||
|
||||
|
||||
def test_dcl_introspection():
|
||||
assert instance.query("SHOW POLICIES ON mydb.filtered_table1") == "default\n"
|
||||
assert instance.query("SHOW POLICIES ON mydb.filtered_table1") == "another\ndefault\n"
|
||||
assert instance.query("SHOW POLICIES CURRENT ON mydb.filtered_table2") == "default\n"
|
||||
assert instance.query("SHOW POLICIES") == "another ON mydb.local\ndefault ON mydb.filtered_table1\ndefault ON mydb.filtered_table2\ndefault ON mydb.filtered_table3\n"
|
||||
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 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"
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
@ -251,7 +254,7 @@ def test_dcl_management():
|
||||
assert instance.query("SHOW POLICIES") == ""
|
||||
|
||||
instance.query("CREATE POLICY pA ON mydb.filtered_table1 FOR SELECT USING a<b")
|
||||
assert instance.query("SELECT * FROM mydb.filtered_table1") == "0\t0\n0\t1\n1\t0\n1\t1\n"
|
||||
assert instance.query("SELECT * FROM mydb.filtered_table1") == ""
|
||||
assert instance.query("SHOW POLICIES CURRENT ON mydb.filtered_table1") == ""
|
||||
assert instance.query("SHOW POLICIES ON mydb.filtered_table1") == "pA\n"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user