Use boost::flat_set instead of vector to store current and enabled roles.

This commit is contained in:
Vitaly Baranov 2020-04-29 22:35:56 +03:00
parent b93a15ef36
commit c7213ab607
22 changed files with 172 additions and 217 deletions

View File

@ -42,7 +42,7 @@ public:
std::shared_ptr<const ContextAccess> getContextAccess( std::shared_ptr<const ContextAccess> getContextAccess(
const UUID & user_id, const UUID & user_id,
const std::vector<UUID> & current_roles, const boost::container::flat_set<UUID> & current_roles,
bool use_default_roles, bool use_default_roles,
const Settings & settings, const Settings & settings,
const String & current_database, const String & current_database,
@ -113,7 +113,7 @@ void AccessControlManager::setDefaultProfileName(const String & default_profile_
std::shared_ptr<const ContextAccess> AccessControlManager::getContextAccess( std::shared_ptr<const ContextAccess> AccessControlManager::getContextAccess(
const UUID & user_id, const UUID & user_id,
const std::vector<UUID> & current_roles, const boost::container::flat_set<UUID> & current_roles,
bool use_default_roles, bool use_default_roles,
const Settings & settings, const Settings & settings,
const String & current_database, const String & current_database,
@ -124,21 +124,21 @@ std::shared_ptr<const ContextAccess> AccessControlManager::getContextAccess(
std::shared_ptr<const EnabledRoles> AccessControlManager::getEnabledRoles( std::shared_ptr<const EnabledRoles> AccessControlManager::getEnabledRoles(
const std::vector<UUID> & current_roles, const boost::container::flat_set<UUID> & current_roles,
const std::vector<UUID> & current_roles_with_admin_option) const const boost::container::flat_set<UUID> & current_roles_with_admin_option) const
{ {
return role_cache->getEnabledRoles(current_roles, current_roles_with_admin_option); return role_cache->getEnabledRoles(current_roles, current_roles_with_admin_option);
} }
std::shared_ptr<const EnabledRowPolicies> AccessControlManager::getEnabledRowPolicies(const UUID & user_id, const std::vector<UUID> & enabled_roles) const std::shared_ptr<const EnabledRowPolicies> AccessControlManager::getEnabledRowPolicies(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const
{ {
return row_policy_cache->getEnabledRowPolicies(user_id, enabled_roles); return row_policy_cache->getEnabledRowPolicies(user_id, enabled_roles);
} }
std::shared_ptr<const EnabledQuota> AccessControlManager::getEnabledQuota( std::shared_ptr<const EnabledQuota> AccessControlManager::getEnabledQuota(
const UUID & user_id, const String & user_name, const std::vector<UUID> & enabled_roles, const Poco::Net::IPAddress & address, const String & custom_quota_key) const const UUID & user_id, const String & user_name, const boost::container::flat_set<UUID> & enabled_roles, const Poco::Net::IPAddress & address, const String & custom_quota_key) const
{ {
return quota_cache->getEnabledQuota(user_id, user_name, enabled_roles, address, custom_quota_key); return quota_cache->getEnabledQuota(user_id, user_name, enabled_roles, address, custom_quota_key);
} }
@ -153,7 +153,7 @@ std::vector<QuotaUsageInfo> AccessControlManager::getQuotaUsageInfo() const
std::shared_ptr<const EnabledSettings> AccessControlManager::getEnabledSettings( std::shared_ptr<const EnabledSettings> AccessControlManager::getEnabledSettings(
const UUID & user_id, const UUID & user_id,
const SettingsProfileElements & settings_from_user, const SettingsProfileElements & settings_from_user,
const std::vector<UUID> & enabled_roles, const boost::container::flat_set<UUID> & enabled_roles,
const SettingsProfileElements & settings_from_enabled_roles) const const SettingsProfileElements & settings_from_enabled_roles) const
{ {
return settings_profiles_cache->getEnabledSettings(user_id, settings_from_user, enabled_roles, settings_from_enabled_roles); return settings_profiles_cache->getEnabledSettings(user_id, settings_from_user, enabled_roles, settings_from_enabled_roles);

View File

@ -2,6 +2,7 @@
#include <Access/MultipleAccessStorage.h> #include <Access/MultipleAccessStorage.h>
#include <Poco/AutoPtr.h> #include <Poco/AutoPtr.h>
#include <boost/container/flat_set.hpp>
#include <memory> #include <memory>
@ -51,24 +52,24 @@ public:
std::shared_ptr<const ContextAccess> getContextAccess( std::shared_ptr<const ContextAccess> getContextAccess(
const UUID & user_id, const UUID & user_id,
const std::vector<UUID> & current_roles, const boost::container::flat_set<UUID> & current_roles,
bool use_default_roles, bool use_default_roles,
const Settings & settings, const Settings & settings,
const String & current_database, const String & current_database,
const ClientInfo & client_info) const; const ClientInfo & client_info) const;
std::shared_ptr<const EnabledRoles> getEnabledRoles( std::shared_ptr<const EnabledRoles> getEnabledRoles(
const std::vector<UUID> & current_roles, const boost::container::flat_set<UUID> & current_roles,
const std::vector<UUID> & current_roles_with_admin_option) const; const boost::container::flat_set<UUID> & current_roles_with_admin_option) const;
std::shared_ptr<const EnabledRowPolicies> getEnabledRowPolicies( std::shared_ptr<const EnabledRowPolicies> getEnabledRowPolicies(
const UUID & user_id, const UUID & user_id,
const std::vector<UUID> & enabled_roles) const; const boost::container::flat_set<UUID> & enabled_roles) const;
std::shared_ptr<const EnabledQuota> getEnabledQuota( std::shared_ptr<const EnabledQuota> getEnabledQuota(
const UUID & user_id, const UUID & user_id,
const String & user_name, const String & user_name,
const std::vector<UUID> & enabled_roles, const boost::container::flat_set<UUID> & enabled_roles,
const Poco::Net::IPAddress & address, const Poco::Net::IPAddress & address,
const String & custom_quota_key) const; const String & custom_quota_key) const;
@ -76,7 +77,7 @@ public:
std::shared_ptr<const EnabledSettings> getEnabledSettings(const UUID & user_id, std::shared_ptr<const EnabledSettings> getEnabledSettings(const UUID & user_id,
const SettingsProfileElements & settings_from_user, const SettingsProfileElements & settings_from_user,
const std::vector<UUID> & enabled_roles, const boost::container::flat_set<UUID> & enabled_roles,
const SettingsProfileElements & settings_from_enabled_roles) const; const SettingsProfileElements & settings_from_enabled_roles) const;
std::shared_ptr<const SettingsChanges> getProfileSettings(const String & profile_name) const; std::shared_ptr<const SettingsChanges> getProfileSettings(const String & profile_name) const;

View File

@ -121,7 +121,6 @@ void ContextAccess::setUser(const UserPtr & user_) const
subscription_for_roles_changes = {}; subscription_for_roles_changes = {};
enabled_roles = nullptr; enabled_roles = nullptr;
roles_info = nullptr; roles_info = nullptr;
roles_with_admin_option = nullptr;
enabled_row_policies = nullptr; enabled_row_policies = nullptr;
enabled_quota = nullptr; enabled_quota = nullptr;
enabled_settings = nullptr; enabled_settings = nullptr;
@ -131,29 +130,28 @@ void ContextAccess::setUser(const UserPtr & user_) const
user_name = user->getName(); user_name = user->getName();
trace_log = &Poco::Logger::get("ContextAccess (" + user_name + ")"); trace_log = &Poco::Logger::get("ContextAccess (" + user_name + ")");
std::vector<UUID> current_roles, current_roles_with_admin_option; boost::container::flat_set<UUID> current_roles, current_roles_with_admin_option;
if (params.use_default_roles) if (params.use_default_roles)
{ {
for (const UUID & id : user->granted_roles.roles) for (const UUID & id : user->granted_roles.roles)
{ {
if (user->default_roles.match(id)) if (user->default_roles.match(id))
current_roles.push_back(id); current_roles.emplace(id);
} }
boost::range::set_intersection(current_roles, user->granted_roles.roles_with_admin_option,
std::back_inserter(current_roles_with_admin_option));
} }
else else
{ {
current_roles.reserve(params.current_roles.size()); boost::range::set_intersection(
for (const auto & id : params.current_roles) params.current_roles,
{ user->granted_roles.roles,
if (user->granted_roles.roles.contains(id)) std::inserter(current_roles, current_roles.end()));
current_roles.push_back(id);
if (user->granted_roles.roles_with_admin_option.contains(id))
current_roles_with_admin_option.push_back(id);
}
} }
boost::range::set_intersection(
current_roles,
user->granted_roles.roles_with_admin_option,
std::inserter(current_roles_with_admin_option, current_roles_with_admin_option.end()));
subscription_for_roles_changes = {}; subscription_for_roles_changes = {};
enabled_roles = manager->getEnabledRoles(current_roles, current_roles_with_admin_option); enabled_roles = manager->getEnabledRoles(current_roles, current_roles_with_admin_option);
subscription_for_roles_changes = enabled_roles->subscribeForChanges([this](const std::shared_ptr<const EnabledRolesInfo> & roles_info_) subscription_for_roles_changes = enabled_roles->subscribeForChanges([this](const std::shared_ptr<const EnabledRolesInfo> & roles_info_)
@ -170,7 +168,6 @@ void ContextAccess::setRolesInfo(const std::shared_ptr<const EnabledRolesInfo> &
{ {
assert(roles_info_); assert(roles_info_);
roles_info = roles_info_; roles_info = roles_info_;
roles_with_admin_option.store(boost::make_shared<boost::container::flat_set<UUID>>(roles_info->enabled_roles_with_admin_option.begin(), roles_info->enabled_roles_with_admin_option.end()));
boost::range::fill(result_access, nullptr /* need recalculate */); boost::range::fill(result_access, nullptr /* need recalculate */);
enabled_row_policies = manager->getEnabledRowPolicies(*params.user_id, roles_info->enabled_roles); enabled_row_policies = manager->getEnabledRowPolicies(*params.user_id, roles_info->enabled_roles);
enabled_quota = manager->getEnabledQuota(*params.user_id, user_name, roles_info->enabled_roles, params.address, params.quota_key); enabled_quota = manager->getEnabledQuota(*params.user_id, user_name, roles_info->enabled_roles, params.address, params.quota_key);
@ -357,10 +354,13 @@ void ContextAccess::checkAdminOption(const UUID & role_id) const
if (isGranted(AccessType::ROLE_ADMIN)) if (isGranted(AccessType::ROLE_ADMIN))
return; return;
auto roles_with_admin_option_loaded = roles_with_admin_option.load(); auto info = getRolesInfo();
if (roles_with_admin_option_loaded && roles_with_admin_option_loaded->count(role_id)) if (info && info->enabled_roles_with_admin_option.count(role_id))
return; return;
if (!user)
throw Exception(user_name + ": User has been dropped", ErrorCodes::UNKNOWN_USER);
std::optional<String> role_name = manager->readName(role_id); std::optional<String> role_name = manager->readName(role_id);
if (!role_name) if (!role_name)
role_name = "ID {" + toString(role_id) + "}"; role_name = "ID {" + toString(role_id) + "}";
@ -485,30 +485,6 @@ std::shared_ptr<const EnabledRolesInfo> ContextAccess::getRolesInfo() const
return roles_info; return roles_info;
} }
std::vector<UUID> ContextAccess::getCurrentRoles() const
{
std::lock_guard lock{mutex};
return roles_info ? roles_info->current_roles : std::vector<UUID>{};
}
Strings ContextAccess::getCurrentRolesNames() const
{
std::lock_guard lock{mutex};
return roles_info ? roles_info->getCurrentRolesNames() : Strings{};
}
std::vector<UUID> ContextAccess::getEnabledRoles() const
{
std::lock_guard lock{mutex};
return roles_info ? roles_info->enabled_roles : std::vector<UUID>{};
}
Strings ContextAccess::getEnabledRolesNames() const
{
std::lock_guard lock{mutex};
return roles_info ? roles_info->getEnabledRolesNames() : Strings{};
}
std::shared_ptr<const EnabledRowPolicies> ContextAccess::getRowPolicies() const std::shared_ptr<const EnabledRowPolicies> ContextAccess::getRowPolicies() const
{ {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};

View File

@ -35,7 +35,7 @@ public:
struct Params struct Params
{ {
std::optional<UUID> user_id; std::optional<UUID> user_id;
std::vector<UUID> current_roles; boost::container::flat_set<UUID> current_roles;
bool use_default_roles = false; bool use_default_roles = false;
UInt64 readonly = 0; UInt64 readonly = 0;
bool allow_ddl = false; bool allow_ddl = false;
@ -56,22 +56,36 @@ public:
}; };
const Params & getParams() const { return params; } const Params & getParams() const { return params; }
/// Returns the current user. The function can return nullptr.
UserPtr getUser() const; UserPtr getUser() const;
String getUserName() const; String getUserName() const;
bool isCorrectPassword(const String & password) const; bool isCorrectPassword(const String & password) const;
bool isClientHostAllowed() const; bool isClientHostAllowed() const;
/// Returns information about current and enabled roles.
/// The function can return nullptr.
std::shared_ptr<const EnabledRolesInfo> getRolesInfo() const; std::shared_ptr<const EnabledRolesInfo> getRolesInfo() const;
std::vector<UUID> getCurrentRoles() const;
Strings getCurrentRolesNames() const;
std::vector<UUID> getEnabledRoles() const;
Strings getEnabledRolesNames() const;
/// Returns information about enabled row policies.
/// The function can return nullptr.
std::shared_ptr<const EnabledRowPolicies> getRowPolicies() const; std::shared_ptr<const EnabledRowPolicies> getRowPolicies() const;
/// Returns the row policy filter for a specified table.
/// The function returns nullptr if there is no filter to apply.
ASTPtr getRowPolicyCondition(const String & database, const String & table_name, RowPolicy::ConditionType index, const ASTPtr & extra_condition = nullptr) const; ASTPtr getRowPolicyCondition(const String & database, const String & table_name, RowPolicy::ConditionType index, const ASTPtr & extra_condition = nullptr) const;
/// Returns the quota to track resource consumption.
/// The function returns nullptr if no tracking or limitation is needed.
std::shared_ptr<const EnabledQuota> getQuota() const; std::shared_ptr<const EnabledQuota> getQuota() const;
/// Returns the default settings, i.e. the settings to apply on user's login.
/// The function returns nullptr if it's no need to apply settings.
std::shared_ptr<const Settings> getDefaultSettings() const; std::shared_ptr<const Settings> getDefaultSettings() const;
/// Returns the settings' constraints.
/// The function returns nullptr if there are no constraints.
std::shared_ptr<const SettingsConstraints> getSettingsConstraints() const; std::shared_ptr<const SettingsConstraints> getSettingsConstraints() const;
/// Checks if a specified access is granted, and throws an exception if not. /// Checks if a specified access is granted, and throws an exception if not.
@ -118,7 +132,8 @@ public:
/// Checks if a specified role is granted with admin option, and throws an exception if not. /// Checks if a specified role is granted with admin option, and throws an exception if not.
void checkAdminOption(const UUID & role_id) const; void checkAdminOption(const UUID & role_id) const;
/// Returns an instance of ContextAccess which has full access to everything. /// Makes an instance of ContextAccess which provides full access to everything
/// without any limitations. This is used for the global context.
static std::shared_ptr<const ContextAccess> getFullAccess(); static std::shared_ptr<const ContextAccess> getFullAccess();
private: private:
@ -157,7 +172,6 @@ private:
mutable std::shared_ptr<const EnabledRoles> enabled_roles; mutable std::shared_ptr<const EnabledRoles> enabled_roles;
mutable ext::scope_guard subscription_for_roles_changes; mutable ext::scope_guard subscription_for_roles_changes;
mutable std::shared_ptr<const EnabledRolesInfo> roles_info; mutable std::shared_ptr<const EnabledRolesInfo> roles_info;
mutable boost::atomic_shared_ptr<const boost::container::flat_set<UUID>> roles_with_admin_option;
mutable boost::atomic_shared_ptr<const AccessRights> result_access[7]; mutable boost::atomic_shared_ptr<const AccessRights> result_access[7];
mutable std::shared_ptr<const EnabledRowPolicies> enabled_row_policies; mutable std::shared_ptr<const EnabledRowPolicies> enabled_row_policies;
mutable std::shared_ptr<const EnabledQuota> enabled_quota; mutable std::shared_ptr<const EnabledQuota> enabled_quota;

View File

@ -23,7 +23,7 @@ public:
{ {
UUID user_id; UUID user_id;
String user_name; String user_name;
std::vector<UUID> enabled_roles; boost::container::flat_set<UUID> enabled_roles;
Poco::Net::IPAddress client_address; Poco::Net::IPAddress client_address;
String client_key; String client_key;

View File

@ -2,6 +2,7 @@
#include <Core/UUID.h> #include <Core/UUID.h>
#include <ext/scope_guard.h> #include <ext/scope_guard.h>
#include <boost/container/flat_set.hpp>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
@ -16,8 +17,8 @@ class EnabledRoles
public: public:
struct Params struct Params
{ {
std::vector<UUID> current_roles; boost::container::flat_set<UUID> current_roles;
std::vector<UUID> current_roles_with_admin_option; boost::container::flat_set<UUID> current_roles_with_admin_option;
auto toTuple() const { return std::tie(current_roles, current_roles_with_admin_option); } auto toTuple() const { return std::tie(current_roles, current_roles_with_admin_option); }
friend bool operator ==(const Params & lhs, const Params & rhs) { return lhs.toTuple() == rhs.toTuple(); } friend bool operator ==(const Params & lhs, const Params & rhs) { return lhs.toTuple() == rhs.toTuple(); }

View File

@ -3,8 +3,8 @@
#include <Access/AccessRights.h> #include <Access/AccessRights.h>
#include <Access/SettingsProfileElement.h> #include <Access/SettingsProfileElement.h>
#include <Core/UUID.h> #include <Core/UUID.h>
#include <boost/container/flat_set.hpp>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace DB namespace DB
@ -13,9 +13,9 @@ namespace DB
/// Information about a role. /// Information about a role.
struct EnabledRolesInfo struct EnabledRolesInfo
{ {
std::vector<UUID> current_roles; boost::container::flat_set<UUID> current_roles;
std::vector<UUID> enabled_roles; boost::container::flat_set<UUID> enabled_roles;
std::vector<UUID> enabled_roles_with_admin_option; boost::container::flat_set<UUID> enabled_roles_with_admin_option;
std::unordered_map<UUID, String> names_of_roles; std::unordered_map<UUID, String> names_of_roles;
AccessRights access; AccessRights access;
AccessRights access_with_grant_option; AccessRights access_with_grant_option;

View File

@ -21,7 +21,7 @@ public:
struct Params struct Params
{ {
UUID user_id; UUID user_id;
std::vector<UUID> enabled_roles; boost::container::flat_set<UUID> enabled_roles;
auto toTuple() const { return std::tie(user_id, enabled_roles); } auto toTuple() const { return std::tie(user_id, enabled_roles); }
friend bool operator ==(const Params & lhs, const Params & rhs) { return lhs.toTuple() == rhs.toTuple(); } friend bool operator ==(const Params & lhs, const Params & rhs) { return lhs.toTuple() == rhs.toTuple(); }

View File

@ -5,6 +5,7 @@
#include <Common/SettingsChanges.h> #include <Common/SettingsChanges.h>
#include <Access/SettingsConstraints.h> #include <Access/SettingsConstraints.h>
#include <Access/SettingsProfileElement.h> #include <Access/SettingsProfileElement.h>
#include <boost/container/flat_set.hpp>
#include <mutex> #include <mutex>
@ -17,7 +18,7 @@ public:
struct Params struct Params
{ {
UUID user_id; UUID user_id;
std::vector<UUID> enabled_roles; boost::container::flat_set<UUID> enabled_roles;
SettingsProfileElements settings_from_enabled_roles; SettingsProfileElements settings_from_enabled_roles;
SettingsProfileElements settings_from_user; SettingsProfileElements settings_from_user;

View File

@ -136,26 +136,6 @@ std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toAST() const
} }
String ExtendedRoleSet::toString() const
{
auto ast = toAST();
return serializeAST(*ast);
}
Strings ExtendedRoleSet::toStrings() const
{
if (all || !except_ids.empty())
return {toString()};
Strings names;
names.reserve(ids.size());
for (const UUID & id : ids)
names.emplace_back(::DB::toString(id));
return names;
}
std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toASTWithNames(const AccessControlManager & manager) const std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toASTWithNames(const AccessControlManager & manager) const
{ {
auto ast = std::make_shared<ASTExtendedRoleSet>(); auto ast = std::make_shared<ASTExtendedRoleSet>();
@ -189,6 +169,13 @@ std::shared_ptr<ASTExtendedRoleSet> ExtendedRoleSet::toASTWithNames(const Access
} }
String ExtendedRoleSet::toString() const
{
auto ast = toAST();
return serializeAST(*ast);
}
String ExtendedRoleSet::toStringWithNames(const AccessControlManager & manager) const String ExtendedRoleSet::toStringWithNames(const AccessControlManager & manager) const
{ {
auto ast = toASTWithNames(manager); auto ast = toASTWithNames(manager);
@ -198,19 +185,39 @@ String ExtendedRoleSet::toStringWithNames(const AccessControlManager & manager)
Strings ExtendedRoleSet::toStringsWithNames(const AccessControlManager & manager) const Strings ExtendedRoleSet::toStringsWithNames(const AccessControlManager & manager) const
{ {
if (all || !except_ids.empty()) if (!all && ids.empty())
return {toStringWithNames(manager)}; return {};
Strings names; Strings res;
names.reserve(ids.size()); res.reserve(ids.size() + except_ids.size());
for (const UUID & id : ids)
if (all)
res.emplace_back("ALL");
else
{ {
auto name = manager.tryReadName(id); for (const UUID & id : ids)
if (name) {
names.emplace_back(std::move(*name)); auto name = manager.tryReadName(id);
if (name)
res.emplace_back(std::move(*name));
}
std::sort(res.begin(), res.end());
} }
boost::range::sort(names);
return names; if (!except_ids.empty())
{
res.emplace_back("EXCEPT");
size_t old_size = res.size();
for (const UUID & id : except_ids)
{
auto name = manager.tryReadName(id);
if (name)
res.emplace_back(std::move(*name));
}
std::sort(res.begin() + old_size, res.end());
}
return res;
} }
@ -247,25 +254,6 @@ bool ExtendedRoleSet::match(const UUID & id) const
} }
bool ExtendedRoleSet::match(const UUID & user_id, const std::vector<UUID> & enabled_roles) const
{
if (!all && !ids.count(user_id))
{
bool found_enabled_role = std::any_of(
enabled_roles.begin(), enabled_roles.end(), [this](const UUID & enabled_role) { return ids.count(enabled_role); });
if (!found_enabled_role)
return false;
}
if (except_ids.count(user_id))
return false;
bool in_except_list = std::any_of(
enabled_roles.begin(), enabled_roles.end(), [this](const UUID & enabled_role) { return except_ids.count(enabled_role); });
return !in_except_list;
}
bool ExtendedRoleSet::match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const bool ExtendedRoleSet::match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const
{ {
if (!all && !ids.count(user_id)) if (!all && !ids.count(user_id))

View File

@ -36,10 +36,9 @@ struct ExtendedRoleSet
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id); ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id);
std::shared_ptr<ASTExtendedRoleSet> toAST() const; std::shared_ptr<ASTExtendedRoleSet> toAST() const;
String toString() const;
Strings toStrings() const;
std::shared_ptr<ASTExtendedRoleSet> toASTWithNames(const AccessControlManager & manager) const; std::shared_ptr<ASTExtendedRoleSet> toASTWithNames(const AccessControlManager & manager) const;
String toString() const;
String toStringWithNames(const AccessControlManager & manager) const; String toStringWithNames(const AccessControlManager & manager) const;
Strings toStringsWithNames(const AccessControlManager & manager) const; Strings toStringsWithNames(const AccessControlManager & manager) const;
@ -50,7 +49,6 @@ struct ExtendedRoleSet
/// Checks if a specified ID matches this ExtendedRoleSet. /// Checks if a specified ID matches this ExtendedRoleSet.
bool match(const UUID & id) const; bool match(const UUID & id) const;
bool match(const UUID & user_id, const std::vector<UUID> & enabled_roles) const;
bool match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const; bool match(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles) const;
/// Returns a list of matching IDs. The function must not be called if `all` == `true`. /// Returns a list of matching IDs. The function must not be called if `all` == `true`.

View File

@ -167,12 +167,7 @@ QuotaCache::QuotaCache(const AccessControlManager & access_control_manager_)
QuotaCache::~QuotaCache() = default; QuotaCache::~QuotaCache() = default;
std::shared_ptr<const EnabledQuota> QuotaCache::getEnabledQuota( std::shared_ptr<const EnabledQuota> QuotaCache::getEnabledQuota(const UUID & user_id, const String & user_name, const boost::container::flat_set<UUID> & enabled_roles, const Poco::Net::IPAddress & client_address, const String & client_key)
const UUID & user_id,
const String & user_name,
const std::vector<UUID> & enabled_roles,
const Poco::Net::IPAddress & client_address,
const String & client_key)
{ {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
ensureAllQuotasRead(); ensureAllQuotasRead();

View File

@ -20,13 +20,7 @@ public:
QuotaCache(const AccessControlManager & access_control_manager_); QuotaCache(const AccessControlManager & access_control_manager_);
~QuotaCache(); ~QuotaCache();
std::shared_ptr<const EnabledQuota> getEnabledQuota( std::shared_ptr<const EnabledQuota> getEnabledQuota(const UUID & user_id, const String & user_name, const boost::container::flat_set<UUID> & enabled_roles, const Poco::Net::IPAddress & address, const String & client_key);
const UUID & user_id,
const String & user_name,
const std::vector<UUID> & enabled_roles,
const Poco::Net::IPAddress & address,
const String & client_key);
std::vector<QuotaUsageInfo> getUsageInfo() const; std::vector<QuotaUsageInfo> getUsageInfo() const;
private: private:

View File

@ -2,68 +2,56 @@
#include <Access/Role.h> #include <Access/Role.h>
#include <Access/EnabledRolesInfo.h> #include <Access/EnabledRolesInfo.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <boost/container/flat_map.hpp> #include <boost/container/flat_set.hpp>
namespace DB namespace DB
{ {
namespace namespace
{ {
struct CollectedRoleInfo void collectRoles(EnabledRolesInfo & roles_info,
{ boost::container::flat_set<UUID> & skip_ids,
RolePtr role;
bool is_current_role = false;
bool with_admin_option = false;
};
void collectRoles(boost::container::flat_map<UUID, CollectedRoleInfo> & collected_roles,
const std::function<RolePtr(const UUID &)> & get_role_function, const std::function<RolePtr(const UUID &)> & get_role_function,
const UUID & role_id, const UUID & role_id,
bool is_current_role, bool is_current_role,
bool with_admin_option) bool with_admin_option)
{ {
auto it = collected_roles.find(role_id); if (roles_info.enabled_roles.count(role_id))
if (it != collected_roles.end())
{ {
it->second.is_current_role |= is_current_role; if (is_current_role)
it->second.with_admin_option |= with_admin_option; roles_info.current_roles.emplace(role_id);
if (with_admin_option)
roles_info.enabled_roles_with_admin_option.emplace(role_id);
return; return;
} }
if (skip_ids.count(role_id))
return;
auto role = get_role_function(role_id); auto role = get_role_function(role_id);
collected_roles[role_id] = CollectedRoleInfo{role, is_current_role, with_admin_option};
if (!role) if (!role)
{
skip_ids.emplace(role_id);
return; return;
}
roles_info.enabled_roles.emplace(role_id);
if (is_current_role)
roles_info.current_roles.emplace(role_id);
if (with_admin_option)
roles_info.enabled_roles_with_admin_option.emplace(role_id);
roles_info.names_of_roles[role_id] = role->getName();
roles_info.access.merge(role->access.access);
roles_info.access_with_grant_option.merge(role->access.access_with_grant_option);
roles_info.settings_from_enabled_roles.merge(role->settings);
for (const auto & granted_role : role->granted_roles.roles) for (const auto & granted_role : role->granted_roles.roles)
collectRoles(collected_roles, get_role_function, granted_role, false, false); collectRoles(roles_info, skip_ids, get_role_function, granted_role, false, false);
for (const auto & granted_role : role->granted_roles.roles_with_admin_option) for (const auto & granted_role : role->granted_roles.roles_with_admin_option)
collectRoles(collected_roles, get_role_function, granted_role, false, true); collectRoles(roles_info, skip_ids, get_role_function, granted_role, false, true);
}
std::shared_ptr<EnabledRolesInfo> collectInfoForRoles(const boost::container::flat_map<UUID, CollectedRoleInfo> & roles)
{
auto new_info = std::make_shared<EnabledRolesInfo>();
for (const auto & [role_id, collect_info] : roles)
{
const auto & role = collect_info.role;
if (!role)
continue;
if (collect_info.is_current_role)
new_info->current_roles.emplace_back(role_id);
new_info->enabled_roles.emplace_back(role_id);
if (collect_info.with_admin_option)
new_info->enabled_roles_with_admin_option.emplace_back(role_id);
new_info->names_of_roles[role_id] = role->getName();
new_info->access.merge(role->access.access);
new_info->access_with_grant_option.merge(role->access.access_with_grant_option);
new_info->settings_from_enabled_roles.merge(role->settings);
}
return new_info;
} }
} }
@ -75,8 +63,8 @@ RoleCache::RoleCache(const AccessControlManager & manager_)
RoleCache::~RoleCache() = default; RoleCache::~RoleCache() = default;
std::shared_ptr<const EnabledRoles> RoleCache::getEnabledRoles( std::shared_ptr<const EnabledRoles>
const std::vector<UUID> & roles, const std::vector<UUID> & roles_with_admin_option) RoleCache::getEnabledRoles(const boost::container::flat_set<UUID> & roles, const boost::container::flat_set<UUID> & roles_with_admin_option)
{ {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
@ -93,13 +81,13 @@ std::shared_ptr<const EnabledRoles> RoleCache::getEnabledRoles(
} }
auto res = std::shared_ptr<EnabledRoles>(new EnabledRoles(params)); auto res = std::shared_ptr<EnabledRoles>(new EnabledRoles(params));
collectRolesInfoFor(*res); collectEnabledRoles(*res);
enabled_roles.emplace(std::move(params), res); enabled_roles.emplace(std::move(params), res);
return res; return res;
} }
void RoleCache::collectRolesInfo() void RoleCache::collectEnabledRoles()
{ {
/// `mutex` is already locked. /// `mutex` is already locked.
@ -110,28 +98,29 @@ void RoleCache::collectRolesInfo()
i = enabled_roles.erase(i); i = enabled_roles.erase(i);
else else
{ {
collectRolesInfoFor(*elem); collectEnabledRoles(*elem);
++i; ++i;
} }
} }
} }
void RoleCache::collectRolesInfoFor(EnabledRoles & enabled) void RoleCache::collectEnabledRoles(EnabledRoles & enabled)
{ {
/// `mutex` is already locked. /// `mutex` is already locked.
/// Collect roles in use. That includes the current roles, the roles granted to the current roles, and so on. /// Collect enabled roles. That includes the current roles, the roles granted to the current roles, and so on.
boost::container::flat_map<UUID, CollectedRoleInfo> collected_roles; auto new_info = std::make_shared<EnabledRolesInfo>();
boost::container::flat_set<UUID> skip_ids;
auto get_role_function = [this](const UUID & id) { return getRole(id); }; auto get_role_function = [this](const UUID & id) { return getRole(id); };
for (const auto & current_role : enabled.params.current_roles) for (const auto & current_role : enabled.params.current_roles)
collectRoles(collected_roles, get_role_function, current_role, true, false); collectRoles(*new_info, skip_ids, get_role_function, current_role, true, false);
for (const auto & current_role : enabled.params.current_roles_with_admin_option) for (const auto & current_role : enabled.params.current_roles_with_admin_option)
collectRoles(collected_roles, get_role_function, current_role, true, true); collectRoles(*new_info, skip_ids, get_role_function, current_role, true, true);
/// Collect data from the collected roles. /// Collect data from the collected roles.
enabled.setRolesInfo(collectInfoForRoles(collected_roles)); enabled.setRolesInfo(new_info);
} }
@ -174,7 +163,7 @@ void RoleCache::roleChanged(const UUID & role_id, const RolePtr & changed_role)
return; return;
role_from_cache->first = changed_role; role_from_cache->first = changed_role;
cache.update(role_id, role_from_cache); cache.update(role_id, role_from_cache);
collectRolesInfo(); collectEnabledRoles();
} }
@ -182,7 +171,7 @@ void RoleCache::roleRemoved(const UUID & role_id)
{ {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
cache.remove(role_id); cache.remove(role_id);
collectRolesInfo(); collectEnabledRoles();
} }
} }

View File

@ -2,6 +2,7 @@
#include <Access/EnabledRoles.h> #include <Access/EnabledRoles.h>
#include <Poco/ExpireCache.h> #include <Poco/ExpireCache.h>
#include <boost/container/flat_set.hpp>
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -18,11 +19,12 @@ public:
RoleCache(const AccessControlManager & manager_); RoleCache(const AccessControlManager & manager_);
~RoleCache(); ~RoleCache();
std::shared_ptr<const EnabledRoles> getEnabledRoles(const std::vector<UUID> & current_roles, const std::vector<UUID> & current_roles_with_admin_option); std::shared_ptr<const EnabledRoles> getEnabledRoles(
const boost::container::flat_set<UUID> & current_roles, const boost::container::flat_set<UUID> & current_roles_with_admin_option);
private: private:
void collectRolesInfo(); void collectEnabledRoles();
void collectRolesInfoFor(EnabledRoles & enabled); void collectEnabledRoles(EnabledRoles & enabled);
RolePtr getRole(const UUID & role_id); RolePtr getRole(const UUID & role_id);
void roleChanged(const UUID & role_id, const RolePtr & changed_role); void roleChanged(const UUID & role_id, const RolePtr & changed_role);
void roleRemoved(const UUID & role_id); void roleRemoved(const UUID & role_id);

View File

@ -99,7 +99,7 @@ RowPolicyCache::RowPolicyCache(const AccessControlManager & access_control_manag
RowPolicyCache::~RowPolicyCache() = default; RowPolicyCache::~RowPolicyCache() = default;
std::shared_ptr<const EnabledRowPolicies> RowPolicyCache::getEnabledRowPolicies(const UUID & user_id, const std::vector<UUID> & enabled_roles) std::shared_ptr<const EnabledRowPolicies> RowPolicyCache::getEnabledRowPolicies(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles)
{ {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};
ensureAllRowPoliciesRead(); ensureAllRowPoliciesRead();

View File

@ -18,7 +18,7 @@ public:
RowPolicyCache(const AccessControlManager & access_control_manager_); RowPolicyCache(const AccessControlManager & access_control_manager_);
~RowPolicyCache(); ~RowPolicyCache();
std::shared_ptr<const EnabledRowPolicies> getEnabledRowPolicies(const UUID & user_id, const std::vector<UUID> & enabled_roles); std::shared_ptr<const EnabledRowPolicies> getEnabledRowPolicies(const UUID & user_id, const boost::container::flat_set<UUID> & enabled_roles);
private: private:
using ParsedConditions = EnabledRowPolicies::ParsedConditions; using ParsedConditions = EnabledRowPolicies::ParsedConditions;

View File

@ -183,7 +183,7 @@ void SettingsProfilesCache::substituteProfiles(SettingsProfileElements & element
std::shared_ptr<const EnabledSettings> SettingsProfilesCache::getEnabledSettings( std::shared_ptr<const EnabledSettings> SettingsProfilesCache::getEnabledSettings(
const UUID & user_id, const UUID & user_id,
const SettingsProfileElements & settings_from_user, const SettingsProfileElements & settings_from_user,
const std::vector<UUID> & enabled_roles, const boost::container::flat_set<UUID> & enabled_roles,
const SettingsProfileElements & settings_from_enabled_roles) const SettingsProfileElements & settings_from_enabled_roles)
{ {
std::lock_guard lock{mutex}; std::lock_guard lock{mutex};

View File

@ -29,7 +29,7 @@ public:
std::shared_ptr<const EnabledSettings> getEnabledSettings( std::shared_ptr<const EnabledSettings> getEnabledSettings(
const UUID & user_id, const UUID & user_id,
const SettingsProfileElements & settings_from_user_, const SettingsProfileElements & settings_from_user_,
const std::vector<UUID> & enabled_roles, const boost::container::flat_set<UUID> & enabled_roles,
const SettingsProfileElements & settings_from_enabled_roles_); const SettingsProfileElements & settings_from_enabled_roles_);
std::shared_ptr<const SettingsChanges> getProfileSettings(const String & profile_name); std::shared_ptr<const SettingsChanges> getProfileSettings(const String & profile_name);

View File

@ -28,6 +28,7 @@
#include <Core/Settings.h> #include <Core/Settings.h>
#include <Access/AccessControlManager.h> #include <Access/AccessControlManager.h>
#include <Access/ContextAccess.h> #include <Access/ContextAccess.h>
#include <Access/EnabledRolesInfo.h>
#include <Access/EnabledRowPolicies.h> #include <Access/EnabledRowPolicies.h>
#include <Access/User.h> #include <Access/User.h>
#include <Access/SettingsProfile.h> #include <Access/SettingsProfile.h>
@ -698,7 +699,7 @@ std::optional<UUID> Context::getUserID() const
} }
void Context::setCurrentRoles(const std::vector<UUID> & current_roles_) void Context::setCurrentRoles(const boost::container::flat_set<UUID> & current_roles_)
{ {
auto lock = getLock(); auto lock = getLock();
if (current_roles == current_roles_ && !use_default_roles) if (current_roles == current_roles_ && !use_default_roles)
@ -718,24 +719,19 @@ void Context::setCurrentRolesDefault()
calculateAccessRights(); calculateAccessRights();
} }
std::vector<UUID> Context::getCurrentRoles() const boost::container::flat_set<UUID> Context::getCurrentRoles() const
{ {
return getAccess()->getCurrentRoles(); return getRolesInfo()->current_roles;
} }
Strings Context::getCurrentRolesNames() const boost::container::flat_set<UUID> Context::getEnabledRoles() const
{ {
return getAccess()->getCurrentRolesNames(); return getRolesInfo()->enabled_roles;
} }
std::vector<UUID> Context::getEnabledRoles() const std::shared_ptr<const EnabledRolesInfo> Context::getRolesInfo() const
{ {
return getAccess()->getEnabledRoles(); return getAccess()->getRolesInfo();
}
Strings Context::getEnabledRolesNames() const
{
return getAccess()->getEnabledRolesNames();
} }

View File

@ -51,6 +51,7 @@ class Context;
class ContextAccess; class ContextAccess;
struct User; struct User;
using UserPtr = std::shared_ptr<const User>; using UserPtr = std::shared_ptr<const User>;
struct EnabledRolesInfo;
class EnabledRowPolicies; class EnabledRowPolicies;
class EnabledQuota; class EnabledQuota;
class AccessFlags; class AccessFlags;
@ -166,7 +167,7 @@ private:
InputBlocksReader input_blocks_reader; InputBlocksReader input_blocks_reader;
std::optional<UUID> user_id; std::optional<UUID> user_id;
std::vector<UUID> current_roles; boost::container::flat_set<UUID> current_roles;
bool use_default_roles = false; bool use_default_roles = false;
std::shared_ptr<const ContextAccess> access; std::shared_ptr<const ContextAccess> access;
std::shared_ptr<const EnabledRowPolicies> initial_row_policy; std::shared_ptr<const EnabledRowPolicies> initial_row_policy;
@ -254,12 +255,11 @@ public:
String getUserName() const; String getUserName() const;
std::optional<UUID> getUserID() const; std::optional<UUID> getUserID() const;
void setCurrentRoles(const std::vector<UUID> & current_roles_); void setCurrentRoles(const boost::container::flat_set<UUID> & current_roles_);
void setCurrentRolesDefault(); void setCurrentRolesDefault();
std::vector<UUID> getCurrentRoles() const; boost::container::flat_set<UUID> getCurrentRoles() const;
Strings getCurrentRolesNames() const; boost::container::flat_set<UUID> getEnabledRoles() const;
std::vector<UUID> getEnabledRoles() const; std::shared_ptr<const EnabledRolesInfo> getRolesInfo() const;
Strings getEnabledRolesNames() const;
/// Checks access rights. /// Checks access rights.
/// Empty database means the current database. /// Empty database means the current database.

View File

@ -39,20 +39,20 @@ void InterpreterSetRoleQuery::setRole(const ASTSetRoleQuery & query)
else else
{ {
ExtendedRoleSet roles_from_query{*query.roles, access_control}; ExtendedRoleSet roles_from_query{*query.roles, access_control};
std::vector<UUID> new_current_roles; boost::container::flat_set<UUID> new_current_roles;
if (roles_from_query.all) if (roles_from_query.all)
{ {
for (const auto & id : user->granted_roles.roles) for (const auto & id : user->granted_roles.roles)
if (roles_from_query.match(id)) if (roles_from_query.match(id))
new_current_roles.push_back(id); new_current_roles.emplace(id);
} }
else else
{ {
for (const auto & id : roles_from_query.getMatchingIDs()) for (const auto & id : roles_from_query.getMatchingIDs())
{ {
if (!user->granted_roles.roles.contains(id)) if (!user->granted_roles.roles.count(id))
throw Exception("Role should be granted to set current", ErrorCodes::SET_NON_GRANTED_ROLE); throw Exception("Role should be granted to set current", ErrorCodes::SET_NON_GRANTED_ROLE);
new_current_roles.push_back(id); new_current_roles.emplace(id);
} }
} }
session_context.setCurrentRoles(new_current_roles); session_context.setCurrentRoles(new_current_roles);
@ -85,7 +85,7 @@ void InterpreterSetRoleQuery::updateUserSetDefaultRoles(User & user, const Exten
{ {
for (const auto & id : roles_from_query.getMatchingIDs()) for (const auto & id : roles_from_query.getMatchingIDs())
{ {
if (!user.granted_roles.roles.contains(id)) if (!user.granted_roles.roles.count(id))
throw Exception("Role should be granted to set default", ErrorCodes::SET_NON_GRANTED_ROLE); throw Exception("Role should be granted to set default", ErrorCodes::SET_NON_GRANTED_ROLE);
} }
} }