From a082ba4e7706ab38ff8407cbb735ee032753eb22 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 17 Jan 2022 07:57:08 -0500 Subject: [PATCH] add file auth for tokens --- llarp/config/config.cpp | 21 +++++++++- llarp/config/config.hpp | 1 + llarp/handlers/tun.cpp | 6 ++- llarp/service/auth.cpp | 92 +++++++++++++++++++++++++++++++++++++++++ llarp/service/auth.hpp | 8 +++- 5 files changed, 124 insertions(+), 4 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index f6c09f881..1e640373a 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -317,7 +317,7 @@ namespace llarp ClientOnly, Comment{ "Set the endpoint authentication mechanism.", - "none/whitelist/lmq", + "none/whitelist/lmq/file", }, [this](std::string arg) { if (arg.empty()) @@ -366,13 +366,30 @@ namespace llarp m_AuthWhitelist.emplace(std::move(addr)); }); + conf.defineOption( + "network", + "auth-file", + ClientOnly, + MultiValue, + Comment{ + "Read auth tokens from file to accept endpoint auth", + "Can be provided multiple times", + }, + [this](fs::path arg) { + if (not fs::exists(arg)) + throw std::invalid_argument{ + stringify("cannot load auth file ", arg, " as it does not seem to exist")}; + m_AuthFiles.emplace(std::move(arg)); + }); + conf.defineOption( "network", "auth-static", ClientOnly, MultiValue, Comment{ - "manually add a static auth code to accept for endpoint auth", + "Manually add a static auth code to accept for endpoint auth", + "Can be provided multiple times", }, [this](std::string arg) { m_AuthStaticTokens.emplace(std::move(arg)); }); diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index bf2e61b8b..6f6d82ef2 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -119,6 +119,7 @@ namespace llarp std::optional m_AuthMethod; std::unordered_set m_AuthWhitelist; std::unordered_set m_AuthStaticTokens; + std::set m_AuthFiles; std::vector m_SRVRecords; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 050cac60c..6f7f27103 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -174,7 +174,11 @@ namespace llarp LogInfo(Name(), " setting to be not reachable by default"); } - if (conf.m_AuthType != service::AuthType::eAuthTypeNone) + if (conf.m_AuthType == service::AuthType::eAuthTypeFile) + { + m_AuthPolicy = service::MakeFileAuthPolicy(m_router, conf.m_AuthFiles); + } + else if (conf.m_AuthType != service::AuthType::eAuthTypeNone) { std::string url, method; if (conf.m_AuthUrl.has_value() and conf.m_AuthMethod.has_value()) diff --git a/llarp/service/auth.cpp b/llarp/service/auth.cpp index 2f631f3fb..a5e4518a0 100644 --- a/llarp/service/auth.cpp +++ b/llarp/service/auth.cpp @@ -1,6 +1,11 @@ #include "auth.hpp" #include +#include +#include "protocol.hpp" +#include +#include + namespace llarp::service { /// maybe get auth result from string @@ -22,6 +27,7 @@ namespace llarp::service ParseAuthType(std::string data) { std::unordered_map values = { + {"file", AuthType::eAuthTypeFile}, {"lmq", AuthType::eAuthTypeLMQ}, {"whitelist", AuthType::eAuthTypeWhitelist}, {"none", AuthType::eAuthTypeNone}}; @@ -58,4 +64,90 @@ namespace llarp::service } } + class FileAuthPolicy : public IAuthPolicy, public std::enable_shared_from_this + { + const std::set m_Files; + AbstractRouter* const m_Router; + mutable util::Mutex m_Access; + std::unordered_set 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 + CheckFiles(const AuthInfo& info) const + { + 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 + if (TrimWhitespace(part) == info.token) + return AuthResult{AuthResultCode::eAuthAccepted, "accepted by whitelist"}; + } + } + } + return AuthResult{AuthResultCode::eAuthRejected, "rejected by whitelist"}; + } + + public: + FileAuthPolicy(AbstractRouter* r, std::set files) + : m_Files{std::move(files)}, m_Router{r} + {} + + void + AuthenticateAsync( + std::shared_ptr msg, std::function hook) override + { + 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); + } + hook(result); + }); + { + util::Lock _lock{m_Access}; + m_Pending.emplace(msg->tag); + } + if (msg->proto == ProtocolType::Auth) + { + m_Router->QueueDiskIO( + [self = shared_from_this(), + auth = AuthInfo{std::string{ + reinterpret_cast(msg->payload.data()), msg->payload.size()}}, + reply]() { + try + { + reply(self->CheckFiles(auth)); + } + catch (std::exception& ex) + { + reply(AuthResult{AuthResultCode::eAuthFailed, ex.what()}); + } + }); + } + else + reply(AuthResult{AuthResultCode::eAuthRejected, "protocol error"}); + } + bool + AsyncAuthPending(ConvoTag tag) const override + { + util::Lock _lock{m_Access}; + return m_Pending.count(tag); + } + }; + + std::shared_ptr + MakeFileAuthPolicy(AbstractRouter* r, std::set files) + { + return std::make_shared(r, std::move(files)); + } + } // namespace llarp::service diff --git a/llarp/service/auth.hpp b/llarp/service/auth.hpp index 98e515e02..fd094f475 100644 --- a/llarp/service/auth.hpp +++ b/llarp/service/auth.hpp @@ -71,7 +71,9 @@ namespace llarp::service /// manual whitelist eAuthTypeWhitelist, /// LMQ server - eAuthTypeLMQ + eAuthTypeLMQ, + /// plain file + eAuthTypeFile, }; /// get an auth type from a string @@ -79,4 +81,8 @@ namespace llarp::service AuthType ParseAuthType(std::string arg); + /// make an IAuthPolicy that reads out of a static file + std::shared_ptr + MakeFileAuthPolicy(AbstractRouter*, std::set files); + } // namespace llarp::service