Fix memory management issue, remove strict allocators and make connector more polite to memory overflow errors
This commit is contained in:
parent
65e3a5a73c
commit
161ba94f45
@ -36,16 +36,17 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
return PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto session = rublon::RublonFactory{}.startSession(pam);
|
Session session{pam};
|
||||||
if(not session.has_value()) {
|
auto ok = rublon::RublonFactory{}.initializeSession(session);
|
||||||
|
if(not ok.has_value()) {
|
||||||
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!session->config().logging) {
|
if(!session.config().logging) {
|
||||||
g_level = LogLevel::Warning;
|
g_level = LogLevel::Warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto & CH = session.value().coreHandler();
|
auto & CH = session.coreHandler();
|
||||||
|
|
||||||
auto selectMethod = [&](const MethodSelect & selector) { //
|
auto selectMethod = [&](const MethodSelect & selector) { //
|
||||||
return selector.create(pam);
|
return selector.create(pam);
|
||||||
@ -56,13 +57,13 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto confirmCode = [&](const MethodProxy & method) mutable { //
|
auto confirmCode = [&](const MethodProxy & method) mutable { //
|
||||||
return method.fire(session.value(), CH, pam);
|
return method.fire(session, CH, pam);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > {
|
auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > {
|
||||||
if(status.userAuthorized()) {
|
if(status.userAuthorized()) {
|
||||||
auto tok = std::string{status.accessToken().data()};
|
auto tok = std::string{status.accessToken().data()};
|
||||||
Finish finish{session.value(), std::move(tok)};
|
Finish finish{session, std::move(tok)};
|
||||||
finish.handle(CH);
|
finish.handle(CH);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@ -73,20 +74,20 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto mapError = [&](const Error & error) -> tl::expected< int, Error > {
|
auto mapError = [&](const Error & error) -> tl::expected< int, Error > {
|
||||||
return printAuthMessageAndExit(rublon::ErrorHandler{pam, session->config()}.printErrorDetails(error));
|
return printAuthMessageAndExit(rublon::ErrorHandler{pam, session.config()}.printErrorDetails(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
CheckApplication ca;
|
CheckApplication ca;
|
||||||
auto ret =
|
auto ret =
|
||||||
ca.call(CH, {session.value().config().systemToken.data(), session.value().config().systemToken.size()}).or_else(mapError);
|
ca.call(CH, {session.config().systemToken.data(), session.config().systemToken.size()}).or_else(mapError);
|
||||||
if(not ret.has_value()) {
|
if(not ret.has_value()) {
|
||||||
log(LogLevel::Error, "Check Application step failed, check configration");
|
log(LogLevel::Error, "Check Application step failed, check configration");
|
||||||
return PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = Init{session.value()}
|
auto ret = Init{session}
|
||||||
.handle(CH, pam) //
|
.handle(CH, pam) //
|
||||||
.and_then(selectMethod)
|
.and_then(selectMethod)
|
||||||
.and_then(confirmMethod)
|
.and_then(confirmMethod)
|
||||||
|
|||||||
@ -136,7 +136,7 @@ class Status {
|
|||||||
|
|
||||||
void save() {
|
void save() {
|
||||||
if(updated()) {
|
if(updated()) {
|
||||||
memory::Monotonic_8k_HeapResource tmpResource;
|
memory::Monotonic_8k_Resource tmpResource;
|
||||||
RapidJSONPMRAlloc alloc{&tmpResource};
|
RapidJSONPMRAlloc alloc{&tmpResource};
|
||||||
FileWriter s{_statusFilePath};
|
FileWriter s{_statusFilePath};
|
||||||
rapidjson::PrettyWriter< FileWriter, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc};
|
rapidjson::PrettyWriter< FileWriter, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc};
|
||||||
@ -147,7 +147,7 @@ class Status {
|
|||||||
|
|
||||||
std::string print() {
|
std::string print() {
|
||||||
std::string result;
|
std::string result;
|
||||||
memory::Monotonic_8k_HeapResource tmpResource;
|
memory::Monotonic_8k_Resource tmpResource;
|
||||||
RapidJSONPMRAlloc alloc{&tmpResource};
|
RapidJSONPMRAlloc alloc{&tmpResource};
|
||||||
StringWriter s{result};
|
StringWriter s{result};
|
||||||
rapidjson::PrettyWriter< StringWriter< std::string >, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc};
|
rapidjson::PrettyWriter< StringWriter< std::string >, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc};
|
||||||
@ -171,7 +171,7 @@ class CheckApplication {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
tl::expected< int, Error > call(const CoreHandler_t & coreHandler, std::string_view systemToken) const {
|
tl::expected< int, Error > call(const CoreHandler_t & coreHandler, std::string_view systemToken) const {
|
||||||
memory::Monotonic_1k_HeapResource mr;
|
memory::Monotonic_1k_Resource mr;
|
||||||
RapidJSONPMRStackAlloc< 2048 > alloc{};
|
RapidJSONPMRStackAlloc< 2048 > alloc{};
|
||||||
constexpr std::string_view api = "/api/app/init";
|
constexpr std::string_view api = "/api/app/init";
|
||||||
Status status;
|
Status status;
|
||||||
|
|||||||
@ -49,18 +49,20 @@ class Configuration {
|
|||||||
|
|
||||||
class ConfigurationReader {
|
class ConfigurationReader {
|
||||||
public:
|
public:
|
||||||
ConfigurationReader(std::pmr::memory_resource * memResource = memory::default_resource()) : memoryResource(memResource) {}
|
ConfigurationReader(std::pmr::memory_resource * memResource, std::string_view filepath) : memoryResource(memResource) {
|
||||||
|
loadFromFile(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
// Load config from file path
|
// Load config from file path
|
||||||
bool loadFromFile(std::string_view filepath) {
|
void loadFromFile(std::string_view filepath) {
|
||||||
using namespace memory::literals;
|
using namespace memory::literals;
|
||||||
memory::MonotonicStackResource< 8_kB > stackResource;
|
memory::MonotonicStackResource< 4_kB > stackResource;
|
||||||
std::ifstream file(filepath.data());
|
std::ifstream file(filepath.data());
|
||||||
if(not file.good())
|
if(not file.good())
|
||||||
return false;
|
return ;
|
||||||
|
|
||||||
std::pmr::string line{&stackResource};
|
std::pmr::string line{&stackResource};
|
||||||
line.reserve(8000); // allocate full stack to line
|
line.reserve(4000); // allocate full stack to line
|
||||||
|
|
||||||
while(std::getline(file, line)) {
|
while(std::getline(file, line)) {
|
||||||
std::pmr::string key{memoryResource};
|
std::pmr::string key{memoryResource};
|
||||||
@ -79,8 +81,6 @@ class ConfigurationReader {
|
|||||||
|
|
||||||
keyValues[std::move(key)] = std::move(value);
|
keyValues[std::move(key)] = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load values into Configuration object, with defaults provided
|
// Load values into Configuration object, with defaults provided
|
||||||
@ -220,18 +220,4 @@ class ConfigurationReader {
|
|||||||
std::pmr::unordered_map< std::pmr::string, std::pmr::string > keyValues{memoryResource};
|
std::pmr::unordered_map< std::pmr::string, std::pmr::string > keyValues{memoryResource};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfigurationFactory {
|
|
||||||
public:
|
|
||||||
ConfigurationFactory() = default;
|
|
||||||
|
|
||||||
std::optional< Configuration > systemConfig() {
|
|
||||||
std::optional< Configuration > conf{Configuration{}};
|
|
||||||
ConfigurationReader reader{};
|
|
||||||
reader.loadFromFile("/etc/rublon.config");
|
|
||||||
if(auto ok = reader.applyTo(conf.value()); not ok.has_value()) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
return conf.value();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace rublon
|
} // namespace rublon
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "rublon/error.hpp"
|
#include "rublon/error.hpp"
|
||||||
#include "rublon/static_string.hpp"
|
#include "rublon/static_string.hpp"
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <rublon/configuration.hpp>
|
#include <rublon/configuration.hpp>
|
||||||
@ -20,12 +21,17 @@ namespace rublon {
|
|||||||
|
|
||||||
template < typename HttpHandler = CURL >
|
template < typename HttpHandler = CURL >
|
||||||
class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
||||||
Configuration _config;
|
std::reference_wrapper< const Configuration > _config;
|
||||||
mutable std::unique_ptr< WebSocket > _ws; /// TODO try to remove mutable modyfier
|
mutable std::unique_ptr< WebSocket > _ws; /// TODO try to remove mutable modyfier
|
||||||
|
HttpHandler http{};
|
||||||
|
|
||||||
|
const Configuration & config() const noexcept {
|
||||||
|
return _config.get();
|
||||||
|
}
|
||||||
|
|
||||||
void signRequest(Request & request) const {
|
void signRequest(Request & request) const {
|
||||||
request.headers["X-Rublon-Signature"] =
|
request.headers["X-Rublon-Signature"] =
|
||||||
std::pmr::string{signData(request.body, _config.secretKey).c_str(), request.headers.get_allocator()};
|
std::pmr::string{signData(request.body, config().secretKey).c_str(), request.headers.get_allocator()};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasSignature(const Response & response) const {
|
bool hasSignature(const Response & response) const {
|
||||||
@ -50,7 +56,7 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
|||||||
|
|
||||||
bool signatureIsNatValid(const Response & response) const {
|
bool signatureIsNatValid(const Response & response) const {
|
||||||
const auto & xRubResp = response.headers.at("x-rublon-signature");
|
const auto & xRubResp = response.headers.at("x-rublon-signature");
|
||||||
const auto & sign = signData(response.body, _config.secretKey);
|
const auto & sign = signData(response.body, config().secretKey);
|
||||||
const bool signatureMatch = xRubResp == sign.data();
|
const bool signatureMatch = xRubResp == sign.data();
|
||||||
if(not signatureMatch)
|
if(not signatureMatch)
|
||||||
log(LogLevel::Error, "Signature mismatch %s != %s ", xRubResp.c_str(), sign.data());
|
log(LogLevel::Error, "Signature mismatch %s != %s ", xRubResp.c_str(), sign.data());
|
||||||
@ -68,19 +74,16 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
|||||||
return coreResponse.HasParseError();
|
return coreResponse.HasParseError();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
HttpHandler http{};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CoreHandler() = delete;
|
CoreHandler() = delete;
|
||||||
CoreHandler(const Configuration & config) : _config{config}, _ws{std::make_unique<WebSocket>(_config)}, http{_config} {
|
CoreHandler(const Configuration & baseconfig) : _config{baseconfig}, _ws{std::make_unique< WebSocket >(_config)}, http{config()} {
|
||||||
log(LogLevel::Debug, "Core Handler apiServer: %s", _config.apiServer.c_str());
|
log(LogLevel::Debug, "Core Handler apiServer: %s", config().apiServer.c_str());
|
||||||
}
|
}
|
||||||
CoreHandler(CoreHandler &&) noexcept = default;
|
|
||||||
CoreHandler & operator=(CoreHandler &&) = default;
|
|
||||||
|
|
||||||
CoreHandler(const CoreHandler &) = delete;
|
CoreHandler(const CoreHandler &) = delete;
|
||||||
|
CoreHandler(CoreHandler &&) noexcept = delete;
|
||||||
|
|
||||||
CoreHandler & operator=(const CoreHandler &) = delete;
|
CoreHandler & operator=(const CoreHandler &) = delete;
|
||||||
|
CoreHandler & operator=(CoreHandler &&) = delete;
|
||||||
|
|
||||||
~CoreHandler() noexcept = default;
|
~CoreHandler() noexcept = default;
|
||||||
|
|
||||||
@ -131,7 +134,6 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tl::unexpected< Error > handleCoreException(std::string_view exceptionString) const {
|
tl::unexpected< Error > handleCoreException(std::string_view exceptionString) const {
|
||||||
log(LogLevel::Debug, "TMP got core exception: %s", exceptionString.data() );
|
|
||||||
// can happen only during check application step
|
// can happen only during check application step
|
||||||
if(auto error = RublonCheckApplicationException::fromString(exceptionString); error.has_value())
|
if(auto error = RublonCheckApplicationException::fromString(exceptionString); error.has_value())
|
||||||
return tl::unexpected{Error{error.value()}};
|
return tl::unexpected{Error{error.value()}};
|
||||||
@ -155,7 +157,7 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tl::expected< Document, Error > request(RapidJSONPMRAlloc & mr, std::string_view path, const Document & body) const {
|
tl::expected< Document, Error > request(RapidJSONPMRAlloc & mr, std::string_view path, const Document & body) const {
|
||||||
memory::StrictMonotonic_8k_HeapResource memoryResource;
|
memory::Monotonic_8k_Resource memoryResource;
|
||||||
|
|
||||||
const auto validateSignature = [&](const auto & arg) { return this->validateSignature(arg); };
|
const auto validateSignature = [&](const auto & arg) { return this->validateSignature(arg); };
|
||||||
const auto validateResponse = [&](const auto & arg) { return this->validateResponse(mr, arg); };
|
const auto validateResponse = [&](const auto & arg) { return this->validateResponse(mr, arg); };
|
||||||
@ -172,8 +174,8 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
|||||||
|
|
||||||
signRequest(request);
|
signRequest(request);
|
||||||
std::pmr::string uri{&memoryResource};
|
std::pmr::string uri{&memoryResource};
|
||||||
uri.reserve(_config.apiServer.size() + path.size() + 1);
|
uri.reserve(config().apiServer.size() + path.size() + 1);
|
||||||
uri += _config.apiServer;
|
uri += config().apiServer;
|
||||||
uri += path.data();
|
uri += path.data();
|
||||||
|
|
||||||
return http
|
return http
|
||||||
@ -185,7 +187,7 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
|||||||
|
|
||||||
bool createWSConnection(std::string_view tid) const {
|
bool createWSConnection(std::string_view tid) const {
|
||||||
if(not _ws) {
|
if(not _ws) {
|
||||||
_ws.reset(new WebSocket (_config));
|
_ws.reset(new WebSocket(config()));
|
||||||
}
|
}
|
||||||
/// TODO connect can be separated from subscribtion on event
|
/// TODO connect can be separated from subscribtion on event
|
||||||
/// TODO status of attach is not checked
|
/// TODO status of attach is not checked
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "rublon/memory.hpp"
|
#include "rublon/memory.hpp"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
#include <rublon/configuration.hpp>
|
#include <rublon/configuration.hpp>
|
||||||
#include <rublon/error.hpp>
|
#include <rublon/error.hpp>
|
||||||
#include <rublon/utils.hpp>
|
#include <rublon/utils.hpp>
|
||||||
@ -54,16 +55,26 @@ struct Response {
|
|||||||
|
|
||||||
class CURL {
|
class CURL {
|
||||||
std::unique_ptr< ::CURL, void (*)(::CURL *) > curl;
|
std::unique_ptr< ::CURL, void (*)(::CURL *) > curl;
|
||||||
const Configuration & _config;
|
std::reference_wrapper< const Configuration > _config;
|
||||||
|
|
||||||
|
const Configuration & conf() const noexcept {
|
||||||
|
return _config.get();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CURL(const Configuration & config)
|
CURL(const Configuration & config)
|
||||||
: curl{std::unique_ptr< ::CURL, void (*)(::CURL *) >(curl_easy_init(), curl_easy_cleanup)}, _config{config} {}
|
: curl{std::unique_ptr< ::CURL, void (*)(::CURL *) >(curl_easy_init(), curl_easy_cleanup)}, _config{config} {}
|
||||||
|
|
||||||
|
CURL(const CURL &) = delete;
|
||||||
|
CURL(CURL &&) = delete;
|
||||||
|
|
||||||
|
CURL & operator=(const CURL &) = delete;
|
||||||
|
CURL & operator=(CURL &&) = delete;
|
||||||
|
|
||||||
tl::expected< std::reference_wrapper< Response >, ConnectionError >
|
tl::expected< std::reference_wrapper< Response >, ConnectionError >
|
||||||
request(std::string_view uri, const Request & request, Response & response) const {
|
request(std::string_view uri, const Request & request, Response & response) const {
|
||||||
using namespace memory::literals;
|
using namespace memory::literals;
|
||||||
memory::Monotonic_8k_HeapResource memoryResource;
|
memory::Monotonic_8k_Resource memoryResource;
|
||||||
|
|
||||||
std::pmr::string response_data{&memoryResource};
|
std::pmr::string response_data{&memoryResource};
|
||||||
response_data.reserve(4_kB);
|
response_data.reserve(4_kB);
|
||||||
@ -75,46 +86,45 @@ class CURL {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Optional: Build full proxy URL if proxy is enabled
|
// Optional: Build full proxy URL if proxy is enabled
|
||||||
if(_config.proxyEnabled) {
|
if(conf().proxyEnabled) {
|
||||||
// configuration reader check if proxy has needed fields
|
// configuration reader check if proxy has needed fields
|
||||||
assert(_config.proxyType.has_value());
|
assert(conf().proxyType.has_value());
|
||||||
assert(_config.proxyServer.has_value());
|
assert(conf().proxyServer.has_value());
|
||||||
|
|
||||||
std::pmr::string proxyUrl{&memoryResource};
|
std::pmr::string proxyUrl{&memoryResource};
|
||||||
proxyUrl.reserve(conservative_estimate(_config.proxyType, _config.proxyServer, _config.proxyPort) + 10);
|
proxyUrl.reserve(conservative_estimate(conf().proxyType, conf().proxyServer, conf().proxyPort) + 10);
|
||||||
|
|
||||||
if(_config.proxyType == "http" || _config.proxyType == "https" || _config.proxyType == "socks4" ||
|
if(conf().proxyType == "http" || conf().proxyType == "https" || conf().proxyType == "socks4" || conf().proxyType == "socks5") {
|
||||||
_config.proxyType == "socks5") {
|
proxyUrl = *conf().proxyType;
|
||||||
proxyUrl = *_config.proxyType;
|
|
||||||
proxyUrl += "://";
|
proxyUrl += "://";
|
||||||
proxyUrl += *_config.proxyServer;
|
proxyUrl += *conf().proxyServer;
|
||||||
if(_config.proxyPort > 0) {
|
if(conf().proxyPort > 0) {
|
||||||
proxyUrl += ":";
|
proxyUrl += ":";
|
||||||
proxyUrl += std::to_string(*_config.proxyPort);
|
proxyUrl += std::to_string(*conf().proxyPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_PROXY, proxyUrl.c_str());
|
curl_easy_setopt(curl.get(), CURLOPT_PROXY, proxyUrl.c_str());
|
||||||
|
|
||||||
if(_config.proxyType == "socks4") {
|
if(conf().proxyType == "socks4") {
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
curl_easy_setopt(curl.get(), CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
||||||
} else if(_config.proxyType == "socks5") {
|
} else if(conf().proxyType == "socks5") {
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
curl_easy_setopt(curl.get(), CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
||||||
} else {
|
} else {
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
curl_easy_setopt(curl.get(), CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_config.proxyAuthRequired) {
|
if(conf().proxyAuthRequired) {
|
||||||
assert(_config.proxyUsername.has_value());
|
assert(conf().proxyUsername.has_value());
|
||||||
assert(_config.proxyPass.has_value());
|
assert(conf().proxyPass.has_value());
|
||||||
|
|
||||||
std::pmr::string proxyAuth{&memoryResource};
|
std::pmr::string proxyAuth{&memoryResource};
|
||||||
proxyAuth.reserve(conservative_estimate(_config.proxyUsername, _config.proxyPass));
|
proxyAuth.reserve(conservative_estimate(conf().proxyUsername, conf().proxyPass));
|
||||||
|
|
||||||
proxyAuth += *_config.proxyUsername;
|
proxyAuth += *conf().proxyUsername;
|
||||||
if(_config.proxyPass->size()) {
|
if(conf().proxyPass->size()) {
|
||||||
// can proxy have name but no pass?
|
// can proxy have name but no pass?
|
||||||
proxyAuth += ":";
|
proxyAuth += ":";
|
||||||
proxyAuth += *_config.proxyPass;
|
proxyAuth += *conf().proxyPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl.get(), CURLOPT_PROXYUSERPWD, proxyAuth.c_str());
|
curl_easy_setopt(curl.get(), CURLOPT_PROXYUSERPWD, proxyAuth.c_str());
|
||||||
|
|||||||
@ -126,12 +126,14 @@ class WerificationError {
|
|||||||
BadInput, // User input has incorrect characters or length
|
BadInput, // User input has incorrect characters or length
|
||||||
SecurityKeyException, // code: 16
|
SecurityKeyException, // code: 16
|
||||||
PasscodeException, // code: 18
|
PasscodeException, // code: 18
|
||||||
|
SendPushException, // code: 21 | this code really should not be here as rest of the codes are strictly for passcode verification
|
||||||
TooManyRequestsException // code: 101
|
TooManyRequestsException // code: 101
|
||||||
};
|
};
|
||||||
constexpr static auto errorClassPrettyName = make_array< std::string_view >( //
|
constexpr static auto errorClassPrettyName = make_array< std::string_view >( //
|
||||||
"BadInput",
|
"BadInput",
|
||||||
"SecurityKeyException",
|
"SecurityKeyException",
|
||||||
"PasscodeException",
|
"PasscodeException",
|
||||||
|
"SendPushException",
|
||||||
"TooManyRequestsException");
|
"TooManyRequestsException");
|
||||||
constexpr static inline auto prettyName = "Werification Error";
|
constexpr static inline auto prettyName = "Werification Error";
|
||||||
|
|
||||||
|
|||||||
@ -66,12 +66,15 @@ class ErrorHandler {
|
|||||||
case WerificationError::ErrorClass::BadInput:
|
case WerificationError::ErrorClass::BadInput:
|
||||||
pam.print(R"(Ensure that the Secret Key is correct.)");
|
pam.print(R"(Ensure that the Secret Key is correct.)");
|
||||||
return AuthenticationStatus::Action::Denied;
|
return AuthenticationStatus::Action::Denied;
|
||||||
case rublon::WerificationError::SecurityKeyException:
|
case WerificationError::SecurityKeyException:
|
||||||
pam.print(R"(Ensure that the Secret Key is correct.)");
|
pam.print(R"(Ensure that the Secret Key is correct.)");
|
||||||
return AuthenticationStatus::Action::Denied;
|
return AuthenticationStatus::Action::Denied;
|
||||||
case rublon::WerificationError::TooManyRequestsException:
|
case WerificationError::TooManyRequestsException:
|
||||||
pam.print(R"(Too many attempts.)");
|
pam.print(R"(Too many attempts.)");
|
||||||
return AuthenticationStatus::Action::Denied;
|
return AuthenticationStatus::Action::Denied;
|
||||||
|
case WerificationError::SendPushException:
|
||||||
|
pam.print(R"(Rublon failed to reach authenticator app)");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +92,7 @@ class ErrorHandler {
|
|||||||
log(LogLevel::Error, R"(The provided version of the app is unsupported.)");
|
log(LogLevel::Error, R"(The provided version of the app is unsupported.)");
|
||||||
log(LogLevel::Error, R"(Try changing the app version.)");
|
log(LogLevel::Error, R"(Try changing the app version.)");
|
||||||
return AuthenticationStatus::Action::Denied;
|
return AuthenticationStatus::Action::Denied;
|
||||||
case rublon::RublonCheckApplicationException::MissingFieldException:
|
case RublonCheckApplicationException::MissingFieldException:
|
||||||
log(LogLevel::Error, R"(The provided version of the app is unsupported.)");
|
log(LogLevel::Error, R"(The provided version of the app is unsupported.)");
|
||||||
log(LogLevel::Error, R"(Try changing the app version.)");
|
log(LogLevel::Error, R"(Try changing the app version.)");
|
||||||
return AuthenticationStatus::Action::Denied;
|
return AuthenticationStatus::Action::Denied;
|
||||||
|
|||||||
@ -43,7 +43,8 @@ class Init : public AuthenticationStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addParams(Document & coreRequest, const Pam_t & pam) const {
|
void addParams(Document & coreRequest, const Pam_t & pam) const {
|
||||||
memory::MonotonicStackResource< 1024 > memoryResource;
|
using namespace memory::literals;
|
||||||
|
memory::MonotonicStackResource< 2_kB > memoryResource;
|
||||||
auto & alloc = coreRequest.GetAllocator();
|
auto & alloc = coreRequest.GetAllocator();
|
||||||
|
|
||||||
const auto os = details::osName(&memoryResource);
|
const auto os = details::osName(&memoryResource);
|
||||||
@ -69,7 +70,8 @@ class Init : public AuthenticationStep {
|
|||||||
|
|
||||||
tl::expected< std::reference_wrapper< const Document >, Error > checkEnrolement(const Document & coreResponse, const Pam_t pam) const {
|
tl::expected< std::reference_wrapper< const Document >, Error > checkEnrolement(const Document & coreResponse, const Pam_t pam) const {
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
memory::MonotonicStackResource< 256 > stackResource;
|
using namespace memory::literals;
|
||||||
|
memory::MonotonicStackResource< 1_kB > stackResource;
|
||||||
RapidJSONPMRAlloc alloc{&stackResource};
|
RapidJSONPMRAlloc alloc{&stackResource};
|
||||||
|
|
||||||
const auto * rublonStatus = JSONPointer{"/result/status", &alloc}.Get(coreResponse);
|
const auto * rublonStatus = JSONPointer{"/result/status", &alloc}.Get(coreResponse);
|
||||||
@ -96,7 +98,7 @@ class Init : public AuthenticationStep {
|
|||||||
const char * _name = "Initialization";
|
const char * _name = "Initialization";
|
||||||
|
|
||||||
Init(Session & session) : base_t(session) {
|
Init(Session & session) : base_t(session) {
|
||||||
log(LogLevel::Debug, "Init");
|
log(LogLevel::Debug, "Starting inicialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Hander_t >
|
template < typename Hander_t >
|
||||||
|
|||||||
@ -122,7 +122,7 @@ struct FileWriter {
|
|||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
static void stringifyTo(const Document & body, T & to) {
|
static void stringifyTo(const Document & body, T & to) {
|
||||||
memory::Monotonic_1k_HeapResource tmpResource;
|
memory::Monotonic_1k_Resource tmpResource;
|
||||||
RapidJSONPMRAlloc alloc{&tmpResource};
|
RapidJSONPMRAlloc alloc{&tmpResource};
|
||||||
StringWriter< T > s{to};
|
StringWriter< T > s{to};
|
||||||
rapidjson::Writer< StringWriter< T >, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc};
|
rapidjson::Writer< StringWriter< T >, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc};
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
namespace rublon {
|
namespace rublon {
|
||||||
namespace memory {
|
namespace memory {
|
||||||
|
|
||||||
namespace literals{
|
namespace literals{
|
||||||
constexpr std::uint64_t operator"" _kB(unsigned long long kilobytes) {
|
constexpr std::uint64_t operator"" _kB(unsigned long long kilobytes) {
|
||||||
return kilobytes * 1024ULL;
|
return kilobytes * 1024ULL;
|
||||||
@ -31,49 +30,32 @@ namespace memory {
|
|||||||
MonotonicStackResource() : std::pmr::monotonic_buffer_resource{_buffer, N, std::pmr::null_memory_resource()} {}
|
MonotonicStackResource() : std::pmr::monotonic_buffer_resource{_buffer, N, std::pmr::null_memory_resource()} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MonotonicHeapResourceBase {
|
class MonotonicResourceBase {
|
||||||
public:
|
public:
|
||||||
std::pmr::memory_resource * _upstream{};
|
std::pmr::memory_resource * _upstream{};
|
||||||
std::size_t _size{};
|
std::size_t _size{};
|
||||||
void * _buffer{nullptr};
|
void * _buffer{nullptr};
|
||||||
|
|
||||||
MonotonicHeapResourceBase(std::size_t size) : _upstream{default_resource()}, _size{size}, _buffer{_upstream->allocate(size)} {}
|
MonotonicResourceBase(std::size_t size) : _upstream{default_resource()}, _size{size}, _buffer{_upstream->allocate(size)} {}
|
||||||
|
|
||||||
~MonotonicHeapResourceBase() {
|
~MonotonicResourceBase() {
|
||||||
if(_buffer)
|
if(_buffer)
|
||||||
_upstream->deallocate(_buffer, _size);
|
_upstream->deallocate(_buffer, _size);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template < std::size_t N >
|
template < std::size_t N >
|
||||||
class MonotonicHeapResource : MonotonicHeapResourceBase, public std::pmr::monotonic_buffer_resource {
|
class MonotonicResource : MonotonicResourceBase, public std::pmr::monotonic_buffer_resource {
|
||||||
public:
|
public:
|
||||||
MonotonicHeapResource()
|
MonotonicResource()
|
||||||
: MonotonicHeapResourceBase{N}, std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, default_resource()} {}
|
: MonotonicResourceBase{N}, std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, default_resource()} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template < std::size_t N >
|
using Monotonic_1k_Resource = MonotonicResource< 1 * 1024 >;
|
||||||
class StrictMonotonicHeapResource : MonotonicHeapResourceBase, public std::pmr::monotonic_buffer_resource {
|
using Monotonic_2k_Resource = MonotonicResource< 2 * 1024 >;
|
||||||
public:
|
using Monotonic_4k_Resource = MonotonicResource< 4 * 1024 >;
|
||||||
StrictMonotonicHeapResource()
|
using Monotonic_8k_Resource = MonotonicResource< 8 * 1024 >;
|
||||||
: MonotonicHeapResourceBase{N},
|
using Monotonic_16k_Resource = MonotonicResource< 16 * 1024 >;
|
||||||
std::pmr::monotonic_buffer_resource{this->_buffer, this->_size, std::pmr::null_memory_resource()} {}
|
|
||||||
};
|
|
||||||
|
|
||||||
using StrictMonotonic_512_HeapResource = StrictMonotonicHeapResource< 512 >;
|
|
||||||
using StrictMonotonic_1k_HeapResource = StrictMonotonicHeapResource< 1 * 1024 >;
|
|
||||||
using StrictMonotonic_2k_HeapResource = StrictMonotonicHeapResource< 2 * 1024 >;
|
|
||||||
using StrictMonotonic_4k_HeapResource = StrictMonotonicHeapResource< 4 * 1024 >;
|
|
||||||
using StrictMonotonic_8k_HeapResource = StrictMonotonicHeapResource< 8 * 1024 >;
|
|
||||||
using StrictMonotonic_16k_HeapResource = StrictMonotonicHeapResource< 16 * 1024 >;
|
|
||||||
using StrictMonotonic_32k_HeapResource = StrictMonotonicHeapResource< 32 * 1024 >;
|
|
||||||
|
|
||||||
using Monotonic_1k_HeapResource = MonotonicHeapResource< 1 * 1024 >;
|
|
||||||
using Monotonic_2k_HeapResource = MonotonicHeapResource< 2 * 1024 >;
|
|
||||||
using Monotonic_4k_HeapResource = MonotonicHeapResource< 4 * 1024 >;
|
|
||||||
using Monotonic_8k_HeapResource = MonotonicHeapResource< 8 * 1024 >;
|
|
||||||
using Monotonic_16k_HeapResource = MonotonicHeapResource< 4 * 1024 >;
|
|
||||||
using Monotonic_32k_HeapResource = MonotonicHeapResource< 8 * 1024 >;
|
|
||||||
} // namespace memory
|
} // namespace memory
|
||||||
|
|
||||||
// class RublonMemory {
|
// class RublonMemory {
|
||||||
|
|||||||
@ -155,7 +155,7 @@ class MethodSelect {
|
|||||||
|
|
||||||
tl::expected< PostMethod, Error > create(Pam_t & pam) const {
|
tl::expected< PostMethod, Error > create(Pam_t & pam) const {
|
||||||
rublon::log(LogLevel::Debug, "prompting user to select method");
|
rublon::log(LogLevel::Debug, "prompting user to select method");
|
||||||
memory::StrictMonotonic_2k_HeapResource memoryResource;
|
memory::Monotonic_2k_Resource memoryResource;
|
||||||
|
|
||||||
std::pmr::map< int, MethodIds > methods_id{&memoryResource};
|
std::pmr::map< int, MethodIds > methods_id{&memoryResource};
|
||||||
std::pmr::map< int, std::pmr::string > methods_names{&memoryResource};
|
std::pmr::map< int, std::pmr::string > methods_names{&memoryResource};
|
||||||
|
|||||||
@ -12,8 +12,8 @@ namespace rublon::method {
|
|||||||
|
|
||||||
class PasscodeBasedAuth : public AuthenticationStep {
|
class PasscodeBasedAuth : public AuthenticationStep {
|
||||||
protected:
|
protected:
|
||||||
const char * uri;
|
const char * _uri;
|
||||||
const char * confirmField;
|
const char * _confirmField;
|
||||||
|
|
||||||
static constexpr const char * confirmCodeEndpoint = "/api/transaction/confirmCode";
|
static constexpr const char * confirmCodeEndpoint = "/api/transaction/confirmCode";
|
||||||
static constexpr const char * confirmSecuritySSHEndpoint = "/api/transaction/confirmSecurityKeySSH";
|
static constexpr const char * confirmSecuritySSHEndpoint = "/api/transaction/confirmSecurityKeySSH";
|
||||||
@ -23,10 +23,10 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
|
|
||||||
static constexpr auto _bypassCodeLength = 9;
|
static constexpr auto _bypassCodeLength = 9;
|
||||||
|
|
||||||
const char * userMessage{nullptr};
|
const char * _userMessage{nullptr};
|
||||||
|
|
||||||
const uint_fast8_t vericodeLength;
|
const uint_fast8_t _vericodeLength;
|
||||||
const bool onlyDigits;
|
const bool _onlyDigits;
|
||||||
int _prompts;
|
int _prompts;
|
||||||
|
|
||||||
constexpr static bool isdigit(char ch) {
|
constexpr static bool isdigit(char ch) {
|
||||||
@ -38,17 +38,17 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool hasValidLength(std::string_view userInput) const {
|
bool hasValidLength(std::string_view userInput) const {
|
||||||
if(userInput.size() == vericodeLength || userInput.size() == _bypassCodeLength) {
|
if(userInput.size() == _vericodeLength || userInput.size() == _bypassCodeLength) {
|
||||||
log(LogLevel::Debug, "User input size %d is correct", userInput.size());
|
log(LogLevel::Debug, "User input size %d is correct", userInput.size());
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log(LogLevel::Warning, "User input size %d is different than %d", userInput.size(), vericodeLength);
|
log(LogLevel::Warning, "User input size %d is different than %d", userInput.size(), _vericodeLength);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasValidCharacters(std::string_view userInput) const {
|
bool hasValidCharacters(std::string_view userInput) const {
|
||||||
if(onlyDigits ? digitsOnly(userInput) : true) {
|
if(_onlyDigits ? digitsOnly(userInput) : true) {
|
||||||
log(LogLevel::Debug, "User input contains valid characters");
|
log(LogLevel::Debug, "User input contains valid characters");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -60,10 +60,10 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
tl::expected< std::reference_wrapper< Document >, Error > readPasscode(Document & body, const Pam_t & pam) const {
|
tl::expected< std::reference_wrapper< Document >, Error > readPasscode(Document & body, const Pam_t & pam) const {
|
||||||
/// TODO assert in interactive mode
|
/// TODO assert in interactive mode
|
||||||
auto & alloc = body.GetAllocator();
|
auto & alloc = body.GetAllocator();
|
||||||
auto vericode = pam.scan([](const char * userInput) { return std::string{userInput}; }, userMessage);
|
auto vericode = pam.scan([](const char * userInput) { return std::string{userInput}; }, _userMessage);
|
||||||
|
|
||||||
if(hasValidLength(vericode) and hasValidCharacters(vericode)) {
|
if(hasValidLength(vericode) and hasValidCharacters(vericode)) {
|
||||||
Value confirmFieldValue(confirmField, alloc);
|
Value confirmFieldValue(_confirmField, alloc);
|
||||||
body.AddMember(confirmFieldValue, Value{vericode.c_str(), alloc}, alloc);
|
body.AddMember(confirmFieldValue, Value{vericode.c_str(), alloc}, alloc);
|
||||||
|
|
||||||
if(_session.hasAccessToken()) {
|
if(_session.hasAccessToken()) {
|
||||||
@ -80,7 +80,6 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
return AuthenticationStatus{AuthenticationStatus::Action::Confirmed};
|
return AuthenticationStatus{AuthenticationStatus::Action::Confirmed};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tl::expected< AuthenticationStatus, Error > errorHandler(Error error, const Pam_t & pam, int promptLeft) const {
|
tl::expected< AuthenticationStatus, Error > errorHandler(Error error, const Pam_t & pam, int promptLeft) const {
|
||||||
if(promptLeft && error.is< WerificationError >()) {
|
if(promptLeft && error.is< WerificationError >()) {
|
||||||
switch(error.get< WerificationError >().errorClass) {
|
switch(error.get< WerificationError >().errorClass) {
|
||||||
@ -96,6 +95,9 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
case WerificationError::TooManyRequestsException:
|
case WerificationError::TooManyRequestsException:
|
||||||
pam.print("Too Many Attempts. Try again after a minute");
|
pam.print("Too Many Attempts. Try again after a minute");
|
||||||
break;
|
break;
|
||||||
|
case WerificationError::SendPushException:
|
||||||
|
// if there is a communication problem we can't do anything here
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tl::unexpected{error};
|
return tl::unexpected{error};
|
||||||
@ -116,11 +118,11 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
Endpoint endpoint,
|
Endpoint endpoint,
|
||||||
int prompts)
|
int prompts)
|
||||||
: AuthenticationStep(session),
|
: AuthenticationStep(session),
|
||||||
uri{(endpoint == Endpoint::ConfirmCode) ? confirmCodeEndpoint : confirmSecuritySSHEndpoint},
|
_uri{(endpoint == Endpoint::ConfirmCode) ? confirmCodeEndpoint : confirmSecuritySSHEndpoint},
|
||||||
confirmField{(endpoint == Endpoint::ConfirmCode) ? fieldVericode : fieldOtp},
|
_confirmField{(endpoint == Endpoint::ConfirmCode) ? fieldVericode : fieldOtp},
|
||||||
userMessage{userMessage},
|
_userMessage{userMessage},
|
||||||
vericodeLength{length},
|
_vericodeLength{length},
|
||||||
onlyDigits{numbersOnly},
|
_onlyDigits{numbersOnly},
|
||||||
_prompts{prompts},
|
_prompts{prompts},
|
||||||
_name{_name} {}
|
_name{_name} {}
|
||||||
|
|
||||||
@ -130,7 +132,7 @@ class PasscodeBasedAuth : public AuthenticationStep {
|
|||||||
Document body{rapidjson::kObjectType, &alloc};
|
Document body{rapidjson::kObjectType, &alloc};
|
||||||
int prompts = _prompts;
|
int prompts = _prompts;
|
||||||
|
|
||||||
const auto requestAuthorization = [&](const auto & body) { return coreHandler.request(alloc, uri, body); };
|
const auto requestAuthorization = [&](const auto & body) { return coreHandler.request(alloc, _uri, body); };
|
||||||
const auto checkCodeValidity = [&](const auto & coreResponse) { return this->checkAuthenticationStatus(coreResponse, pam); };
|
const auto checkCodeValidity = [&](const auto & coreResponse) { return this->checkAuthenticationStatus(coreResponse, pam); };
|
||||||
const auto waitForCoreToConfirm = [&](const auto &) { return waitForCoreConfirmation(coreHandler); };
|
const auto waitForCoreToConfirm = [&](const auto &) { return waitForCoreConfirmation(coreHandler); };
|
||||||
const auto handleError = [&](const auto error) { return errorHandler(error, pam, prompts); };
|
const auto handleError = [&](const auto error) { return errorHandler(error, pam, prompts); };
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "rublon/memory.hpp"
|
||||||
#include <tl/expected.hpp>
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
#include <rublon/bits.hpp>
|
#include <rublon/bits.hpp>
|
||||||
@ -11,17 +12,18 @@ namespace rublon {
|
|||||||
|
|
||||||
class RublonFactory {
|
class RublonFactory {
|
||||||
public:
|
public:
|
||||||
tl::expected< Session, Error > startSession(const Pam_t & pam) {
|
tl::expected< void, Error > initializeSession(Session & session) {
|
||||||
details::initLog();
|
log(LogLevel::Debug, "Configuration read start");
|
||||||
|
memory::Monotonic_16k_Resource heap;
|
||||||
|
ConfigurationReader reader{&heap, "/etc/rublon.config"};
|
||||||
|
|
||||||
auto config = ConfigurationFactory{}.systemConfig();
|
if(auto ok = reader.applyTo(session.config()); not ok.has_value()) {
|
||||||
|
log(LogLevel::Warning, "Configuration contains errors");
|
||||||
if(not config.has_value()) {
|
session.pam().print("The configuration file does not exist or contains incorrect values");
|
||||||
pam.print("The configuration file does not exist or contains incorrect values");
|
|
||||||
return tl::unexpected{ConfigurationError{}};
|
return tl::unexpected{ConfigurationError{}};
|
||||||
}
|
}
|
||||||
|
log(LogLevel::Debug, "Configuration read success");
|
||||||
return Session{pam, config.value()};
|
return {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "rublon/utils.hpp"
|
#include <memory_resource>
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/document.h>
|
||||||
#include <rublon/bits.hpp>
|
#include <rublon/bits.hpp>
|
||||||
#include <rublon/configuration.hpp>
|
#include <rublon/configuration.hpp>
|
||||||
#include <rublon/json.hpp>
|
#include <rublon/json.hpp>
|
||||||
|
#include <rublon/utils.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
namespace rublon {
|
namespace rublon {
|
||||||
|
|
||||||
class Session {
|
class Session {
|
||||||
|
std::pmr::memory_resource * mr;
|
||||||
const Pam_t & _pam;
|
const Pam_t & _pam;
|
||||||
const Configuration _config;
|
Configuration _config;
|
||||||
|
|
||||||
std::pmr::string _tid;
|
std::pmr::string _tid;
|
||||||
std::pmr::string _accessToken;
|
std::pmr::string _accessToken;
|
||||||
|
|
||||||
CoreHandler_t _coreHandler;
|
CoreHandler_t _coreHandler;
|
||||||
/// TODO log
|
/// TODO log
|
||||||
/// TODO momory resource
|
|
||||||
public:
|
public:
|
||||||
Session(const Pam_t & pam, const Configuration & config)
|
Session(const Pam_t & pam)
|
||||||
: _pam{pam}, _config{config}, _coreHandler{_config} {
|
: mr{memory::default_resource()}, _pam{pam}, _config{mr}, _coreHandler{_config} {
|
||||||
log(LogLevel::Debug, __PRETTY_FUNCTION__);
|
details::initLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
Session(Session &&) noexcept = default;
|
Session(Session &&) noexcept = delete;
|
||||||
Session(const Session &) = delete;
|
Session(const Session &) = delete;
|
||||||
|
|
||||||
Session & operator=(Session &&) noexcept = delete;
|
Session & operator=(Session &&) noexcept = delete;
|
||||||
@ -38,6 +39,9 @@ class Session {
|
|||||||
const auto & pam() const {
|
const auto & pam() const {
|
||||||
return _pam;
|
return _pam;
|
||||||
}
|
}
|
||||||
|
auto & config() {
|
||||||
|
return _config;
|
||||||
|
}
|
||||||
const auto & config() const {
|
const auto & config() const {
|
||||||
return _config;
|
return _config;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -205,7 +205,7 @@ namespace details {
|
|||||||
|
|
||||||
template < typename Headers >
|
template < typename Headers >
|
||||||
inline void headers(std::string_view data, Headers & headers) {
|
inline void headers(std::string_view data, Headers & headers) {
|
||||||
memory::StrictMonotonic_4k_HeapResource stackResource;
|
memory::Monotonic_4k_Resource stackResource;
|
||||||
std::pmr::string tmp{&stackResource};
|
std::pmr::string tmp{&stackResource};
|
||||||
|
|
||||||
std::istringstream resp{};
|
std::istringstream resp{};
|
||||||
@ -223,7 +223,8 @@ namespace details {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::pmr::string hostname(std::pmr::memory_resource * mr) {
|
std::pmr::string hostname(std::pmr::memory_resource * mr) {
|
||||||
std::pmr::string hostname{2048, '\0', mr};
|
// longest hostname on linux is 253 characters
|
||||||
|
std::pmr::string hostname{255, '\0', mr};
|
||||||
if(gethostname(hostname.data(), hostname.size()) != 0) {
|
if(gethostname(hostname.data(), hostname.size()) != 0) {
|
||||||
log(LogLevel::Warning, "Hostname is not available");
|
log(LogLevel::Warning, "Hostname is not available");
|
||||||
return "";
|
return "";
|
||||||
@ -233,7 +234,7 @@ namespace details {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::pmr::string osName(std::pmr::memory_resource * mr) {
|
std::pmr::string osName(std::pmr::memory_resource * mr) {
|
||||||
memory::Monotonic_8k_HeapResource memoryResource;
|
memory::Monotonic_8k_Resource memoryResource;
|
||||||
|
|
||||||
std::ifstream file(std::filesystem::path{"/etc/os-release"});
|
std::ifstream file(std::filesystem::path{"/etc/os-release"});
|
||||||
if(not file.good())
|
if(not file.good())
|
||||||
|
|||||||
@ -78,7 +78,7 @@ class WebSocket {
|
|||||||
assert(cfg.proxyType.has_value());
|
assert(cfg.proxyType.has_value());
|
||||||
assert(cfg.proxyServer.has_value());
|
assert(cfg.proxyServer.has_value());
|
||||||
|
|
||||||
memory::Monotonic_8k_HeapResource memoryResource;
|
memory::Monotonic_8k_Resource memoryResource;
|
||||||
std::pmr::string proxyUrl{&memoryResource};
|
std::pmr::string proxyUrl{&memoryResource};
|
||||||
proxyUrl.reserve(conservative_estimate(cfg.proxyUsername, cfg.proxyPass, cfg.proxyServer, cfg.proxyPort) + 10);
|
proxyUrl.reserve(conservative_estimate(cfg.proxyUsername, cfg.proxyPass, cfg.proxyServer, cfg.proxyPort) + 10);
|
||||||
|
|
||||||
@ -251,7 +251,7 @@ class WebSocket {
|
|||||||
startPos = endPos + 2;
|
startPos = endPos + 2;
|
||||||
auto jsonString = input.substr(startPos, input.length() - startPos - 1);
|
auto jsonString = input.substr(startPos, input.length() - startPos - 1);
|
||||||
|
|
||||||
memory::Monotonic_1k_HeapResource mr;
|
memory::Monotonic_1k_Resource mr;
|
||||||
RapidJSONPMRAlloc alloc{&mr};
|
RapidJSONPMRAlloc alloc{&mr};
|
||||||
|
|
||||||
Document dataJson{&alloc};
|
Document dataJson{&alloc};
|
||||||
|
|||||||
@ -58,16 +58,17 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
|
|||||||
return PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto session = rublon::RublonFactory{}.startSession(pam);
|
Session session{pam};
|
||||||
if(not session.has_value()) {
|
auto ok = rublon::RublonFactory{}.initializeSession(session);
|
||||||
|
if(not ok.has_value()) {
|
||||||
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!session->config().logging) {
|
if(!session.config().logging) {
|
||||||
g_level = LogLevel::Warning;
|
g_level = LogLevel::Warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto & CH = session.value().coreHandler();
|
auto & CH = session.coreHandler();
|
||||||
|
|
||||||
auto selectMethod = [&](const MethodSelect & selector) { //
|
auto selectMethod = [&](const MethodSelect & selector) { //
|
||||||
return selector.create(pam);
|
return selector.create(pam);
|
||||||
@ -78,12 +79,12 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto confirmCode = [&](const MethodProxy & method) mutable { //
|
auto confirmCode = [&](const MethodProxy & method) mutable { //
|
||||||
return method.fire(session.value(), CH, pam);
|
return method.fire(session, CH, pam);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > {
|
auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > {
|
||||||
if(status.userAuthorized()) {
|
if(status.userAuthorized()) {
|
||||||
Finish{session.value(), status.accessToken()}.handle(CH);
|
Finish{session, status.accessToken()}.handle(CH);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
};
|
};
|
||||||
@ -93,12 +94,12 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto mapError = [&](const Error & error) -> tl::expected< int, Error > {
|
auto mapError = [&](const Error & error) -> tl::expected< int, Error > {
|
||||||
return printAuthMessageAndExit(rublon::ErrorHandler{pam, session->config()}.printErrorDetails(error));
|
return printAuthMessageAndExit(rublon::ErrorHandler{pam, session.config()}.printErrorDetails(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
CheckApplication ca;
|
CheckApplication ca;
|
||||||
const auto & config = session.value().config();
|
const auto & config = session.config();
|
||||||
const auto ret = ca.call(CH, config.systemToken).or_else(mapError);
|
const auto ret = ca.call(CH, config.systemToken).or_else(mapError);
|
||||||
if(not ret.has_value()) {
|
if(not ret.has_value()) {
|
||||||
log(LogLevel::Error, "Check Application step failed, check configration");
|
log(LogLevel::Error, "Check Application step failed, check configration");
|
||||||
@ -106,7 +107,7 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = Init{session.value()}
|
auto ret = Init{session}
|
||||||
.handle(CH, pam) //
|
.handle(CH, pam) //
|
||||||
.and_then(selectMethod)
|
.and_then(selectMethod)
|
||||||
.and_then(confirmMethod)
|
.and_then(confirmMethod)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user