Add the parameter custom_settings_prefixes to the server config.

This commit is contained in:
Vitaly Baranov 2020-07-29 02:39:18 +03:00
parent f73a4749cf
commit 7c4ae5ee65
9 changed files with 121 additions and 12 deletions

View File

@ -614,6 +614,9 @@ int Server::main(const std::vector<std::string> & /*args*/)
}
global_context->setUncompressedCache(uncompressed_cache_size);
if (config().has("custom_settings_prefixes"))
global_context->getAccessControlManager().setCustomSettingsPrefixes(config().getString("custom_settings_prefixes"));
/// Load global settings from default_profile and system_profile.
global_context->setDefaultProfiles(config());
const Settings & settings = global_context->getSettingsRef();

View File

@ -262,6 +262,9 @@
<!-- Default profile of settings. -->
<default_profile>default</default_profile>
<!-- Comma-separated list of prefixes for user-defined settings. -->
<custom_settings_prefixes></custom_settings_prefixes>
<!-- System profile of settings. This settings are used by internal processes (Buffer storage, Distibuted DDL worker and so on). -->
<!-- <system_profile>default</system_profile> -->

View File

@ -11,12 +11,19 @@
#include <Access/SettingsProfilesCache.h>
#include <Access/ExternalAuthenticators.h>
#include <Core/Settings.h>
#include <common/find_symbols.h>
#include <Poco/ExpireCache.h>
#include <boost/algorithm/string/join.hpp>
#include <mutex>
namespace DB
{
namespace ErrorCodes
{
extern const int UNKNOWN_SETTING;
}
namespace
{
std::vector<std::unique_ptr<IAccessStorage>> createStorages()
@ -59,6 +66,53 @@ private:
};
class AccessControlManager::CustomSettingsPrefixes
{
public:
void registerPrefixes(const Strings & prefixes_)
{
std::lock_guard lock{mutex};
registered_prefixes = prefixes_;
}
bool isSettingNameAllowed(const std::string_view & setting_name) const
{
if (Settings::hasBuiltin(setting_name))
return true;
std::lock_guard lock{mutex};
for (const auto & prefix : registered_prefixes)
{
if (setting_name.starts_with(prefix))
return true;
}
return false;
}
void checkSettingNameIsAllowed(const std::string_view & setting_name) const
{
if (isSettingNameAllowed(setting_name))
return;
std::lock_guard lock{mutex};
if (!registered_prefixes.empty())
{
throw Exception(
"Setting " + String{setting_name} + " is neither a builtin setting nor started with the prefix '"
+ boost::algorithm::join(registered_prefixes, "' or '") + "' registered for user-defined settings",
ErrorCodes::UNKNOWN_SETTING);
}
else
BaseSettingsHelpers::throwSettingNotFound(setting_name);
}
private:
Strings registered_prefixes;
mutable std::mutex mutex;
};
AccessControlManager::AccessControlManager()
: MultipleAccessStorage(createStorages()),
context_access_cache(std::make_unique<ContextAccessCache>(*this)),
@ -66,7 +120,8 @@ AccessControlManager::AccessControlManager()
row_policy_cache(std::make_unique<RowPolicyCache>(*this)),
quota_cache(std::make_unique<QuotaCache>(*this)),
settings_profiles_cache(std::make_unique<SettingsProfilesCache>(*this)),
external_authenticators(std::make_unique<ExternalAuthenticators>())
external_authenticators(std::make_unique<ExternalAuthenticators>()),
custom_settings_prefixes(std::make_unique<CustomSettingsPrefixes>())
{
}
@ -100,6 +155,29 @@ void AccessControlManager::setDefaultProfileName(const String & default_profile_
}
void AccessControlManager::setCustomSettingsPrefixes(const Strings & prefixes)
{
custom_settings_prefixes->registerPrefixes(prefixes);
}
void AccessControlManager::setCustomSettingsPrefixes(const String & comma_separated_prefixes)
{
Strings prefixes;
splitInto<','>(prefixes, comma_separated_prefixes);
setCustomSettingsPrefixes(prefixes);
}
bool AccessControlManager::isSettingNameAllowed(const std::string_view & setting_name) const
{
return custom_settings_prefixes->isSettingNameAllowed(setting_name);
}
void AccessControlManager::checkSettingNameIsAllowed(const std::string_view & setting_name) const
{
custom_settings_prefixes->checkSettingNameIsAllowed(setting_name);
}
std::shared_ptr<const ContextAccess> AccessControlManager::getContextAccess(
const UUID & user_id,
const boost::container::flat_set<UUID> & current_roles,

View File

@ -53,6 +53,13 @@ public:
void setUsersConfig(const Poco::Util::AbstractConfiguration & users_config);
void setDefaultProfileName(const String & default_profile_name);
/// Sets prefixes which should be used for custom settings.
/// This function also enables custom prefixes to be used.
void setCustomSettingsPrefixes(const Strings & prefixes);
void setCustomSettingsPrefixes(const String & comma_separated_prefixes);
bool isSettingNameAllowed(const std::string_view & name) const;
void checkSettingNameIsAllowed(const std::string_view & name) const;
std::shared_ptr<const ContextAccess> getContextAccess(
const UUID & user_id,
const boost::container::flat_set<UUID> & current_roles,
@ -89,14 +96,15 @@ public:
const ExternalAuthenticators & getExternalAuthenticators() const;
private:
class ContextAccessCache;
private: class ContextAccessCache;
class CustomSettingsPrefixes;
std::unique_ptr<ContextAccessCache> context_access_cache;
std::unique_ptr<RoleCache> role_cache;
std::unique_ptr<RowPolicyCache> row_policy_cache;
std::unique_ptr<QuotaCache> quota_cache;
std::unique_ptr<SettingsProfilesCache> settings_profiles_cache;
std::unique_ptr<ExternalAuthenticators> external_authenticators;
std::unique_ptr<CustomSettingsPrefixes> custom_settings_prefixes;
};
}

View File

@ -1,4 +1,5 @@
#include <Access/SettingsConstraints.h>
#include <Access/AccessControlManager.h>
#include <Core/Settings.h>
#include <Common/FieldVisitors.h>
#include <Common/FieldVisitorsAccurateComparison.h>
@ -16,7 +17,11 @@ namespace ErrorCodes
extern const int SETTING_CONSTRAINT_VIOLATION;
}
SettingsConstraints::SettingsConstraints() = default;
SettingsConstraints::SettingsConstraints(const AccessControlManager & manager_) : manager(&manager_)
{
}
SettingsConstraints::SettingsConstraints(const SettingsConstraints & src) = default;
SettingsConstraints & SettingsConstraints::operator=(const SettingsConstraints & src) = default;
SettingsConstraints::SettingsConstraints(SettingsConstraints && src) = default;
@ -191,6 +196,11 @@ bool SettingsConstraints::checkImpl(const Settings & current_settings, SettingCh
}
};
if (reaction == THROW_ON_VIOLATION)
manager->checkSettingNameIsAllowed(setting_name);
else if (!manager->isSettingNameAllowed(setting_name))
return false;
Field current_value, new_value;
if (current_settings.tryGet(setting_name, current_value))
{
@ -316,9 +326,8 @@ bool SettingsConstraints::Constraint::operator==(const Constraint & other) const
&& (*setting_name == *other.setting_name);
}
bool operator ==(const SettingsConstraints & left, const SettingsConstraints & right)
{
return left.constraints == right.constraints;
return (left.constraints == right.constraints);
}
}

View File

@ -14,6 +14,7 @@ namespace DB
struct Settings;
struct SettingChange;
class SettingsChanges;
class AccessControlManager;
/** Checks if specified changes of settings are allowed or not.
@ -50,7 +51,7 @@ class SettingsChanges;
class SettingsConstraints
{
public:
SettingsConstraints();
SettingsConstraints(const AccessControlManager & manager_);
SettingsConstraints(const SettingsConstraints & src);
SettingsConstraints & operator =(const SettingsConstraints & src);
SettingsConstraints(SettingsConstraints && src);
@ -108,6 +109,7 @@ private:
const Constraint * tryGetConstraint(const std::string_view & setting_name) const;
std::unordered_map<std::string_view, Constraint> constraints;
const AccessControlManager * manager = nullptr;
};
}

View File

@ -48,6 +48,10 @@ void SettingsProfileElement::init(const ASTSettingsProfileElement & ast, const A
min_value = Settings::castValueUtil(setting_name, min_value);
if (!max_value.isNull())
max_value = Settings::castValueUtil(setting_name, max_value);
/// Optionally check if a setting with that name is allowed.
if (manager)
manager->checkSettingNameIsAllowed(setting_name);
}
}
@ -149,9 +153,9 @@ SettingsChanges SettingsProfileElements::toSettingsChanges() const
return res;
}
SettingsConstraints SettingsProfileElements::toSettingsConstraints() const
SettingsConstraints SettingsProfileElements::toSettingsConstraints(const AccessControlManager & manager) const
{
SettingsConstraints res;
SettingsConstraints res{manager};
for (const auto & elem : *this)
{
if (!elem.setting_name.empty())

View File

@ -61,7 +61,7 @@ public:
Settings toSettings() const;
SettingsChanges toSettingsChanges() const;
SettingsConstraints toSettingsConstraints() const;
SettingsConstraints toSettingsConstraints(const AccessControlManager & manager) const;
};
}

View File

@ -103,6 +103,7 @@ void SettingsProfilesCache::setDefaultProfileName(const String & default_profile
default_profile_id = it->second;
}
void SettingsProfilesCache::mergeSettingsAndConstraints()
{
/// `mutex` is already locked.
@ -143,9 +144,10 @@ void SettingsProfilesCache::mergeSettingsAndConstraintsFor(EnabledSettings & ena
substituteProfiles(merged_settings);
auto settings = merged_settings.toSettings();
auto constraints = merged_settings.toSettingsConstraints(manager);
enabled.setSettingsAndConstraints(
std::make_shared<Settings>(merged_settings.toSettings()),
std::make_shared<SettingsConstraints>(merged_settings.toSettingsConstraints()));
std::make_shared<Settings>(std::move(settings)), std::make_shared<SettingsConstraints>(std::move(constraints)));
}