| 399 | } |
| 400 | |
| 401 | UserPtr parseUser( |
| 402 | const Poco::Util::AbstractConfiguration & config, |
| 403 | String user_name, |
| 404 | const std::unordered_set<UUID> & allowed_profile_ids, |
| 405 | const std::unordered_set<UUID> & role_ids_from_users_config, |
| 406 | const AccessControl & access_control, |
| 407 | bool allow_no_password, |
| 408 | bool allow_plaintext_password, |
| 409 | LoggerPtr log) |
| 410 | { |
| 411 | auto user = std::make_shared<User>(); |
| 412 | String user_config = "users." + user_name; |
| 413 | |
| 414 | /// If the user name contains a dot, it is escaped with a backslash when parsed from the config file. |
| 415 | /// We need to remove the backslash to get the correct user name. |
| 416 | Poco::replaceInPlace(user_name, "\\.", "."); |
| 417 | user->setName(user_name); |
| 418 | |
| 419 | const auto auth_methods_config = user_config + ".auth_methods"; |
| 420 | bool has_auth_methods = config.has(auth_methods_config); |
| 421 | |
| 422 | std::optional<OneTimePasswordSecret> otp_secret; |
| 423 | if (config.has(user_config + ".time_based_one_time_password")) |
| 424 | { |
| 425 | String otp_secret_key = config.getString(user_config + ".time_based_one_time_password.secret"); |
| 426 | |
| 427 | std::optional<Int32> num_digits; |
| 428 | if (config.has(user_config + ".time_based_one_time_password.digits")) |
| 429 | num_digits = config.getInt(user_config + ".time_based_one_time_password.digits"); |
| 430 | |
| 431 | std::optional<Int32> period; |
| 432 | if (config.has(user_config + ".time_based_one_time_password.period")) |
| 433 | period = config.getInt(user_config + ".time_based_one_time_password.period"); |
| 434 | |
| 435 | std::optional<String> algorithm_name; |
| 436 | if (config.has(user_config + ".time_based_one_time_password.algorithm")) |
| 437 | algorithm_name = config.getString(user_config + ".time_based_one_time_password.algorithm"); |
| 438 | |
| 439 | otp_secret.emplace(otp_secret_key, OneTimePasswordParams(num_digits, period, algorithm_name)); |
| 440 | } |
| 441 | |
| 442 | if (has_auth_methods) |
| 443 | { |
| 444 | validateNoFlatAuthFields(config, user_config, user_name); |
| 445 | |
| 446 | Poco::Util::AbstractConfiguration::Keys auth_methods; |
| 447 | config.keys(auth_methods_config, auth_methods); |
| 448 | for (const auto & auth_method : auth_methods) |
| 449 | { |
| 450 | const String auth_method_path = auth_methods_config + "." + auth_method; |
| 451 | if (config.has(auth_method_path + ".time_based_one_time_password")) |
| 452 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 453 | "'time_based_one_time_password' cannot be specified inside an individual authentication method for user {}. " |
| 454 | "It must be configured at the user level, outside of 'auth_methods'.", user_name); |
| 455 | user->authentication_methods.emplace_back(parseUserAuthMethod(config, user_name, auth_method_path, otp_secret)); |
| 456 | } |
| 457 | |
| 458 | if (user->authentication_methods.empty()) |
no test coverage detected