aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Interpreters/InterserverCredentials.cpp
blob: 094b58789a8d7e25a53e35a505b063fdb3ff93e9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <Interpreters/InterserverCredentials.h>
#include <Common/logger_useful.h>
#include <Common/StringUtils/StringUtils.h>

namespace DB
{

namespace ErrorCodes
{
    extern const int NO_ELEMENTS_IN_CONFIG;
}

std::unique_ptr<InterserverCredentials>
InterserverCredentials::make(const Poco::Util::AbstractConfiguration & config, const std::string & root_tag)
{
    if (config.has("user") && !config.has("password"))
        throw Exception(ErrorCodes::NO_ELEMENTS_IN_CONFIG, "Configuration parameter interserver_http_credentials.password can't be empty");

    if (!config.has("user") && config.has("password"))
        throw Exception(ErrorCodes::NO_ELEMENTS_IN_CONFIG,
                        "Configuration parameter interserver_http_credentials.user can't be empty if user specified");

    /// They both can be empty
    auto user = config.getString(root_tag + ".user", "");
    auto password = config.getString(root_tag + ".password", "");

    auto store = parseCredentialsFromConfig(user, password, config, root_tag);

    return std::make_unique<InterserverCredentials>(user, password, store);
}

InterserverCredentials::CurrentCredentials InterserverCredentials::parseCredentialsFromConfig(
    const std::string & current_user_,
    const std::string & current_password_,
    const Poco::Util::AbstractConfiguration & config,
    const std::string & root_tag)
{
    auto * log = &Poco::Logger::get("InterserverCredentials");
    CurrentCredentials store;
    store.emplace_back(current_user_, current_password_);
    if (config.getBool(root_tag + ".allow_empty", false))
    {
        LOG_DEBUG(log, "Allowing empty credentials");
        /// Allow empty credential to support migrating from no auth
        store.emplace_back("", "");
    }

    Poco::Util::AbstractConfiguration::Keys old_users;
    config.keys(root_tag, old_users);

    for (const auto & user_key : old_users)
    {
        if (startsWith(user_key, "old"))
        {
            std::string full_prefix = root_tag + "." + user_key;
            std::string old_user_name = config.getString(full_prefix + ".user");
            LOG_DEBUG(log, "Adding credentials for old user {}", old_user_name);

            std::string old_user_password =  config.getString(full_prefix + ".password");

            store.emplace_back(old_user_name, old_user_password);
        }
    }

    return store;
}

InterserverCredentials::CheckResult InterserverCredentials::isValidUser(const UserWithPassword & credentials) const
{
    auto itr = std::find(all_users_store.begin(), all_users_store.end(), credentials);

    if (itr == all_users_store.end())
    {
        if (credentials.first.empty())
            return {"Server requires HTTP Basic authentication, but client doesn't provide it", false};

        return {"Incorrect user or password in HTTP basic authentication: " + credentials.first, false};
    }

    return {"", true};
}

InterserverCredentials::CheckResult InterserverCredentials::isValidUser(const std::string & user, const std::string & password) const
{
    return isValidUser(std::make_pair(user, password));
}

}