Add a proxy fallback, and read proxy from env
This commit is contained in:
parent
4d456c56a8
commit
5d163800c3
@ -1,4 +1,3 @@
|
|||||||
#include "rublon/bits.hpp"
|
|
||||||
#include <security/pam_appl.h>
|
#include <security/pam_appl.h>
|
||||||
#include <security/pam_client.h>
|
#include <security/pam_client.h>
|
||||||
#include <security/pam_ext.h>
|
#include <security/pam_ext.h>
|
||||||
@ -6,6 +5,7 @@
|
|||||||
#include <security/pam_modules.h>
|
#include <security/pam_modules.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include <rublon/bits.hpp>
|
||||||
#include <rublon/check_application.hpp>
|
#include <rublon/check_application.hpp>
|
||||||
#include <rublon/error.hpp>
|
#include <rublon/error.hpp>
|
||||||
#include <rublon/error_handler.hpp>
|
#include <rublon/error_handler.hpp>
|
||||||
@ -17,50 +17,50 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
using namespace rublon;
|
using namespace rublon;
|
||||||
details::initLog();
|
details::initLog();
|
||||||
PamStub pam{};
|
PamStub pam{};
|
||||||
|
|
||||||
auto printAuthMessageAndExit = [&](const AuthenticationStatus status) {
|
auto printAuthMessageAndExit = [&](const AuthenticationStatus status) {
|
||||||
switch(status.action()) {
|
switch(status.action()) {
|
||||||
case AuthenticationStatus::Action::Bypass:
|
case AuthenticationStatus::Action::Bypass:
|
||||||
pam.print("RUBLON authentication BYPASSED");
|
pam.print("RUBLON authentication BYPASSED");
|
||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
|
|
||||||
case AuthenticationStatus::Action::Denied:
|
case AuthenticationStatus::Action::Denied:
|
||||||
pam.print("RUBLON authentication FAILED");
|
pam.print("RUBLON authentication FAILED");
|
||||||
return PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
|
|
||||||
case AuthenticationStatus::Action::Confirmed:
|
case AuthenticationStatus::Action::Confirmed:
|
||||||
pam.print("RUBLON authentication SUCCEEDED");
|
pam.print("RUBLON authentication SUCCEEDED");
|
||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pam.print("RUBLON connector has exited with unknown code, access DENY!\n");
|
pam.print("RUBLON connector has exited with unknown code, access DENY!\n");
|
||||||
return PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
};
|
};
|
||||||
|
|
||||||
Session session{pam};
|
Session session{pam};
|
||||||
auto ok = rublon::RublonFactory{}.initializeSession(session);
|
auto ok = rublon::RublonFactory{}.initializeSession(session);
|
||||||
if(not ok.has_value()) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreHandler_t CH{session.config()};
|
CoreHandler_t CH{session.config()};
|
||||||
|
|
||||||
auto selectMethod = [&](const MethodSelect & selector) { //
|
auto selectMethod = [&](const MethodSelect & selector) { //
|
||||||
return selector.create(pam);
|
return selector.create(pam);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto confirmMethod = [&](const PostMethod & postMethod) { //
|
auto confirmMethod = [&](const PostMethod & postMethod) { //
|
||||||
return postMethod.handle(CH);
|
return postMethod.handle(CH);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto confirmCode = [&](const MethodProxy & method) mutable { //
|
auto confirmCode = [&](const MethodProxy & method) mutable { //
|
||||||
return method.fire(session, 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 finish{session, status.accessToken()};
|
Finish finish{session, status.accessToken()};
|
||||||
@ -68,15 +68,15 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto allowLogin = [&](const AuthenticationStatus & status) -> tl::expected< int, Error > { //
|
auto allowLogin = [&](const AuthenticationStatus & status) -> tl::expected< int, Error > { //
|
||||||
return printAuthMessageAndExit(status);
|
return printAuthMessageAndExit(status);
|
||||||
};
|
};
|
||||||
|
|
||||||
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 = ca.call(CH, session.config().systemToken).or_else(mapError);
|
auto ret = ca.call(CH, session.config().systemToken).or_else(mapError);
|
||||||
@ -85,7 +85,7 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
return PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = Init{session}
|
auto ret = Init{session}
|
||||||
.handle(CH, pam) //
|
.handle(CH, pam) //
|
||||||
.and_then(selectMethod)
|
.and_then(selectMethod)
|
||||||
@ -94,6 +94,6 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|||||||
.and_then(finalizeTransaction)
|
.and_then(finalizeTransaction)
|
||||||
.and_then(allowLogin)
|
.and_then(allowLogin)
|
||||||
.or_else(mapError);
|
.or_else(mapError);
|
||||||
|
|
||||||
return ret.value_or(PAM_MAXTRIES);
|
return ret.value_or(PAM_MAXTRIES);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "tl/expected.hpp"
|
||||||
#include <rublon/error.hpp>
|
#include <rublon/error.hpp>
|
||||||
#include <rublon/memory.hpp>
|
#include <rublon/memory.hpp>
|
||||||
#include <rublon/static_string.hpp>
|
#include <rublon/static_string.hpp>
|
||||||
@ -60,7 +61,7 @@ class ConfigurationReader {
|
|||||||
memory::MonotonicStack_1k_Resource memoryResource;
|
memory::MonotonicStack_1k_Resource memoryResource;
|
||||||
std::ifstream file(filepath.data());
|
std::ifstream file(filepath.data());
|
||||||
if(not file.good())
|
if(not file.good())
|
||||||
return ;
|
return;
|
||||||
|
|
||||||
std::pmr::string line{&memoryResource};
|
std::pmr::string line{&memoryResource};
|
||||||
line.reserve(300);
|
line.reserve(300);
|
||||||
@ -74,7 +75,7 @@ class ConfigurationReader {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto posEqual = line.find('=');
|
auto posEqual = line.find('=');
|
||||||
std::pmr::string key {line.substr(0, posEqual),&memoryResource};
|
std::pmr::string key{line.substr(0, posEqual), &memoryResource};
|
||||||
std::pmr::string value{line.substr(posEqual + 1), &memoryResource};
|
std::pmr::string value{line.substr(posEqual + 1), &memoryResource};
|
||||||
|
|
||||||
keyValues[std::move(key)] = std::move(value);
|
keyValues[std::move(key)] = std::move(value);
|
||||||
@ -147,6 +148,64 @@ class ConfigurationReader {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto parseProxyURL = [&](const char * envValue) -> bool {
|
||||||
|
// Very simple parser: scheme://[user[:pass]@]host[:port]
|
||||||
|
std::string_view url = envValue;
|
||||||
|
|
||||||
|
std::string_view scheme{};
|
||||||
|
std::string_view auth{};
|
||||||
|
std::string_view hostport{};
|
||||||
|
|
||||||
|
auto scheme_pos = url.find("://");
|
||||||
|
if(scheme_pos != std::string_view::npos) {
|
||||||
|
scheme = url.substr(0, scheme_pos);
|
||||||
|
url = url.substr(scheme_pos + 3);
|
||||||
|
} else {
|
||||||
|
scheme = "http"; // default
|
||||||
|
}
|
||||||
|
|
||||||
|
auto at_pos = url.find('@');
|
||||||
|
if(at_pos != std::string_view::npos) {
|
||||||
|
auth = url.substr(0, at_pos);
|
||||||
|
hostport = url.substr(at_pos + 1);
|
||||||
|
} else {
|
||||||
|
hostport = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view host = hostport;
|
||||||
|
std::string_view port_str{};
|
||||||
|
auto colon_pos = hostport.rfind(':');
|
||||||
|
if(colon_pos != std::string_view::npos && colon_pos < hostport.size() - 1) {
|
||||||
|
host = hostport.substr(0, colon_pos);
|
||||||
|
port_str = hostport.substr(colon_pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.proxyEnabled = true;
|
||||||
|
config.proxyType = scheme;
|
||||||
|
config.proxyServer = host;
|
||||||
|
|
||||||
|
if(!port_str.empty()) {
|
||||||
|
config.proxyPort = conv::to_uint32opt(port_str);
|
||||||
|
if(not config.proxyPort) {
|
||||||
|
log(LogLevel::Error, "Invalid proxy port in environment variable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!auth.empty()) {
|
||||||
|
auto colon = auth.find(':');
|
||||||
|
if(colon != std::string_view::npos) {
|
||||||
|
config.proxyUsername = auth.substr(0, colon);
|
||||||
|
config.proxyPass = auth.substr(colon + 1);
|
||||||
|
} else {
|
||||||
|
config.proxyUsername = auth;
|
||||||
|
}
|
||||||
|
config.proxyAuthRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/// NOTE:
|
/// NOTE:
|
||||||
// getStringOpt can return a valid empty string, for example configuration entry like
|
// getStringOpt can return a valid empty string, for example configuration entry like
|
||||||
// option=
|
// option=
|
||||||
@ -183,6 +242,22 @@ class ConfigurationReader {
|
|||||||
config.proxyEnabled = getBool("proxyEnabled").value_or(false);
|
config.proxyEnabled = getBool("proxyEnabled").value_or(false);
|
||||||
config.proxyType = getStringOpt("proxyType");
|
config.proxyType = getStringOpt("proxyType");
|
||||||
config.proxyServer = getStringOpt("proxyServer");
|
config.proxyServer = getStringOpt("proxyServer");
|
||||||
|
|
||||||
|
|
||||||
|
// Apply fallback if no config is set
|
||||||
|
if (config.proxyEnabled && (!config.proxyType || config.proxyType->empty()) && (!config.proxyServer || config.proxyServer->empty())) {
|
||||||
|
log(LogLevel::Info, "Proxy is enabled but no configuration for it is provided, trying to read from env");
|
||||||
|
if (const char* https_proxy = std::getenv("https_proxy"); https_proxy && *https_proxy) {
|
||||||
|
if (parseProxyURL(https_proxy)) {
|
||||||
|
log(LogLevel::Info, "Loaded proxy config from HTTPS_PROXY");
|
||||||
|
}
|
||||||
|
} else if (const char* http_proxy = std::getenv("http_proxy"); http_proxy && *http_proxy) {
|
||||||
|
if (parseProxyURL(http_proxy)) {
|
||||||
|
log(LogLevel::Info, "Loaded proxy config from HTTP_PROXY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(config.proxyEnabled) {
|
if(config.proxyEnabled) {
|
||||||
if(not config.proxyType or config.proxyType->empty()) {
|
if(not config.proxyType or config.proxyType->empty()) {
|
||||||
log(LogLevel::Error, "Proxy is enabled but proxy type is not present or empty");
|
log(LogLevel::Error, "Proxy is enabled but proxy type is not present or empty");
|
||||||
|
|||||||
@ -99,7 +99,7 @@ class CURL {
|
|||||||
proxyUrl = *conf().proxyType;
|
proxyUrl = *conf().proxyType;
|
||||||
proxyUrl += "://";
|
proxyUrl += "://";
|
||||||
proxyUrl += *conf().proxyServer;
|
proxyUrl += *conf().proxyServer;
|
||||||
if(conf().proxyPort > 0) {
|
if(conf().proxyPort.value_or(0) > 0) {
|
||||||
proxyUrl += ":";
|
proxyUrl += ":";
|
||||||
proxyUrl += std::to_string(*conf().proxyPort);
|
proxyUrl += std::to_string(*conf().proxyPort);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <charconv>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <rublon/memory.hpp>
|
#include <rublon/memory.hpp>
|
||||||
#include <rublon/static_string.hpp>
|
#include <rublon/static_string.hpp>
|
||||||
@ -149,23 +150,23 @@ namespace conv {
|
|||||||
std::transform(userinput.cbegin(), userinput.cend(), buf.data(), asciitolower);
|
std::transform(userinput.cbegin(), userinput.cend(), buf.data(), asciitolower);
|
||||||
return strcmp(buf.data(), "true") == 0;
|
return strcmp(buf.data(), "true") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline tl::expected< std::uint32_t, Error > to_uint32(std::string_view userinput) noexcept {
|
|
||||||
try {
|
|
||||||
return std::stoi(userinput.data());
|
|
||||||
} catch(const std::invalid_argument & e) {
|
|
||||||
return tl::make_unexpected(Error::NotANumber);
|
|
||||||
} catch(const std::out_of_range & e) {
|
|
||||||
return tl::make_unexpected(Error::OutOfRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::optional< std::uint32_t> to_uint32opt(std::string_view userinput) noexcept {
|
inline std::optional< std::uint32_t> to_uint32opt(std::string_view userinput) noexcept {
|
||||||
try {
|
int out;
|
||||||
return std::stoi(userinput.data());
|
const std::from_chars_result result = std::from_chars(userinput.data(), userinput.data() + userinput.size(), out);
|
||||||
} catch(...) {
|
if(result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline tl::expected< std::uint32_t, Error > to_uint32(std::string_view userinput) noexcept {
|
||||||
|
int out;
|
||||||
|
const std::from_chars_result result = std::from_chars(userinput.data(), userinput.data() + userinput.size(), out);
|
||||||
|
if(result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range) {
|
||||||
|
return tl::make_unexpected(Error::NotANumber);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
} // namespace conv
|
} // namespace conv
|
||||||
|
|
||||||
|
|||||||
@ -93,7 +93,7 @@ class WebSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proxyUrl += *cfg.proxyServer;
|
proxyUrl += *cfg.proxyServer;
|
||||||
if(cfg.proxyPort > 0) {
|
if(cfg.proxyPort.value_or(0) > 0) {
|
||||||
proxyUrl += ":";
|
proxyUrl += ":";
|
||||||
proxyUrl += std::to_string(*cfg.proxyPort);
|
proxyUrl += std::to_string(*cfg.proxyPort);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user