lokinet/llarp/service/auth.cpp

192 lines
5.4 KiB
C++
Raw Normal View History

2020-05-28 11:07:32 +00:00
#include "auth.hpp"
#include "protocol.hpp"
2020-05-28 11:07:32 +00:00
#include <llarp/router/router.hpp>
2022-01-17 12:57:08 +00:00
#include <llarp/util/fs.hpp>
#include <llarp/util/str.hpp>
2022-01-17 12:57:08 +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;
}
AuthType
2023-11-03 13:40:14 +00:00
parse_auth_type(std::string data)
{
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}};
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
AuthFileType
2023-11-03 13:40:14 +00:00
parse_auth_file_type(std::string data)
{
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}};
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
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;
const AuthFileType m_Type;
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())
{
// 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
}
bool
2023-11-03 13:40:14 +00:00
check_passwd(std::string hash, std::string challenge) const
{
switch (m_Type)
{
2023-11-03 13:40:14 +00:00
case AuthFileType::PLAIN:
return hash == challenge;
2023-11-03 13:40:14 +00:00
case AuthFileType::HASHES:
#ifdef HAVE_CRYPT
2023-10-23 22:58:58 +00:00
return crypto::check_passwd_hash(std::move(hash), std::move(challenge));
#endif
default:
return false;
}
}
2022-01-17 12:57:08 +00:00
public:
FileAuthPolicy(Router* r, std::set<fs::path> files, AuthFileType filetype)
: 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(
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)
{
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
{
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