2020-05-28 11:07:32 +00:00
|
|
|
#include "auth.hpp"
|
2023-10-24 13:18:03 +00:00
|
|
|
|
2023-10-19 11:49:46 +00:00
|
|
|
#include "protocol.hpp"
|
2020-05-28 11:07:32 +00:00
|
|
|
|
2023-09-15 14:55:32 +00:00
|
|
|
#include <llarp/router/router.hpp>
|
2022-01-17 12:57:08 +00:00
|
|
|
#include <llarp/util/fs.hpp>
|
2023-10-24 13:18:03 +00:00
|
|
|
#include <llarp/util/str.hpp>
|
2022-01-17 12:57:08 +00:00
|
|
|
|
2023-10-19 11:49:46 +00:00
|
|
|
#include <unordered_map>
|
|
|
|
|
2020-05-28 11:07:32 +00:00
|
|
|
namespace llarp::service
|
|
|
|
{
|
|
|
|
/// maybe get auth result from string
|
2023-11-03 13:40:14 +00:00
|
|
|
std::optional<AuthCode>
|
|
|
|
parse_auth_code(std::string data)
|
2020-05-28 11:07:32 +00:00
|
|
|
{
|
2023-11-03 13:40:14 +00:00
|
|
|
std::unordered_map<std::string, AuthCode> values = {
|
|
|
|
{"OKAY", AuthCode::ACCEPTED},
|
|
|
|
{"REJECT", AuthCode::REJECTED},
|
|
|
|
{"PAYME", AuthCode::PAYMENT_REQUIRED},
|
|
|
|
{"LIMITED", AuthCode::RATE_LIMIT}};
|
2020-05-28 11:07:32 +00:00
|
|
|
auto itr = values.find(data);
|
|
|
|
if (itr == values.end())
|
|
|
|
return std::nullopt;
|
|
|
|
return itr->second;
|
|
|
|
}
|
2020-06-30 16:02:29 +00:00
|
|
|
|
|
|
|
AuthType
|
2023-11-03 13:40:14 +00:00
|
|
|
parse_auth_type(std::string data)
|
2020-06-30 16:02:29 +00:00
|
|
|
{
|
2021-03-05 17:31:52 +00:00
|
|
|
std::unordered_map<std::string, AuthType> values = {
|
2023-11-03 13:40:14 +00:00
|
|
|
{"file", AuthType::FILE},
|
|
|
|
{"lmq", AuthType::OMQ},
|
|
|
|
{"whitelist", AuthType::WHITELIST},
|
|
|
|
{"none", AuthType::NONE}};
|
2020-06-30 16:02:29 +00:00
|
|
|
const auto itr = values.find(data);
|
|
|
|
if (itr == values.end())
|
|
|
|
throw std::invalid_argument("no such auth type: " + data);
|
|
|
|
return itr->second;
|
|
|
|
}
|
2021-02-24 18:41:23 +00:00
|
|
|
|
2022-04-01 16:52:25 +00:00
|
|
|
AuthFileType
|
2023-11-03 13:40:14 +00:00
|
|
|
parse_auth_file_type(std::string data)
|
2022-04-01 16:52:25 +00:00
|
|
|
{
|
|
|
|
std::unordered_map<std::string, AuthFileType> values = {
|
2023-11-03 13:40:14 +00:00
|
|
|
{"plain", AuthFileType::PLAIN},
|
|
|
|
{"plaintext", AuthFileType::PLAIN},
|
|
|
|
{"hashed", AuthFileType::HASHES},
|
|
|
|
{"hashes", AuthFileType::HASHES},
|
|
|
|
{"hash", AuthFileType::HASHES}};
|
2022-04-01 16:52:25 +00:00
|
|
|
const auto itr = values.find(data);
|
|
|
|
if (itr == values.end())
|
|
|
|
throw std::invalid_argument("no such auth file type: " + data);
|
2022-04-01 18:31:20 +00:00
|
|
|
#ifndef HAVE_CRYPT
|
2023-11-03 13:40:14 +00:00
|
|
|
if (itr->second == AuthFileType::HASHES)
|
2022-04-01 17:18:18 +00:00
|
|
|
throw std::invalid_argument("unsupported auth file type: " + data);
|
|
|
|
#endif
|
2022-04-01 16:52:25 +00:00
|
|
|
return itr->second;
|
|
|
|
}
|
|
|
|
|
2021-02-24 18:41:23 +00:00
|
|
|
/// turn an auth result code into an int
|
|
|
|
uint64_t
|
2023-11-03 13:40:14 +00:00
|
|
|
auth_code_to_int(AuthCode code)
|
2021-02-24 18:41:23 +00:00
|
|
|
{
|
2023-11-03 13:40:14 +00:00
|
|
|
return static_cast<std::underlying_type_t<AuthCode>>(code);
|
2021-02-24 18:41:23 +00:00
|
|
|
}
|
|
|
|
/// may turn an int into an auth result code
|
2023-11-03 13:40:14 +00:00
|
|
|
std::optional<AuthCode>
|
|
|
|
int_to_auth_code(uint64_t code)
|
2021-02-24 18:41:23 +00:00
|
|
|
{
|
|
|
|
switch (code)
|
|
|
|
{
|
|
|
|
case 0:
|
2023-11-03 13:40:14 +00:00
|
|
|
return AuthCode::ACCEPTED;
|
2021-02-24 18:41:23 +00:00
|
|
|
case 1:
|
2023-11-03 13:40:14 +00:00
|
|
|
return AuthCode::REJECTED;
|
2021-02-24 18:41:23 +00:00
|
|
|
case 2:
|
2023-11-03 13:40:14 +00:00
|
|
|
return AuthCode::FAILED;
|
2021-02-24 18:41:23 +00:00
|
|
|
case 3:
|
2023-11-03 13:40:14 +00:00
|
|
|
return AuthCode::RATE_LIMIT;
|
2021-02-24 18:41:23 +00:00
|
|
|
case 4:
|
2023-11-03 13:40:14 +00:00
|
|
|
return AuthCode::PAYMENT_REQUIRED;
|
2021-02-24 18:41:23 +00:00
|
|
|
default:
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-17 12:57:08 +00:00
|
|
|
class FileAuthPolicy : public IAuthPolicy, public std::enable_shared_from_this<FileAuthPolicy>
|
|
|
|
{
|
|
|
|
const std::set<fs::path> m_Files;
|
2022-04-01 16:52:25 +00:00
|
|
|
const AuthFileType m_Type;
|
2023-09-15 14:55:32 +00:00
|
|
|
Router* const m_Router;
|
2022-01-17 12:57:08 +00:00
|
|
|
mutable util::Mutex m_Access;
|
|
|
|
std::unordered_set<ConvoTag> m_Pending;
|
|
|
|
/// returns an auth result for a auth info challange, opens every file until it finds a token
|
|
|
|
/// matching it
|
|
|
|
/// this is expected to be done in the IO thread
|
|
|
|
AuthResult
|
2023-11-03 13:40:14 +00:00
|
|
|
check_files(const AuthInfo& info) const
|
2022-01-17 12:57:08 +00:00
|
|
|
{
|
|
|
|
for (const auto& f : m_Files)
|
|
|
|
{
|
|
|
|
fs::ifstream i{f};
|
|
|
|
std::string line{};
|
|
|
|
while (std::getline(i, line))
|
|
|
|
{
|
|
|
|
// split off comments
|
|
|
|
const auto parts = split_any(line, "#;", true);
|
|
|
|
if (auto part = parts[0]; not parts.empty() and not parts[0].empty())
|
|
|
|
{
|
2022-04-01 16:52:25 +00:00
|
|
|
// split off whitespaces and check password
|
2023-11-03 13:40:14 +00:00
|
|
|
if (check_passwd(std::string{TrimWhitespace(part)}, info.token))
|
|
|
|
return AuthResult{AuthCode::ACCEPTED, "accepted by whitelist"};
|
2022-01-17 12:57:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-03 13:40:14 +00:00
|
|
|
return AuthResult{AuthCode::REJECTED, "rejected by whitelist"};
|
2022-01-17 12:57:08 +00:00
|
|
|
}
|
|
|
|
|
2022-04-01 16:52:25 +00:00
|
|
|
bool
|
2023-11-03 13:40:14 +00:00
|
|
|
check_passwd(std::string hash, std::string challenge) const
|
2022-04-01 16:52:25 +00:00
|
|
|
{
|
|
|
|
switch (m_Type)
|
|
|
|
{
|
2023-11-03 13:40:14 +00:00
|
|
|
case AuthFileType::PLAIN:
|
2022-04-01 16:52:25 +00:00
|
|
|
return hash == challenge;
|
2023-11-03 13:40:14 +00:00
|
|
|
case AuthFileType::HASHES:
|
2023-10-25 20:14:54 +00:00
|
|
|
#ifdef HAVE_CRYPT
|
2023-10-23 22:58:58 +00:00
|
|
|
return crypto::check_passwd_hash(std::move(hash), std::move(challenge));
|
2023-10-25 20:14:54 +00:00
|
|
|
#endif
|
2022-04-01 16:52:25 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-17 12:57:08 +00:00
|
|
|
public:
|
2023-09-15 14:55:32 +00:00
|
|
|
FileAuthPolicy(Router* r, std::set<fs::path> files, AuthFileType filetype)
|
2022-04-01 16:52:25 +00:00
|
|
|
: m_Files{std::move(files)}, m_Type{filetype}, m_Router{r}
|
2022-01-17 12:57:08 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
2023-11-03 13:40:14 +00:00
|
|
|
authenticate_async(
|
2023-10-18 12:48:09 +00:00
|
|
|
std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> hook) override
|
2022-01-17 12:57:08 +00:00
|
|
|
{
|
|
|
|
auto reply = m_Router->loop()->make_caller(
|
|
|
|
[tag = msg->tag, hook, self = shared_from_this()](AuthResult result) {
|
|
|
|
{
|
|
|
|
util::Lock _lock{self->m_Access};
|
|
|
|
self->m_Pending.erase(tag);
|
|
|
|
}
|
2023-11-03 13:40:14 +00:00
|
|
|
hook(result.reason, result.code == AuthCode::ACCEPTED);
|
2022-01-17 12:57:08 +00:00
|
|
|
});
|
|
|
|
{
|
|
|
|
util::Lock _lock{m_Access};
|
|
|
|
m_Pending.emplace(msg->tag);
|
|
|
|
}
|
|
|
|
if (msg->proto == ProtocolType::Auth)
|
|
|
|
{
|
2023-09-15 14:55:32 +00:00
|
|
|
m_Router->queue_disk_io(
|
2022-01-17 12:57:08 +00:00
|
|
|
[self = shared_from_this(),
|
|
|
|
auth = AuthInfo{std::string{
|
|
|
|
reinterpret_cast<const char*>(msg->payload.data()), msg->payload.size()}},
|
|
|
|
reply]() {
|
|
|
|
try
|
|
|
|
{
|
2023-11-03 13:40:14 +00:00
|
|
|
reply(self->check_files(auth));
|
2022-01-17 12:57:08 +00:00
|
|
|
}
|
|
|
|
catch (std::exception& ex)
|
|
|
|
{
|
2023-11-03 13:40:14 +00:00
|
|
|
reply(AuthResult{AuthCode::FAILED, ex.what()});
|
2022-01-17 12:57:08 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
2023-11-03 13:40:14 +00:00
|
|
|
reply(AuthResult{AuthCode::REJECTED, "protocol error"});
|
2022-01-17 12:57:08 +00:00
|
|
|
}
|
|
|
|
bool
|
2023-11-03 13:40:14 +00:00
|
|
|
auth_async_pending(ConvoTag tag) const override
|
2022-01-17 12:57:08 +00:00
|
|
|
{
|
|
|
|
util::Lock _lock{m_Access};
|
|
|
|
return m_Pending.count(tag);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::shared_ptr<IAuthPolicy>
|
2023-11-03 13:40:14 +00:00
|
|
|
make_file_auth_policy(Router* r, std::set<fs::path> files, AuthFileType filetype)
|
2022-01-17 12:57:08 +00:00
|
|
|
{
|
2022-04-01 16:52:25 +00:00
|
|
|
return std::make_shared<FileAuthPolicy>(r, std::move(files), filetype);
|
2022-01-17 12:57:08 +00:00
|
|
|
}
|
|
|
|
|
2020-05-28 11:07:32 +00:00
|
|
|
} // namespace llarp::service
|