**Use case**
In some organisations are using AD with hierarchical structure (nested organisation unit) and DN follow this structure. As result we can not  use permanent build_dn for users with different OU.

**Describe the solution you'd like**
Solution can be look like:
1) bind as service account
2) set dn for user_name by some filter string to user_dn
3) bind as user_dn with password
3) use user_dn with filter for group/roles fetching

This approach is implemented in Metabase.

const bool has_role_mapping = config.has(prefix_str + "role_mapping");
    if (!has_server)
        throw Exception("Missing 'server' field for LDAP user directory", ErrorCodes::BAD_ARGUMENTS);
    const auto ldap_server_name_cfg = config.getString(prefix_str + "server");
    if (ldap_server_name_cfg.empty())
        throw Exception("Empty 'server' field for LDAP user directory", ErrorCodes::BAD_ARGUMENTS);
    std::set<String> common_roles_cfg;
    if (has_roles)
    {
        Poco::Util::AbstractConfiguration::Keys role_names;
        config.keys(prefix_str + "roles", role_names);
        
        common_roles_cfg.insert(role_names.begin(), role_names.end());
    }
    LDAPClient::SearchParamsList 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", "");
            rm_params.search_filter = config.getString(rm_prefix_str + "search_filter", "");
            rm_params.attribute = config.getString(rm_prefix_str + "attribute", "cn");