2020-07-23 17:55:24 +00:00
# include <Access/LDAPAccessStorage.h>
2020-08-20 07:39:27 +00:00
# include <Access/AccessControlManager.h>
2020-07-23 17:55:24 +00:00
# include <Access/User.h>
2020-08-20 07:39:27 +00:00
# include <Access/Role.h>
2020-11-19 22:02:18 +00:00
# include <Access/LDAPClient.h>
2020-08-15 12:17:07 +00:00
# include <Common/Exception.h>
2020-07-23 17:55:24 +00:00
# include <common/logger_useful.h>
# include <ext/scope_guard.h>
# include <Poco/Util/AbstractConfiguration.h>
2020-09-20 22:51:38 +00:00
# include <Poco/JSON/JSON.h>
# include <Poco/JSON/Object.h>
# include <Poco/JSON/Stringifier.h>
2020-11-19 22:02:18 +00:00
# include <boost/container_hash/hash.hpp>
2020-10-08 20:57:23 +00:00
# include <boost/range/algorithm/copy.hpp>
# include <iterator>
2020-09-20 22:51:38 +00:00
# include <sstream>
2020-11-21 20:44:54 +00:00
# include <unordered_map>
2020-07-23 17:55:24 +00:00
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS ;
}
2020-09-20 22:51:38 +00:00
LDAPAccessStorage : : LDAPAccessStorage ( const String & storage_name_ , AccessControlManager * access_control_manager_ , const Poco : : Util : : AbstractConfiguration & config , const String & prefix )
2020-08-18 10:54:02 +00:00
: IAccessStorage ( storage_name_ )
2020-07-23 17:55:24 +00:00
{
2020-09-20 22:51:38 +00:00
setConfiguration ( access_control_manager_ , config , prefix ) ;
2020-07-23 17:55:24 +00:00
}
2020-10-22 16:47:52 +00:00
String LDAPAccessStorage : : getLDAPServerName ( ) const
{
return ldap_server ;
}
2020-08-20 07:39:27 +00:00
void LDAPAccessStorage : : setConfiguration ( AccessControlManager * access_control_manager_ , const Poco : : Util : : AbstractConfiguration & config , const String & prefix )
2020-07-23 17:55:24 +00:00
{
2020-10-03 13:31:02 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-08-20 07:39:27 +00:00
// TODO: switch to passing config as a ConfigurationView and remove this extra prefix once a version of Poco with proper implementation is available.
2020-08-18 10:54:02 +00:00
const String prefix_str = ( prefix . empty ( ) ? " " : prefix + " . " ) ;
const bool has_server = config . has ( prefix_str + " server " ) ;
2020-08-20 07:39:27 +00:00
const bool has_roles = config . has ( prefix_str + " roles " ) ;
2020-11-19 22:02:18 +00:00
const bool has_role_mapping = config . has ( prefix_str + " role_mapping " ) ;
2020-07-23 17:55:24 +00:00
if ( ! has_server )
2020-11-20 16:59:56 +00:00
throw Exception ( " Missing 'server' field for LDAP user directory " , ErrorCodes : : BAD_ARGUMENTS ) ;
2020-07-23 17:55:24 +00:00
2020-08-18 10:54:02 +00:00
const auto ldap_server_cfg = config . getString ( prefix_str + " server " ) ;
2020-07-24 09:52:03 +00:00
if ( ldap_server_cfg . empty ( ) )
2020-11-20 16:59:56 +00:00
throw Exception ( " Empty 'server' field for LDAP user directory " , ErrorCodes : : BAD_ARGUMENTS ) ;
2020-07-23 17:55:24 +00:00
2020-11-19 22:02:18 +00:00
std : : set < String > common_roles_cfg ;
2020-08-20 07:39:27 +00:00
if ( has_roles )
{
Poco : : Util : : AbstractConfiguration : : Keys role_names ;
config . keys ( prefix_str + " roles " , role_names ) ;
2020-08-15 12:17:07 +00:00
2020-08-20 07:39:27 +00:00
// Currently, we only extract names of roles from the section names and assign them directly and unconditionally.
2020-11-19 22:02:18 +00:00
common_roles_cfg . insert ( role_names . begin ( ) , role_names . end ( ) ) ;
}
LDAPSearchParamsList role_search_params_cfg ;
if ( has_role_mapping )
{
Poco : : Util : : AbstractConfiguration : : Keys all_keys ;
config . keys ( prefix , all_keys ) ;
for ( const auto & key : all_keys )
{
if ( key ! = " role_mapping " & & key . find ( " role_mapping[ " ) ! = 0 )
continue ;
const String rm_prefix = prefix_str + key ;
const String rm_prefix_str = rm_prefix + ' . ' ;
role_search_params_cfg . emplace_back ( ) ;
auto & rm_params = role_search_params_cfg . back ( ) ;
rm_params . base_dn = config . getString ( rm_prefix_str + " base_dn " , " " ) ;
2020-11-20 19:31:21 +00:00
rm_params . search_filter = config . getString ( rm_prefix_str + " search_filter " , " " ) ;
2020-11-19 22:02:18 +00:00
rm_params . attribute = config . getString ( rm_prefix_str + " attribute " , " cn " ) ;
2020-12-17 14:27:30 +00:00
rm_params . prefix = config . getString ( rm_prefix_str + " prefix " , " " ) ;
2020-11-19 22:02:18 +00:00
auto scope = config . getString ( rm_prefix_str + " scope " , " subtree " ) ;
boost : : algorithm : : to_lower ( scope ) ;
if ( scope = = " base " ) rm_params . scope = LDAPSearchParams : : Scope : : BASE ;
else if ( scope = = " one_level " ) rm_params . scope = LDAPSearchParams : : Scope : : ONE_LEVEL ;
else if ( scope = = " subtree " ) rm_params . scope = LDAPSearchParams : : Scope : : SUBTREE ;
else if ( scope = = " children " ) rm_params . scope = LDAPSearchParams : : Scope : : CHILDREN ;
else
2020-11-20 16:59:56 +00:00
throw Exception ( " Invalid value of 'scope' field in ' " + key + " ' section of LDAP user directory, must be one of 'base', 'one_level', 'subtree', or 'children' " , ErrorCodes : : BAD_ARGUMENTS ) ;
2020-11-19 22:02:18 +00:00
}
2020-08-20 07:39:27 +00:00
}
2020-07-23 17:55:24 +00:00
2020-08-20 07:39:27 +00:00
access_control_manager = access_control_manager_ ;
2020-08-28 08:06:06 +00:00
ldap_server = ldap_server_cfg ;
2020-11-19 22:02:18 +00:00
role_search_params . swap ( role_search_params_cfg ) ;
common_role_names . swap ( common_roles_cfg ) ;
2020-12-27 20:54:24 +00:00
external_role_hashes . clear ( ) ;
2020-11-19 22:02:18 +00:00
users_per_roles . clear ( ) ;
2020-12-27 20:54:24 +00:00
roles_per_users . clear ( ) ;
2020-11-19 22:02:18 +00:00
granted_role_names . clear ( ) ;
granted_role_ids . clear ( ) ;
2020-08-26 20:34:33 +00:00
role_change_subscription = access_control_manager - > subscribeForChanges < Role > (
[ this ] ( const UUID & id , const AccessEntityPtr & entity )
{
return this - > processRoleChange ( id , entity ) ;
}
) ;
2020-07-23 17:55:24 +00:00
}
2020-08-26 20:34:33 +00:00
void LDAPAccessStorage : : processRoleChange ( const UUID & id , const AccessEntityPtr & entity )
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-12-27 20:54:24 +00:00
const auto role = typeid_cast < std : : shared_ptr < const Role > > ( entity ) ;
2020-11-19 22:02:18 +00:00
const auto it = granted_role_names . find ( id ) ;
2020-10-08 20:57:23 +00:00
2020-12-27 20:54:24 +00:00
if ( role ) // Added or renamed a role.
2020-08-26 20:34:33 +00:00
{
2020-11-19 22:02:18 +00:00
const auto & new_role_name = role - > getName ( ) ;
2020-12-27 20:54:24 +00:00
if ( it ! = granted_role_names . end ( ) ) // Renamed a granted role.
2020-11-19 22:02:18 +00:00
{
const auto & old_role_name = it - > second ;
if ( new_role_name ! = old_role_name )
{
2020-12-27 20:54:24 +00:00
// Revoke the old role first, then grant the new role.
2020-11-19 22:02:18 +00:00
applyRoleChangeNoLock ( false /* revoke */ , id , old_role_name ) ;
2020-12-27 20:54:24 +00:00
applyRoleChangeNoLock ( true /* grant */ , id , new_role_name ) ;
2020-11-19 22:02:18 +00:00
}
}
2020-12-27 20:54:24 +00:00
else // Added a role.
{
applyRoleChangeNoLock ( true /* grant */ , id , new_role_name ) ;
}
2020-08-26 20:34:33 +00:00
}
2020-12-27 20:54:24 +00:00
else // Removed a role.
2020-11-19 22:02:18 +00:00
{
2020-12-27 20:54:24 +00:00
if ( it ! = granted_role_names . end ( ) ) // Removed a granted role.
2020-11-19 22:02:18 +00:00
{
const auto & old_role_name = it - > second ;
applyRoleChangeNoLock ( false /* revoke */ , id , old_role_name ) ;
}
}
}
void LDAPAccessStorage : : applyRoleChangeNoLock ( bool grant , const UUID & role_id , const String & role_name )
{
std : : vector < UUID > user_ids ;
2020-12-27 20:54:24 +00:00
// Build a list of ids of the relevant users.
2020-11-19 22:02:18 +00:00
if ( common_role_names . count ( role_name ) )
2020-08-26 20:34:33 +00:00
{
2020-11-19 22:02:18 +00:00
user_ids = memory_storage . findAll < User > ( ) ;
}
2020-11-19 22:26:52 +00:00
else
{
2020-11-19 22:02:18 +00:00
const auto it = users_per_roles . find ( role_name ) ;
if ( it ! = users_per_roles . end ( ) )
{
const auto & user_names = it - > second ;
user_ids . reserve ( user_names . size ( ) ) ;
2020-12-27 20:54:24 +00:00
2020-11-19 22:02:18 +00:00
for ( const auto & user_name : user_names )
{
if ( const auto user_id = memory_storage . find < User > ( user_name ) )
user_ids . emplace_back ( * user_id ) ;
}
}
2020-10-08 20:57:23 +00:00
}
2020-12-27 20:54:24 +00:00
// Update the granted roles of the relevant users.
2020-11-19 22:02:18 +00:00
if ( ! user_ids . empty ( ) )
2020-10-08 20:57:23 +00:00
{
2020-11-19 22:02:18 +00:00
auto update_func = [ & role_id , & grant ] ( const AccessEntityPtr & entity_ ) - > AccessEntityPtr
2020-08-26 20:34:33 +00:00
{
2020-10-08 20:57:23 +00:00
if ( auto user = typeid_cast < std : : shared_ptr < const User > > ( entity_ ) )
2020-08-26 20:34:33 +00:00
{
2020-10-08 20:57:23 +00:00
auto changed_user = typeid_cast < std : : shared_ptr < User > > ( user - > clone ( ) ) ;
auto & granted_roles = changed_user - > granted_roles . roles ;
2020-11-19 22:02:18 +00:00
if ( grant )
granted_roles . insert ( role_id ) ;
else
granted_roles . erase ( role_id ) ;
2020-10-08 20:57:23 +00:00
return changed_user ;
}
return entity_ ;
} ;
2020-11-19 22:02:18 +00:00
memory_storage . update ( user_ids , update_func ) ;
2020-12-27 20:54:24 +00:00
}
2020-11-19 22:02:18 +00:00
2020-12-27 20:54:24 +00:00
// Actualize granted_role_* mappings.
if ( grant )
{
if ( ! user_ids . empty ( ) )
2020-11-19 22:02:18 +00:00
{
granted_role_names . insert_or_assign ( role_id , role_name ) ;
granted_role_ids . insert_or_assign ( role_name , role_id ) ;
}
2020-12-27 20:54:24 +00:00
}
else
{
granted_role_names . erase ( role_id ) ;
granted_role_ids . erase ( role_name ) ;
2020-10-08 20:57:23 +00:00
}
}
2020-12-27 20:54:24 +00:00
void LDAPAccessStorage : : assignRolesNoLock ( User & user , const LDAPSearchResultsList & external_roles ) const
2020-10-08 20:57:23 +00:00
{
2020-12-27 20:54:24 +00:00
const auto external_roles_hash = boost : : hash < LDAPSearchResultsList > { } ( external_roles ) ;
return assignRolesNoLock ( user , external_roles , external_roles_hash ) ;
}
2020-11-19 22:02:18 +00:00
2020-12-27 20:54:24 +00:00
void LDAPAccessStorage : : assignRolesNoLock ( User & user , const LDAPSearchResultsList & external_roles , const std : : size_t external_roles_hash ) const
{
const auto & user_name = user . getName ( ) ;
auto & granted_roles = user . granted_roles . roles ;
const auto local_role_names = mapExternalRolesNoLock ( external_roles ) ;
2020-11-19 22:02:18 +00:00
2020-12-27 20:54:24 +00:00
auto grant_role = [ this , & user_name , & granted_roles ] ( const String & role_name , const bool common )
2020-10-08 20:57:23 +00:00
{
2020-12-27 20:54:24 +00:00
auto it = granted_role_ids . find ( role_name ) ;
2020-11-19 22:02:18 +00:00
if ( it = = granted_role_ids . end ( ) )
{
2020-12-27 20:54:24 +00:00
if ( const auto role_id = access_control_manager - > find < Role > ( role_name ) )
{
granted_role_names . insert_or_assign ( * role_id , role_name ) ;
it = granted_role_ids . insert_or_assign ( role_name , * role_id ) . first ;
}
2020-11-19 22:02:18 +00:00
}
2020-12-27 20:54:24 +00:00
if ( it ! = granted_role_ids . end ( ) )
2020-11-19 22:02:18 +00:00
{
const auto & role_id = it - > second ;
granted_roles . insert ( role_id ) ;
}
else
{
2020-12-27 20:54:24 +00:00
LOG_WARNING ( getLogger ( ) , " Unable to grant {} role '{}' to user '{}': role not found " , ( common ? " common " : " mapped " ) , role_name , user_name ) ;
2020-11-19 22:02:18 +00:00
}
2020-12-27 20:54:24 +00:00
} ;
external_role_hashes . erase ( user_name ) ;
granted_roles . clear ( ) ;
const auto old_role_names = std : : move ( roles_per_users [ user_name ] ) ;
// Grant the common roles first.
for ( const auto & role_name : common_role_names )
{
grant_role ( role_name , true /* common */ ) ;
2020-11-19 22:02:18 +00:00
}
2020-12-27 20:54:24 +00:00
// Grant the mapped external roles and actualize users_per_roles mapping.
// local_role_names allowed to overlap with common_role_names.
for ( const auto & role_name : local_role_names )
2020-11-19 22:02:18 +00:00
{
2020-12-27 20:54:24 +00:00
grant_role ( role_name , false /* mapped */ ) ;
2020-11-19 22:02:18 +00:00
users_per_roles [ role_name ] . insert ( user_name ) ;
}
2020-12-27 20:54:24 +00:00
// Cleanup users_per_roles and granted_role_* mappings.
for ( const auto & old_role_name : old_role_names )
{
if ( local_role_names . count ( old_role_name ) )
continue ;
const auto rit = users_per_roles . find ( old_role_name ) ;
if ( rit = = users_per_roles . end ( ) )
continue ;
auto & user_names = rit - > second ;
user_names . erase ( user_name ) ;
if ( ! user_names . empty ( ) )
continue ;
users_per_roles . erase ( rit ) ;
if ( common_role_names . count ( old_role_name ) )
continue ;
const auto iit = granted_role_ids . find ( old_role_name ) ;
if ( iit = = granted_role_ids . end ( ) )
continue ;
const auto old_role_id = iit - > second ;
granted_role_names . erase ( old_role_id ) ;
granted_role_ids . erase ( iit ) ;
}
// Actualize roles_per_users mapping and external_role_hashes cache.
if ( local_role_names . empty ( ) )
roles_per_users . erase ( user_name ) ;
else
roles_per_users [ user_name ] = std : : move ( local_role_names ) ;
external_role_hashes [ user_name ] = external_roles_hash ;
2020-11-19 22:02:18 +00:00
}
2020-12-27 20:54:24 +00:00
void LDAPAccessStorage : : updateAssignedRolesNoLock ( const UUID & id , const String & user_name , const LDAPSearchResultsList & external_roles ) const
2020-11-19 22:02:18 +00:00
{
2020-12-27 20:54:24 +00:00
// No need to include common_role_names in this hash each time, since they don't change.
const auto external_roles_hash = boost : : hash < LDAPSearchResultsList > { } ( external_roles ) ;
2020-11-19 22:02:18 +00:00
2020-12-27 20:54:24 +00:00
// Map and grant the roles from scratch only if the list of external role has changed.
2020-11-19 22:02:18 +00:00
const auto it = external_role_hashes . find ( user_name ) ;
2020-12-27 20:54:24 +00:00
if ( it ! = external_role_hashes . end ( ) & & it - > second = = external_roles_hash )
2020-11-19 22:02:18 +00:00
return ;
2020-12-27 20:54:24 +00:00
auto update_func = [ this , & external_roles , external_roles_hash ] ( const AccessEntityPtr & entity_ ) - > AccessEntityPtr
2020-11-19 22:02:18 +00:00
{
if ( auto user = typeid_cast < std : : shared_ptr < const User > > ( entity_ ) )
{
auto changed_user = typeid_cast < std : : shared_ptr < User > > ( user - > clone ( ) ) ;
2020-12-27 20:54:24 +00:00
assignRolesNoLock ( * changed_user , external_roles , external_roles_hash ) ;
2020-11-19 22:02:18 +00:00
return changed_user ;
}
return entity_ ;
} ;
memory_storage . update ( id , update_func ) ;
}
2020-12-17 14:27:30 +00:00
std : : set < String > LDAPAccessStorage : : mapExternalRolesNoLock ( const LDAPSearchResultsList & external_roles ) const
2020-11-19 22:02:18 +00:00
{
std : : set < String > role_names ;
if ( external_roles . size ( ) ! = role_search_params . size ( ) )
2020-12-17 14:27:30 +00:00
throw Exception ( " Unable to map external roles " , ErrorCodes : : BAD_ARGUMENTS ) ;
2020-11-19 22:02:18 +00:00
for ( std : : size_t i = 0 ; i < external_roles . size ( ) ; + + i )
{
const auto & external_role_set = external_roles [ i ] ;
2020-12-17 14:27:30 +00:00
const auto & prefix = role_search_params [ i ] . prefix ;
2020-11-19 22:02:18 +00:00
for ( const auto & external_role : external_role_set )
{
2020-12-17 14:27:30 +00:00
if (
prefix . size ( ) < external_role . size ( ) & &
external_role . compare ( 0 , prefix . size ( ) , prefix ) = = 0
)
2020-11-19 22:02:18 +00:00
{
2020-12-17 14:48:12 +00:00
role_names . emplace ( external_role , prefix . size ( ) ) ;
2020-11-19 22:02:18 +00:00
}
}
}
return role_names ;
}
bool LDAPAccessStorage : : isPasswordCorrectLDAPNoLock ( const User & user , const String & password , const ExternalAuthenticators & external_authenticators , LDAPSearchResultsList & search_results ) const
{
return user . authentication . isCorrectPasswordLDAP ( password , user . getName ( ) , external_authenticators , & role_search_params , & search_results ) ;
2020-08-26 20:34:33 +00:00
}
2020-08-18 10:54:02 +00:00
const char * LDAPAccessStorage : : getStorageType ( ) const
{
return STORAGE_TYPE ;
}
2020-09-20 22:51:38 +00:00
String LDAPAccessStorage : : getStorageParamsJSON ( ) const
2020-08-18 10:54:02 +00:00
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-09-20 22:51:38 +00:00
Poco : : JSON : : Object params_json ;
2020-08-18 10:54:02 +00:00
2020-09-20 22:51:38 +00:00
params_json . set ( " server " , ldap_server ) ;
2020-11-21 15:08:02 +00:00
Poco : : JSON : : Array common_role_names_json ;
for ( const auto & role : common_role_names )
{
common_role_names_json . add ( role ) ;
}
params_json . set ( " roles " , common_role_names_json ) ;
Poco : : JSON : : Array role_mappings_json ;
for ( const auto & role_mapping : role_search_params )
{
Poco : : JSON : : Object role_mapping_json ;
role_mapping_json . set ( " base_dn " , role_mapping . base_dn ) ;
role_mapping_json . set ( " search_filter " , role_mapping . search_filter ) ;
role_mapping_json . set ( " attribute " , role_mapping . attribute ) ;
2020-12-17 14:27:30 +00:00
role_mapping_json . set ( " prefix " , role_mapping . prefix ) ;
2020-11-21 15:08:02 +00:00
String scope ;
switch ( role_mapping . scope )
{
case LDAPSearchParams : : Scope : : BASE : scope = " base " ; break ;
case LDAPSearchParams : : Scope : : ONE_LEVEL : scope = " one_level " ; break ;
case LDAPSearchParams : : Scope : : SUBTREE : scope = " subtree " ; break ;
case LDAPSearchParams : : Scope : : CHILDREN : scope = " children " ; break ;
}
role_mapping_json . set ( " scope " , scope ) ;
role_mappings_json . add ( role_mapping_json ) ;
}
params_json . set ( " role_mappings " , role_mappings_json ) ;
2020-08-18 10:54:02 +00:00
2020-11-09 19:07:38 +00:00
std : : ostringstream oss ; // STYLE_CHECK_ALLOW_STD_STRING_STREAM
2020-11-07 00:14:53 +00:00
oss . exceptions ( std : : ios : : failbit ) ;
2020-09-20 22:51:38 +00:00
Poco : : JSON : : Stringifier : : stringify ( params_json , oss ) ;
return oss . str ( ) ;
2020-08-26 18:09:26 +00:00
}
2020-09-20 22:51:38 +00:00
std : : optional < UUID > LDAPAccessStorage : : findImpl ( EntityType type , const String & name ) const
2020-07-23 17:55:24 +00:00
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . find ( type , name ) ;
}
std : : vector < UUID > LDAPAccessStorage : : findAllImpl ( EntityType type ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . findAll ( type ) ;
}
bool LDAPAccessStorage : : existsImpl ( const UUID & id ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . exists ( id ) ;
}
AccessEntityPtr LDAPAccessStorage : : readImpl ( const UUID & id ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . read ( id ) ;
}
String LDAPAccessStorage : : readNameImpl ( const UUID & id ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . readName ( id ) ;
}
bool LDAPAccessStorage : : canInsertImpl ( const AccessEntityPtr & ) const
{
return false ;
}
UUID LDAPAccessStorage : : insertImpl ( const AccessEntityPtr & entity , bool )
{
throwReadonlyCannotInsert ( entity - > getType ( ) , entity - > getName ( ) ) ;
}
void LDAPAccessStorage : : removeImpl ( const UUID & id )
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
auto entity = read ( id ) ;
throwReadonlyCannotRemove ( entity - > getType ( ) , entity - > getName ( ) ) ;
}
void LDAPAccessStorage : : updateImpl ( const UUID & id , const UpdateFunc & )
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
auto entity = read ( id ) ;
throwReadonlyCannotUpdate ( entity - > getType ( ) , entity - > getName ( ) ) ;
}
ext : : scope_guard LDAPAccessStorage : : subscribeForChangesImpl ( const UUID & id , const OnChangedHandler & handler ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . subscribeForChanges ( id , handler ) ;
}
ext : : scope_guard LDAPAccessStorage : : subscribeForChangesImpl ( EntityType type , const OnChangedHandler & handler ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . subscribeForChanges ( type , handler ) ;
}
bool LDAPAccessStorage : : hasSubscriptionImpl ( const UUID & id ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . hasSubscription ( id ) ;
}
bool LDAPAccessStorage : : hasSubscriptionImpl ( EntityType type ) const
{
2020-10-02 20:32:13 +00:00
std : : scoped_lock lock ( mutex ) ;
2020-07-23 17:55:24 +00:00
return memory_storage . hasSubscription ( type ) ;
}
2020-09-20 22:51:38 +00:00
UUID LDAPAccessStorage : : loginImpl ( const String & user_name , const String & password , const Poco : : Net : : IPAddress & address , const ExternalAuthenticators & external_authenticators ) const
{
std : : scoped_lock lock ( mutex ) ;
2020-11-19 22:02:18 +00:00
LDAPSearchResultsList external_roles ;
2020-10-04 19:55:58 +00:00
auto id = memory_storage . find < User > ( user_name ) ;
if ( id )
2020-09-20 22:51:38 +00:00
{
2020-10-04 19:55:58 +00:00
auto user = memory_storage . read < User > ( * id ) ;
2020-09-20 22:51:38 +00:00
2020-11-19 22:02:18 +00:00
if ( ! isPasswordCorrectLDAPNoLock ( * user , password , external_authenticators , external_roles ) )
2020-10-04 19:55:58 +00:00
throwInvalidPassword ( ) ;
if ( ! isAddressAllowedImpl ( * user , address ) )
throwAddressNotAllowed ( address ) ;
2020-11-19 22:02:18 +00:00
// Just in case external_roles are changed. This will be no-op if they are not.
2020-12-27 20:54:24 +00:00
updateAssignedRolesNoLock ( * id , user_name , external_roles ) ;
2020-11-19 22:02:18 +00:00
2020-10-04 19:55:58 +00:00
return * id ;
2020-09-20 22:51:38 +00:00
}
2020-10-04 19:55:58 +00:00
else
2020-09-20 22:51:38 +00:00
{
2020-10-04 19:55:58 +00:00
// User does not exist, so we create one, and will add it if authentication is successful.
auto user = std : : make_shared < User > ( ) ;
user - > setName ( user_name ) ;
user - > authentication = Authentication ( Authentication : : Type : : LDAP_SERVER ) ;
user - > authentication . setServerName ( ldap_server ) ;
2020-11-19 22:02:18 +00:00
if ( ! isPasswordCorrectLDAPNoLock ( * user , password , external_authenticators , external_roles ) )
2020-10-04 19:55:58 +00:00
throwInvalidPassword ( ) ;
if ( ! isAddressAllowedImpl ( * user , address ) )
throwAddressNotAllowed ( address ) ;
2020-12-27 20:54:24 +00:00
assignRolesNoLock ( * user , external_roles ) ;
2020-10-04 19:55:58 +00:00
return memory_storage . insert ( user ) ;
2020-09-20 22:51:38 +00:00
}
2020-10-04 19:55:58 +00:00
}
2020-10-06 15:54:22 +00:00
UUID LDAPAccessStorage : : getIDOfLoggedUserImpl ( const String & user_name ) const
{
std : : scoped_lock lock ( mutex ) ;
auto id = memory_storage . find < User > ( user_name ) ;
if ( id )
{
return * id ;
}
else
{
// User does not exist, so we create one, and add it pretending that the authentication is successful.
auto user = std : : make_shared < User > ( ) ;
user - > setName ( user_name ) ;
user - > authentication = Authentication ( Authentication : : Type : : LDAP_SERVER ) ;
user - > authentication . setServerName ( ldap_server ) ;
2020-11-19 22:02:18 +00:00
LDAPSearchResultsList external_roles ;
2020-10-06 15:54:22 +00:00
2020-12-27 20:54:24 +00:00
// TODO: mapped external roles are not available here. Without a password we can't authenticate and retrieve roles from LDAP server.
assignRolesNoLock ( * user , external_roles ) ;
2020-10-06 15:54:22 +00:00
return memory_storage . insert ( user ) ;
}
}
2020-07-23 17:55:24 +00:00
}