2020-03-07 17:37:38 +00:00
# include <Access/ContextAccess.h>
2021-11-02 11:06:20 +00:00
# include <Access/AccessControl.h>
2020-03-07 17:37:38 +00:00
# include <Access/EnabledRoles.h>
# include <Access/EnabledRowPolicies.h>
# include <Access/EnabledQuota.h>
2020-05-08 12:50:45 +00:00
# include <Access/QuotaUsage.h>
2020-03-07 17:37:38 +00:00
# include <Access/User.h>
# include <Access/EnabledRolesInfo.h>
2020-03-04 22:27:03 +00:00
# include <Access/EnabledSettings.h>
2021-07-22 16:07:03 +00:00
# include <Access/SettingsProfilesInfo.h>
2020-03-07 17:37:38 +00:00
# include <Interpreters/DatabaseCatalog.h>
# include <Common/Exception.h>
# include <Common/quoteString.h>
# include <Core/Settings.h>
# include <IO/WriteHelpers.h>
# include <Poco/Logger.h>
2021-10-02 07:13:14 +00:00
# include <base/logger_useful.h>
2020-03-07 17:37:38 +00:00
# include <boost/algorithm/string/join.hpp>
# include <boost/range/algorithm/set_algorithm.hpp>
# include <assert.h>
namespace DB
{
namespace ErrorCodes
{
extern const int ACCESS_DENIED ;
extern const int READONLY ;
extern const int QUERY_IS_PROHIBITED ;
extern const int FUNCTION_NOT_ALLOWED ;
extern const int UNKNOWN_USER ;
}
namespace
{
2020-07-07 10:00:49 +00:00
AccessRights mixAccessRightsFromUserAndRoles ( const User & user , const EnabledRolesInfo & roles_info )
2020-03-07 17:37:38 +00:00
{
2020-07-07 10:00:49 +00:00
AccessRights res = user . access ;
res . makeUnion ( roles_info . access ) ;
2020-07-02 00:09:57 +00:00
return res ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 14:24:32 +00:00
AccessRights addImplicitAccessRights ( const AccessRights & access )
2020-07-07 10:00:49 +00:00
{
auto modifier = [ & ] ( const AccessFlags & flags , const AccessFlags & min_flags_with_children , const AccessFlags & max_flags_with_children , const std : : string_view & database , const std : : string_view & table , const std : : string_view & column ) - > AccessFlags
{
size_t level = ! database . empty ( ) + ! table . empty ( ) + ! column . empty ( ) ;
AccessFlags res = flags ;
/// CREATE_TABLE => CREATE_VIEW, DROP_TABLE => DROP_VIEW, ALTER_TABLE => ALTER_VIEW
static const AccessFlags create_table = AccessType : : CREATE_TABLE ;
static const AccessFlags create_view = AccessType : : CREATE_VIEW ;
static const AccessFlags drop_table = AccessType : : DROP_TABLE ;
static const AccessFlags drop_view = AccessType : : DROP_VIEW ;
static const AccessFlags alter_table = AccessType : : ALTER_TABLE ;
static const AccessFlags alter_view = AccessType : : ALTER_VIEW ;
if ( res & create_table )
res | = create_view ;
if ( res & drop_table )
res | = drop_view ;
if ( res & alter_table )
res | = alter_view ;
2020-10-26 19:12:40 +00:00
/// CREATE TABLE (on any database/table) => CREATE_TEMPORARY_TABLE (global)
2020-07-07 10:00:49 +00:00
static const AccessFlags create_temporary_table = AccessType : : CREATE_TEMPORARY_TABLE ;
if ( ( level = = 0 ) & & ( max_flags_with_children & create_table ) )
res | = create_temporary_table ;
/// ALTER_TTL => ALTER_MATERIALIZE_TTL
static const AccessFlags alter_ttl = AccessType : : ALTER_TTL ;
static const AccessFlags alter_materialize_ttl = AccessType : : ALTER_MATERIALIZE_TTL ;
if ( res & alter_ttl )
res | = alter_materialize_ttl ;
/// RELOAD_DICTIONARY (global) => RELOAD_EMBEDDED_DICTIONARIES (global)
static const AccessFlags reload_dictionary = AccessType : : SYSTEM_RELOAD_DICTIONARY ;
static const AccessFlags reload_embedded_dictionaries = AccessType : : SYSTEM_RELOAD_EMBEDDED_DICTIONARIES ;
if ( ( level = = 0 ) & & ( min_flags_with_children & reload_dictionary ) )
res | = reload_embedded_dictionaries ;
/// any column flag => SHOW_COLUMNS => SHOW_TABLES => SHOW_DATABASES
/// any table flag => SHOW_TABLES => SHOW_DATABASES
/// any dictionary flag => SHOW_DICTIONARIES => SHOW_DATABASES
/// any database flag => SHOW_DATABASES
static const AccessFlags show_columns = AccessType : : SHOW_COLUMNS ;
static const AccessFlags show_tables = AccessType : : SHOW_TABLES ;
static const AccessFlags show_dictionaries = AccessType : : SHOW_DICTIONARIES ;
static const AccessFlags show_tables_or_dictionaries = show_tables | show_dictionaries ;
static const AccessFlags show_databases = AccessType : : SHOW_DATABASES ;
if ( res & AccessFlags : : allColumnFlags ( ) )
res | = show_columns ;
if ( ( res & AccessFlags : : allTableFlags ( ) )
| | ( level < = 2 & & ( res & show_columns ) )
| | ( level = = 2 & & ( max_flags_with_children & show_columns ) ) )
{
res | = show_tables ;
}
if ( res & AccessFlags : : allDictionaryFlags ( ) )
res | = show_dictionaries ;
if ( ( res & AccessFlags : : allDatabaseFlags ( ) )
| | ( level < = 1 & & ( res & show_tables_or_dictionaries ) )
| | ( level = = 1 & & ( max_flags_with_children & show_tables_or_dictionaries ) ) )
{
res | = show_databases ;
}
return res ;
} ;
2020-12-08 14:24:32 +00:00
AccessRights res = access ;
res . modifyFlags ( modifier ) ;
2020-07-07 10:00:49 +00:00
2021-09-09 09:37:51 +00:00
/// Anyone has access to the "system" and "information_schema" database.
2020-12-08 14:24:32 +00:00
res . grant ( AccessType : : SELECT , DatabaseCatalog : : SYSTEM_DATABASE ) ;
2021-09-09 09:37:51 +00:00
res . grant ( AccessType : : SELECT , DatabaseCatalog : : INFORMATION_SCHEMA ) ;
res . grant ( AccessType : : SELECT , DatabaseCatalog : : INFORMATION_SCHEMA_UPPERCASE ) ;
2020-12-08 14:24:32 +00:00
return res ;
2020-07-02 00:09:57 +00:00
}
std : : array < UUID , 1 > to_array ( const UUID & id )
{
std : : array < UUID , 1 > ids ;
ids [ 0 ] = id ;
return ids ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 14:24:32 +00:00
/// Helper for using in templates.
std : : string_view getDatabase ( ) { return { } ; }
template < typename . . . OtherArgs >
std : : string_view getDatabase ( const std : : string_view & arg1 , const OtherArgs & . . . ) { return arg1 ; }
2020-03-07 17:37:38 +00:00
}
2021-11-02 11:06:20 +00:00
ContextAccess : : ContextAccess ( const AccessControl & access_control_ , const Params & params_ )
: access_control ( & access_control_ )
2020-03-07 17:37:38 +00:00
, params ( params_ )
{
2021-05-17 07:03:26 +00:00
std : : lock_guard lock { mutex } ;
2021-11-02 11:06:20 +00:00
subscription_for_user_change = access_control - > subscribeForChanges (
2020-03-07 17:37:38 +00:00
* params . user_id , [ this ] ( const UUID & , const AccessEntityPtr & entity )
{
UserPtr changed_user = entity ? typeid_cast < UserPtr > ( entity ) : nullptr ;
2021-05-17 07:03:26 +00:00
std : : lock_guard lock2 { mutex } ;
2020-03-07 17:37:38 +00:00
setUser ( changed_user ) ;
} ) ;
2021-11-02 11:06:20 +00:00
setUser ( access_control - > read < User > ( * params . user_id ) ) ;
2020-03-07 17:37:38 +00:00
}
void ContextAccess : : setUser ( const UserPtr & user_ ) const
{
user = user_ ;
if ( ! user )
{
/// User has been dropped.
subscription_for_user_change = { } ;
subscription_for_roles_changes = { } ;
2021-07-15 08:55:51 +00:00
access = nullptr ;
access_with_implicit = nullptr ;
2020-03-07 17:37:38 +00:00
enabled_roles = nullptr ;
roles_info = nullptr ;
enabled_row_policies = nullptr ;
enabled_quota = nullptr ;
2020-03-04 22:27:03 +00:00
enabled_settings = nullptr ;
2020-03-07 17:37:38 +00:00
return ;
}
user_name = user - > getName ( ) ;
trace_log = & Poco : : Logger : : get ( " ContextAccess ( " + user_name + " ) " ) ;
2021-02-26 22:37:00 +00:00
std : : vector < UUID > current_roles , current_roles_with_admin_option ;
2020-03-07 17:37:38 +00:00
if ( params . use_default_roles )
{
2021-02-26 22:37:00 +00:00
current_roles = user - > granted_roles . findGranted ( user - > default_roles ) ;
current_roles_with_admin_option = user - > granted_roles . findGrantedWithAdminOption ( user - > default_roles ) ;
2020-03-07 17:37:38 +00:00
}
else
{
2021-02-26 22:37:00 +00:00
current_roles = user - > granted_roles . findGranted ( params . current_roles ) ;
current_roles_with_admin_option = user - > granted_roles . findGrantedWithAdminOption ( params . current_roles ) ;
2020-03-07 17:37:38 +00:00
}
2021-05-17 07:03:26 +00:00
subscription_for_roles_changes . reset ( ) ;
2021-11-02 11:06:20 +00:00
enabled_roles = access_control - > getEnabledRoles ( current_roles , current_roles_with_admin_option ) ;
2020-03-07 17:37:38 +00:00
subscription_for_roles_changes = enabled_roles - > subscribeForChanges ( [ this ] ( const std : : shared_ptr < const EnabledRolesInfo > & roles_info_ )
{
std : : lock_guard lock { mutex } ;
setRolesInfo ( roles_info_ ) ;
} ) ;
setRolesInfo ( enabled_roles - > getRolesInfo ( ) ) ;
}
void ContextAccess : : setRolesInfo ( const std : : shared_ptr < const EnabledRolesInfo > & roles_info_ ) const
{
assert ( roles_info_ ) ;
roles_info = roles_info_ ;
2021-11-02 11:06:20 +00:00
enabled_row_policies = access_control - > getEnabledRowPolicies (
2020-12-01 21:07:20 +00:00
* params . user_id , roles_info - > enabled_roles ) ;
2021-11-02 11:06:20 +00:00
enabled_quota = access_control - > getEnabledQuota (
2020-12-01 21:07:20 +00:00
* params . user_id , user_name , roles_info - > enabled_roles , params . address , params . forwarded_address , params . quota_key ) ;
2021-11-02 11:06:20 +00:00
enabled_settings = access_control - > getEnabledSettings (
2020-12-01 21:07:20 +00:00
* params . user_id , user - > settings , roles_info - > enabled_roles , roles_info - > settings_from_enabled_roles ) ;
2020-07-02 00:09:57 +00:00
calculateAccessRights ( ) ;
2020-03-07 17:37:38 +00:00
}
2020-07-02 00:09:57 +00:00
void ContextAccess : : calculateAccessRights ( ) const
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
access = std : : make_shared < AccessRights > ( mixAccessRightsFromUserAndRoles ( * user , * roles_info ) ) ;
access_with_implicit = std : : make_shared < AccessRights > ( addImplicitAccessRights ( * access ) ) ;
2020-03-07 17:37:38 +00:00
2020-06-20 22:44:52 +00:00
if ( trace_log )
2020-03-07 17:37:38 +00:00
{
if ( roles_info & & ! roles_info - > getCurrentRolesNames ( ) . empty ( ) )
{
2020-05-23 22:24:01 +00:00
LOG_TRACE ( trace_log , " Current_roles: {}, enabled_roles: {} " ,
2020-05-23 17:52:11 +00:00
boost : : algorithm : : join ( roles_info - > getCurrentRolesNames ( ) , " , " ) ,
boost : : algorithm : : join ( roles_info - > getEnabledRolesNames ( ) , " , " ) ) ;
2020-03-07 17:37:38 +00:00
}
2020-06-20 22:44:52 +00:00
LOG_TRACE ( trace_log , " Settings: readonly={}, allow_ddl={}, allow_introspection_functions={} " , params . readonly , params . allow_ddl , params . allow_introspection ) ;
2020-07-02 00:09:57 +00:00
LOG_TRACE ( trace_log , " List of all grants: {} " , access - > toString ( ) ) ;
2020-12-08 14:24:32 +00:00
LOG_TRACE ( trace_log , " List of all grants including implicit: {} " , access_with_implicit - > toString ( ) ) ;
2020-03-07 17:37:38 +00:00
}
}
UserPtr ContextAccess : : getUser ( ) const
{
std : : lock_guard lock { mutex } ;
return user ;
}
String ContextAccess : : getUserName ( ) const
{
std : : lock_guard lock { mutex } ;
return user_name ;
}
std : : shared_ptr < const EnabledRolesInfo > ContextAccess : : getRolesInfo ( ) const
{
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( roles_info )
return roles_info ;
static const auto no_roles = std : : make_shared < EnabledRolesInfo > ( ) ;
return no_roles ;
2020-03-07 17:37:38 +00:00
}
2020-05-07 02:45:27 +00:00
std : : shared_ptr < const EnabledRowPolicies > ContextAccess : : getEnabledRowPolicies ( ) const
2020-03-07 17:37:38 +00:00
{
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( enabled_row_policies )
return enabled_row_policies ;
static const auto no_row_policies = std : : make_shared < EnabledRowPolicies > ( ) ;
return no_row_policies ;
2020-03-07 17:37:38 +00:00
}
2021-11-18 13:04:42 +00:00
ASTPtr ContextAccess : : getRowPolicyFilter ( const String & database , const String & table_name , RowPolicyFilterType filter_type , const ASTPtr & combine_with_expr ) const
2020-03-07 17:37:38 +00:00
{
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( enabled_row_policies )
2021-11-18 13:04:42 +00:00
return enabled_row_policies - > getFilter ( database , table_name , filter_type , combine_with_expr ) ;
2021-07-15 08:55:51 +00:00
return nullptr ;
2020-03-07 17:37:38 +00:00
}
std : : shared_ptr < const EnabledQuota > ContextAccess : : getQuota ( ) const
{
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( enabled_quota )
return enabled_quota ;
static const auto unlimited_quota = EnabledQuota : : getUnlimitedQuota ( ) ;
return unlimited_quota ;
2020-03-07 17:37:38 +00:00
}
2020-05-08 12:50:45 +00:00
std : : optional < QuotaUsage > ContextAccess : : getQuotaUsage ( ) const
2020-04-10 22:23:27 +00:00
{
2020-05-08 12:50:45 +00:00
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( enabled_quota )
return enabled_quota - > getUsage ( ) ;
return { } ;
2020-04-10 22:23:27 +00:00
}
2020-05-08 12:50:45 +00:00
2020-03-07 17:37:38 +00:00
std : : shared_ptr < const ContextAccess > ContextAccess : : getFullAccess ( )
2020-04-10 22:23:27 +00:00
{
2020-03-07 17:37:38 +00:00
static const std : : shared_ptr < const ContextAccess > res = [ ]
{
auto full_access = std : : shared_ptr < ContextAccess > ( new ContextAccess ) ;
2020-12-08 14:24:32 +00:00
full_access - > is_full_access = true ;
2020-06-20 22:44:52 +00:00
full_access - > access = std : : make_shared < AccessRights > ( AccessRights : : getFullAccess ( ) ) ;
2021-07-15 08:55:51 +00:00
full_access - > access_with_implicit = std : : make_shared < AccessRights > ( addImplicitAccessRights ( * full_access - > access ) ) ;
2020-03-07 17:37:38 +00:00
return full_access ;
} ( ) ;
return res ;
2020-04-10 22:23:27 +00:00
}
2021-07-22 16:07:03 +00:00
SettingsChanges ContextAccess : : getDefaultSettings ( ) const
2020-03-07 17:37:38 +00:00
{
2020-03-04 22:27:03 +00:00
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( enabled_settings )
2021-07-22 16:07:03 +00:00
{
if ( auto info = enabled_settings - > getInfo ( ) )
return info - > settings ;
}
return { } ;
2020-03-07 17:37:38 +00:00
}
2021-07-22 16:07:03 +00:00
std : : shared_ptr < const SettingsProfilesInfo > ContextAccess : : getDefaultProfileInfo ( ) const
2020-03-07 17:37:38 +00:00
{
2020-03-04 22:27:03 +00:00
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( enabled_settings )
2021-07-22 16:07:03 +00:00
return enabled_settings - > getInfo ( ) ;
2021-11-02 11:06:20 +00:00
static const auto everything_by_default = std : : make_shared < SettingsProfilesInfo > ( * access_control ) ;
2021-07-22 16:07:03 +00:00
return everything_by_default ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 14:24:32 +00:00
std : : shared_ptr < const AccessRights > ContextAccess : : getAccessRights ( ) const
2020-06-20 22:44:52 +00:00
{
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( access )
return access ;
static const auto nothing_granted = std : : make_shared < AccessRights > ( ) ;
return nothing_granted ;
2020-06-20 22:44:52 +00:00
}
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
std : : shared_ptr < const AccessRights > ContextAccess : : getAccessRightsWithImplicit ( ) const
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
std : : lock_guard lock { mutex } ;
2021-07-15 08:55:51 +00:00
if ( access_with_implicit )
return access_with_implicit ;
static const auto nothing_granted = std : : make_shared < AccessRights > ( ) ;
return nothing_granted ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 14:24:32 +00:00
template < bool throw_if_denied , bool grant_option , typename . . . Args >
2021-02-26 22:37:00 +00:00
bool ContextAccess : : checkAccessImplHelper ( const AccessFlags & flags , const Args & . . . args ) const
2020-06-20 22:44:52 +00:00
{
2020-12-08 14:24:32 +00:00
auto access_granted = [ & ]
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
if ( trace_log )
2021-02-26 22:37:00 +00:00
LOG_TRACE ( trace_log , " Access granted: {}{} " , ( AccessRightsElement { flags , args . . . } . toStringWithoutOptions ( ) ) ,
2020-12-08 14:24:32 +00:00
( grant_option ? " WITH GRANT OPTION " : " " ) ) ;
return true ;
} ;
2020-03-07 17:37:38 +00:00
2020-12-21 00:38:53 +00:00
auto access_denied = [ & ] ( const String & error_msg , int error_code [[maybe_unused]] )
2020-06-20 22:44:52 +00:00
{
2020-12-08 14:24:32 +00:00
if ( trace_log )
2021-02-26 22:37:00 +00:00
LOG_TRACE ( trace_log , " Access denied: {}{} " , ( AccessRightsElement { flags , args . . . } . toStringWithoutOptions ( ) ) ,
2020-12-08 14:24:32 +00:00
( grant_option ? " WITH GRANT OPTION " : " " ) ) ;
if constexpr ( throw_if_denied )
throw Exception ( getUserName ( ) + " : " + error_msg , error_code ) ;
return false ;
2020-06-20 22:44:52 +00:00
} ;
2020-03-22 21:40:32 +00:00
2020-12-08 14:24:32 +00:00
if ( ! flags | | is_full_access )
return access_granted ( ) ;
2020-03-22 21:40:32 +00:00
2020-12-08 14:24:32 +00:00
if ( ! getUser ( ) )
return access_denied ( " User has been dropped " , ErrorCodes : : UNKNOWN_USER ) ;
2020-12-11 19:42:14 +00:00
/// Access to temporary tables is controlled in an unusual way, not like normal tables.
/// Creating of temporary tables is controlled by AccessType::CREATE_TEMPORARY_TABLES grant,
/// and other grants are considered as always given.
/// The DatabaseCatalog class won't resolve StorageID for temporary tables
/// which shouldn't be accessed.
if ( getDatabase ( args . . . ) = = DatabaseCatalog : : TEMPORARY_DATABASE )
2020-12-08 14:24:32 +00:00
return access_granted ( ) ;
auto acs = getAccessRightsWithImplicit ( ) ;
bool granted ;
if constexpr ( grant_option )
granted = acs - > hasGrantOption ( flags , args . . . ) ;
else
granted = acs - > isGranted ( flags , args . . . ) ;
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
if ( ! granted )
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
if ( grant_option & & acs - > isGranted ( flags , args . . . ) )
{
return access_denied (
" Not enough privileges. "
" The required privileges have been granted, but without grant option. "
" To execute this query it's necessary to have grant "
2021-02-26 22:37:00 +00:00
+ AccessRightsElement { flags , args . . . } . toStringWithoutOptions ( ) + " WITH GRANT OPTION " ,
2020-12-08 14:24:32 +00:00
ErrorCodes : : ACCESS_DENIED ) ;
}
return access_denied (
" Not enough privileges. To execute this query it's necessary to have grant "
2021-02-26 22:37:00 +00:00
+ AccessRightsElement { flags , args . . . } . toStringWithoutOptions ( ) + ( grant_option ? " WITH GRANT OPTION " : " " ) ,
2020-06-20 22:44:52 +00:00
ErrorCodes : : ACCESS_DENIED ) ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 14:24:32 +00:00
struct PrecalculatedFlags
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
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 ;
const AccessFlags dictionary_ddl = AccessType : : CREATE_DICTIONARY | AccessType : : DROP_DICTIONARY ;
const AccessFlags table_and_dictionary_ddl = table_ddl | dictionary_ddl ;
const AccessFlags write_table_access = AccessType : : INSERT | AccessType : : OPTIMIZE ;
const AccessFlags write_dcl_access = AccessType : : ACCESS_MANAGEMENT - AccessType : : SHOW_ACCESS ;
const AccessFlags not_readonly_flags = write_table_access | table_and_dictionary_ddl | write_dcl_access | AccessType : : SYSTEM | AccessType : : KILL_QUERY ;
const AccessFlags not_readonly_1_flags = AccessType : : CREATE_TEMPORARY_TABLE ;
const AccessFlags ddl_flags = table_ddl | dictionary_ddl ;
const AccessFlags introspection_flags = AccessType : : INTROSPECTION ;
} ;
static const PrecalculatedFlags precalc ;
2020-06-20 22:44:52 +00:00
2020-12-08 14:24:32 +00:00
if ( params . readonly )
{
if constexpr ( grant_option )
return access_denied ( " Cannot change grants in readonly mode. " , ErrorCodes : : READONLY ) ;
if ( ( flags & precalc . not_readonly_flags ) | |
( ( params . readonly = = 1 ) & & ( flags & precalc . not_readonly_1_flags ) ) )
2020-06-20 22:44:52 +00:00
{
if ( params . interface = = ClientInfo : : Interface : : HTTP & & params . http_method = = ClientInfo : : HTTPMethod : : GET )
2020-12-08 14:24:32 +00:00
{
return access_denied (
2020-06-20 22:44:52 +00:00
" Cannot execute query in readonly mode. "
" For queries over HTTP, method GET implies readonly. You should use method POST for modifying queries " ,
ErrorCodes : : READONLY ) ;
2020-12-08 14:24:32 +00:00
}
2020-06-20 22:44:52 +00:00
else
2020-12-08 14:24:32 +00:00
return access_denied ( " Cannot execute query in readonly mode " , ErrorCodes : : READONLY ) ;
2020-06-20 22:44:52 +00:00
}
2020-03-07 17:37:38 +00:00
}
2020-12-08 18:09:13 +00:00
if ( ! params . allow_ddl & & ! grant_option )
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
if ( flags & precalc . ddl_flags )
return access_denied ( " Cannot execute query. DDL queries are prohibited for the user " , ErrorCodes : : QUERY_IS_PROHIBITED ) ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 18:07:50 +00:00
if ( ! params . allow_introspection & & ! grant_option )
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
if ( flags & precalc . introspection_flags )
return access_denied ( " Introspection functions are disabled, because setting 'allow_introspection_functions' is set to 0 " , ErrorCodes : : FUNCTION_NOT_ALLOWED ) ;
2020-03-07 17:37:38 +00:00
}
2020-12-08 14:24:32 +00:00
return access_granted ( ) ;
2020-03-07 17:37:38 +00:00
}
2021-02-26 22:37:00 +00:00
template < bool throw_if_denied , bool grant_option >
bool ContextAccess : : checkAccessImpl ( const AccessFlags & flags ) const
{
return checkAccessImplHelper < throw_if_denied , grant_option > ( flags ) ;
}
template < bool throw_if_denied , bool grant_option , typename . . . Args >
bool ContextAccess : : checkAccessImpl ( const AccessFlags & flags , const std : : string_view & database , const Args & . . . args ) const
{
return checkAccessImplHelper < throw_if_denied , grant_option > ( flags , database . empty ( ) ? params . current_database : database , args . . . ) ;
}
template < bool throw_if_denied , bool grant_option >
bool ContextAccess : : checkAccessImplHelper ( const AccessRightsElement & element ) const
{
assert ( ! element . grant_option | | grant_option ) ;
if ( element . any_database )
return checkAccessImpl < throw_if_denied , grant_option > ( element . access_flags ) ;
else if ( element . any_table )
return checkAccessImpl < throw_if_denied , grant_option > ( element . access_flags , element . database ) ;
else if ( element . any_column )
return checkAccessImpl < throw_if_denied , grant_option > ( element . access_flags , element . database , element . table ) ;
else
return checkAccessImpl < throw_if_denied , grant_option > ( element . access_flags , element . database , element . table , element . columns ) ;
}
template < bool throw_if_denied , bool grant_option >
bool ContextAccess : : checkAccessImpl ( const AccessRightsElement & element ) const
{
if constexpr ( grant_option )
{
return checkAccessImplHelper < throw_if_denied , true > ( element ) ;
}
else
{
if ( element . grant_option )
return checkAccessImplHelper < throw_if_denied , true > ( element ) ;
else
return checkAccessImplHelper < throw_if_denied , false > ( element ) ;
}
}
template < bool throw_if_denied , bool grant_option >
bool ContextAccess : : checkAccessImpl ( const AccessRightsElements & elements ) const
{
for ( const auto & element : elements )
if ( ! checkAccessImpl < throw_if_denied , grant_option > ( element ) )
return false ;
return true ;
}
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
bool ContextAccess : : isGranted ( const AccessFlags & flags ) const { return checkAccessImpl < false , false > ( flags ) ; }
bool ContextAccess : : isGranted ( const AccessFlags & flags , const std : : string_view & database ) const { return checkAccessImpl < false , false > ( flags , database ) ; }
bool ContextAccess : : isGranted ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table ) const { return checkAccessImpl < false , false > ( flags , database , table ) ; }
bool ContextAccess : : isGranted ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : string_view & column ) const { return checkAccessImpl < false , false > ( flags , database , table , column ) ; }
bool ContextAccess : : isGranted ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : vector < std : : string_view > & columns ) const { return checkAccessImpl < false , false > ( flags , database , table , columns ) ; }
bool ContextAccess : : isGranted ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const Strings & columns ) const { return checkAccessImpl < false , false > ( flags , database , table , columns ) ; }
bool ContextAccess : : isGranted ( const AccessRightsElement & element ) const { return checkAccessImpl < false , false > ( element ) ; }
bool ContextAccess : : isGranted ( const AccessRightsElements & elements ) const { return checkAccessImpl < false , false > ( elements ) ; }
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
bool ContextAccess : : hasGrantOption ( const AccessFlags & flags ) const { return checkAccessImpl < false , true > ( flags ) ; }
bool ContextAccess : : hasGrantOption ( const AccessFlags & flags , const std : : string_view & database ) const { return checkAccessImpl < false , true > ( flags , database ) ; }
bool ContextAccess : : hasGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table ) const { return checkAccessImpl < false , true > ( flags , database , table ) ; }
bool ContextAccess : : hasGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : string_view & column ) const { return checkAccessImpl < false , true > ( flags , database , table , column ) ; }
bool ContextAccess : : hasGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : vector < std : : string_view > & columns ) const { return checkAccessImpl < false , true > ( flags , database , table , columns ) ; }
bool ContextAccess : : hasGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const Strings & columns ) const { return checkAccessImpl < false , true > ( flags , database , table , columns ) ; }
bool ContextAccess : : hasGrantOption ( const AccessRightsElement & element ) const { return checkAccessImpl < false , true > ( element ) ; }
bool ContextAccess : : hasGrantOption ( const AccessRightsElements & elements ) const { return checkAccessImpl < false , true > ( elements ) ; }
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
void ContextAccess : : checkAccess ( const AccessFlags & flags ) const { checkAccessImpl < true , false > ( flags ) ; }
void ContextAccess : : checkAccess ( const AccessFlags & flags , const std : : string_view & database ) const { checkAccessImpl < true , false > ( flags , database ) ; }
void ContextAccess : : checkAccess ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table ) const { checkAccessImpl < true , false > ( flags , database , table ) ; }
void ContextAccess : : checkAccess ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : string_view & column ) const { checkAccessImpl < true , false > ( flags , database , table , column ) ; }
void ContextAccess : : checkAccess ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : vector < std : : string_view > & columns ) const { checkAccessImpl < true , false > ( flags , database , table , columns ) ; }
void ContextAccess : : checkAccess ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const Strings & columns ) const { checkAccessImpl < true , false > ( flags , database , table , columns ) ; }
void ContextAccess : : checkAccess ( const AccessRightsElement & element ) const { checkAccessImpl < true , false > ( element ) ; }
void ContextAccess : : checkAccess ( const AccessRightsElements & elements ) const { checkAccessImpl < true , false > ( elements ) ; }
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
void ContextAccess : : checkGrantOption ( const AccessFlags & flags ) const { checkAccessImpl < true , true > ( flags ) ; }
void ContextAccess : : checkGrantOption ( const AccessFlags & flags , const std : : string_view & database ) const { checkAccessImpl < true , true > ( flags , database ) ; }
void ContextAccess : : checkGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table ) const { checkAccessImpl < true , true > ( flags , database , table ) ; }
void ContextAccess : : checkGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : string_view & column ) const { checkAccessImpl < true , true > ( flags , database , table , column ) ; }
void ContextAccess : : checkGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const std : : vector < std : : string_view > & columns ) const { checkAccessImpl < true , true > ( flags , database , table , columns ) ; }
void ContextAccess : : checkGrantOption ( const AccessFlags & flags , const std : : string_view & database , const std : : string_view & table , const Strings & columns ) const { checkAccessImpl < true , true > ( flags , database , table , columns ) ; }
void ContextAccess : : checkGrantOption ( const AccessRightsElement & element ) const { checkAccessImpl < true , true > ( element ) ; }
void ContextAccess : : checkGrantOption ( const AccessRightsElements & elements ) const { checkAccessImpl < true , true > ( elements ) ; }
2020-10-12 18:29:02 +00:00
2020-12-08 14:24:32 +00:00
template < bool throw_if_denied , typename Container , typename GetNameFunction >
2021-02-26 22:37:00 +00:00
bool ContextAccess : : checkAdminOptionImplHelper ( const Container & role_ids , const GetNameFunction & get_name_function ) const
2020-03-07 17:37:38 +00:00
{
2020-12-08 14:24:32 +00:00
if ( ! std : : size ( role_ids ) | | is_full_access )
return true ;
2020-03-07 17:37:38 +00:00
2020-12-21 00:41:22 +00:00
auto show_error = [ this ] ( const String & msg , int error_code [[maybe_unused]] )
2020-12-08 14:24:32 +00:00
{
UNUSED ( this ) ;
if constexpr ( throw_if_denied )
throw Exception ( getUserName ( ) + " : " + msg , error_code ) ;
} ;
2020-05-08 12:50:45 +00:00
2020-12-08 14:24:32 +00:00
if ( ! getUser ( ) )
{
show_error ( " User has been dropped " , ErrorCodes : : UNKNOWN_USER ) ;
return false ;
}
2020-03-07 17:37:38 +00:00
2020-12-08 14:24:32 +00:00
if ( isGranted ( AccessType : : ROLE_ADMIN ) )
return true ;
2020-03-04 22:27:03 +00:00
2020-12-08 14:24:32 +00:00
auto info = getRolesInfo ( ) ;
size_t i = 0 ;
for ( auto it = std : : begin ( role_ids ) ; it ! = std : : end ( role_ids ) ; + + it , + + i )
{
const UUID & role_id = * it ;
2021-07-15 08:55:51 +00:00
if ( info - > enabled_roles_with_admin_option . count ( role_id ) )
2020-12-08 14:24:32 +00:00
continue ;
2020-03-04 22:27:03 +00:00
2020-12-08 14:24:32 +00:00
if ( throw_if_denied )
{
auto role_name = get_name_function ( role_id , i ) ;
if ( ! role_name )
role_name = " ID { " + toString ( role_id ) + " } " ;
2021-07-15 08:55:51 +00:00
if ( info - > enabled_roles . count ( role_id ) )
2020-12-08 14:24:32 +00:00
show_error ( " Not enough privileges. "
" Role " + backQuote ( * role_name ) + " is granted, but without ADMIN option. "
" To execute this query it's necessary to have the role " + backQuoteIfNeed ( * role_name ) + " granted with ADMIN option. " ,
ErrorCodes : : ACCESS_DENIED ) ;
else
show_error ( " Not enough privileges. "
" To execute this query it's necessary to have the role " + backQuoteIfNeed ( * role_name ) + " granted with ADMIN option. " ,
ErrorCodes : : ACCESS_DENIED ) ;
}
return false ;
}
return true ;
2020-03-04 22:27:03 +00:00
}
2021-02-26 22:37:00 +00:00
template < bool throw_if_denied >
bool ContextAccess : : checkAdminOptionImpl ( const UUID & role_id ) const
{
2021-11-02 11:06:20 +00:00
return checkAdminOptionImplHelper < throw_if_denied > ( to_array ( role_id ) , [ this ] ( const UUID & id , size_t ) { return access_control - > tryReadName ( id ) ; } ) ;
2021-02-26 22:37:00 +00:00
}
template < bool throw_if_denied >
bool ContextAccess : : checkAdminOptionImpl ( const UUID & role_id , const String & role_name ) const
{
return checkAdminOptionImplHelper < throw_if_denied > ( to_array ( role_id ) , [ & role_name ] ( const UUID & , size_t ) { return std : : optional < String > { role_name } ; } ) ;
}
template < bool throw_if_denied >
bool ContextAccess : : checkAdminOptionImpl ( const UUID & role_id , const std : : unordered_map < UUID , String > & names_of_roles ) const
{
return checkAdminOptionImplHelper < throw_if_denied > ( to_array ( role_id ) , [ & names_of_roles ] ( const UUID & id , size_t ) { auto it = names_of_roles . find ( id ) ; return ( it ! = names_of_roles . end ( ) ) ? it - > second : std : : optional < String > { } ; } ) ;
}
template < bool throw_if_denied >
bool ContextAccess : : checkAdminOptionImpl ( const std : : vector < UUID > & role_ids ) const
{
2021-11-02 11:06:20 +00:00
return checkAdminOptionImplHelper < throw_if_denied > ( role_ids , [ this ] ( const UUID & id , size_t ) { return access_control - > tryReadName ( id ) ; } ) ;
2021-02-26 22:37:00 +00:00
}
template < bool throw_if_denied >
bool ContextAccess : : checkAdminOptionImpl ( const std : : vector < UUID > & role_ids , const Strings & names_of_roles ) const
{
return checkAdminOptionImplHelper < throw_if_denied > ( role_ids , [ & names_of_roles ] ( const UUID & , size_t i ) { return std : : optional < String > { names_of_roles [ i ] } ; } ) ;
}
template < bool throw_if_denied >
bool ContextAccess : : checkAdminOptionImpl ( const std : : vector < UUID > & role_ids , const std : : unordered_map < UUID , String > & names_of_roles ) const
{
return checkAdminOptionImplHelper < throw_if_denied > ( role_ids , [ & names_of_roles ] ( const UUID & id , size_t ) { auto it = names_of_roles . find ( id ) ; return ( it ! = names_of_roles . end ( ) ) ? it - > second : std : : optional < String > { } ; } ) ;
}
2020-12-08 14:24:32 +00:00
bool ContextAccess : : hasAdminOption ( const UUID & role_id ) const { return checkAdminOptionImpl < false > ( role_id ) ; }
bool ContextAccess : : hasAdminOption ( const UUID & role_id , const String & role_name ) const { return checkAdminOptionImpl < false > ( role_id , role_name ) ; }
bool ContextAccess : : hasAdminOption ( const UUID & role_id , const std : : unordered_map < UUID , String > & names_of_roles ) const { return checkAdminOptionImpl < false > ( role_id , names_of_roles ) ; }
bool ContextAccess : : hasAdminOption ( const std : : vector < UUID > & role_ids ) const { return checkAdminOptionImpl < false > ( role_ids ) ; }
bool ContextAccess : : hasAdminOption ( const std : : vector < UUID > & role_ids , const Strings & names_of_roles ) const { return checkAdminOptionImpl < false > ( role_ids , names_of_roles ) ; }
bool ContextAccess : : hasAdminOption ( const std : : vector < UUID > & role_ids , const std : : unordered_map < UUID , String > & names_of_roles ) const { return checkAdminOptionImpl < false > ( role_ids , names_of_roles ) ; }
void ContextAccess : : checkAdminOption ( const UUID & role_id ) const { checkAdminOptionImpl < true > ( role_id ) ; }
void ContextAccess : : checkAdminOption ( const UUID & role_id , const String & role_name ) const { checkAdminOptionImpl < true > ( role_id , role_name ) ; }
void ContextAccess : : checkAdminOption ( const UUID & role_id , const std : : unordered_map < UUID , String > & names_of_roles ) const { checkAdminOptionImpl < true > ( role_id , names_of_roles ) ; }
void ContextAccess : : checkAdminOption ( const std : : vector < UUID > & role_ids ) const { checkAdminOptionImpl < true > ( role_ids ) ; }
void ContextAccess : : checkAdminOption ( const std : : vector < UUID > & role_ids , const Strings & names_of_roles ) const { checkAdminOptionImpl < true > ( role_ids , names_of_roles ) ; }
void ContextAccess : : checkAdminOption ( const std : : vector < UUID > & role_ids , const std : : unordered_map < UUID , String > & names_of_roles ) const { checkAdminOptionImpl < true > ( role_ids , names_of_roles ) ; }
2020-03-07 17:37:38 +00:00
}