fix build on debian

This commit is contained in:
Bartosz Wieczorek 2023-07-24 13:25:48 +02:00
parent c052281006
commit e9f612753b
7 changed files with 100 additions and 50 deletions

View File

@ -3,6 +3,9 @@ include_directories(extern/rapidjson/include)
add_library(rublon-ssh
INTERFACE
)
add_library(rublon-ssh_ide INTERFACE
./include/rublon/authentication_step_interface.hpp
./include/rublon/configuration.hpp
./include/rublon/core_handler.hpp
@ -18,16 +21,13 @@ add_library(rublon-ssh
./include/rublon/rublon.hpp
./include/rublon/sign.hpp
./include/rublon/span.hpp
./include/rublon/utils.hpp
)
./include/rublon/utils.hpp)
target_include_directories(rublon-ssh
PUBLIC INTERFACE
INTERFACE
extern
${CMAKE_CURRENT_LIST_DIR}/include
)
add_subdirectory(lib)
add_subdirectory(tests)

View File

@ -48,11 +48,9 @@ class Init : public AuthenticationStep< Init< MethodFactory_t, PamInfo_t > > {
if(httpResponse.has_value()) {
log(LogLevel::Info, "[TMP] has response, processing", __PRETTY_FUNCTION__);
const auto & rublonResponse = httpResponse.value()["response"];
const auto & rublonResponse = httpResponse.value()["result"];
std::string tid = rublonResponse["tid"].GetString();
return _methodFactory.create(rublonResponse["methods"].GetArray());
return _methodFactory.create(rublonResponse["methods"].GetArray(), std::move(tid));
} else {
// mostly connectio errors
switch(httpResponse.error().errorClass) {

View File

@ -5,25 +5,25 @@
#include <variant>
#include <rublon/core_handler.hpp>
#include <rublon/pam_action.hpp>
#include <rublon/pam.hpp>
#include <rublon/pam_action.hpp>
#include <rublon/method/OTP.hpp>
#include <rublon/method/SMS.hpp>
namespace rublon{
namespace rublon {
class Method {
std::string tid;
public:
Method() {}
template < typename Handler_t >
tl::expected< int , PamAction > fire(const CoreHandlerInterface< Handler_t > & coreHandler) {
tl::expected< int, PamAction > fire(const CoreHandlerInterface< Handler_t > & coreHandler) {
return std::visit([&](const auto & method) { return method.fire(coreHandler); }, _impl);
}
private:
std::variant< method::OTP, method::SMS > _impl;
};
@ -31,16 +31,17 @@ class Method {
template < typename Pam_t = LinuxPam >
class MethodFactory {
const Pam_t & pam;
public:
MethodFactory(const Pam_t & pam) : pam{pam} {}
template < typename Array_t >
tl::expected< Method, PamAction > create(const Array_t & methods) const {
tl::expected< Method, PamAction > create(const Array_t & methods, const std::string & tid) const {
std::pmr::map< int, std::pmr::string > methods_id;
pam.print("%s", "");
int i;
for(const auto & method : methods) {
rublon::log(LogLevel::Debug, "method %s found at pos %d", method.GetString(), i);
if(method == "email") {
pam.print("%d: Email Link", i + 1);
methods_id[++i] = "email";
@ -62,15 +63,20 @@ class MethodFactory {
methods_id[++i] = "sms";
}
}
auto methodid = pam.scan([](char * userinput) { return std::stoi(userinput); }, "\nSelect method [1-%d]: ", methods.Size());
pam.print("you selected: %s", methods_id.count(methodid.value_or(0)) ? methods_id.at(methodid.value_or(0)).c_str() : "unknown option");
auto methodid = pam.scan(
[](char * userinput) {
rublon::log(LogLevel::Debug, "User input: %s", userinput);
return std::stoi(userinput);
},
"\nSelect method [1-%d]: ",
methods.Size());
pam.print(
"you selected: %s", methods_id.count(methodid.value_or(0)) ? methods_id.at(methodid.value_or(0)).c_str() : "unknown option");
return tl::unexpected{PamAction::accept};
}
};
}
} // namespace rublon

View File

@ -30,7 +30,7 @@ inline auto dateStr() {
constexpr const char* LogLevelNames[] {"Debug", "Info", "Warning", "Error"};
static LogLevel g_level = Debug;
constexpr LogLevel g_level = Debug;
namespace details{
static void doLog(LogLevel level, const char * line) noexcept {

View File

@ -55,32 +55,45 @@ class CoreResponseGenerator {
std::array< char, 2048 > _buf;
io::sprintf(_buf.data(),
generateBrokenData ? result_broken_template : result_ok_template,
tid,
_tid,
status,
companyName,
applicationName,
print_methods());
return _buf.data();
}
CoreResponseGenerator & methods(std::initializer_list< std::string > newMethods) {
_methods.clear();
std::copy(newMethods.begin(), newMethods.end(), std::inserter(_methods, _methods.begin()));
return *this;
}
CoreResponseGenerator & tid(std::string tid) {
_tid = tid;
return *this;
}
std::string _tid{generateTid()};
std::string status;
std::string companyName{"rublon"};
std::string applicationName{"test_app"};
std::set< std::string > _methods{"email", "totp", "qrcode", "push"};
bool skipSignatureGeneration{false};
bool generateBrokenData{false};
private:
std::string print_methods() {
std::string ret;
for(const auto & m : methods)
for(const auto & m : _methods)
ret += "\"" + m + "\",";
ret.pop_back();
return ret;
}
static std::string generateTid() {
return gen_random(32);
}
std::string tid{generateTid()};
std::string status;
std::string companyName{"rublon"};
std::string applicationName{"test_app"};
std::set< std::string > methods{"email", "totp", "qrcode", "push"};
bool skipSignatureGeneration{false};
bool generateBrokenData{false};
};

View File

@ -9,6 +9,7 @@
#include <rublon/configuration.hpp>
#include "core_response_generator.hpp"
#include "rublon/sign.hpp"
namespace {
rublon::Configuration conf{rublon::Configuration::Parameters{//
@ -21,7 +22,7 @@ rublon::Configuration conf{rublon::Configuration::Parameters{//
false}};
} // namespace
class HttpHandlerMock {
class HttpHandlerMock : public CoreResponseGenerator{
auto signResponse(rublon::Response & res) {
const auto & sign =
skipSignatureGeneration ? std::array< char, 64 >{} : rublon::signData(res.body, conf.parameters.secretKey.c_str());
@ -32,12 +33,12 @@ class HttpHandlerMock {
MOCK_METHOD(std::optional< rublon::Response >, request, ( std::string_view, const rublon::Request & ), (const));
HttpHandlerMock & statusPending() {
gen.status = "pending";
status = "pending";
return *this;
}
HttpHandlerMock & brokenBody() {
gen.generateBrokenData = true;
generateBrokenData = true;
return *this;
}
@ -48,7 +49,7 @@ class HttpHandlerMock {
operator rublon::Response() {
rublon::Response res;
res.body = gen.generateBody();
res.body = generateBody();
signResponse(res);
@ -56,5 +57,4 @@ class HttpHandlerMock {
}
bool skipSignatureGeneration;
CoreResponseGenerator gen;
};

View File

@ -27,6 +27,16 @@ class CoreHandlerMock : public CoreHandlerInterface< CoreHandlerMock > {
gen.generateBrokenData = true;
return *this;
}
CoreHandlerMock & methods(std::initializer_list<std::string> methods) {
gen.methods(methods);
return *this;
}
CoreHandlerMock & tid(std::string tid) {
gen.tid(tid);
return *this;
}
operator tl::expected< Document, CoreHandlerError >() {
auto body = gen.generateBody();
@ -37,6 +47,10 @@ class CoreHandlerMock : public CoreHandlerInterface< CoreHandlerMock > {
return doc;
}
auto create() {
return static_cast< tl::expected< Document, CoreHandlerError > >(*this);
}
CoreResponseGenerator gen;
};
@ -50,9 +64,21 @@ class PamInfoMock {
template < typename Pam >
class MethodFactoryMock {
public:
using MethodFactoryCreate_t = tl::expected< Method, PamAction >;
MethodFactoryMock(const Pam &) {}
MOCK_METHOD(MethodFactoryCreate_t, create_mocked, (std::vector< std::string > methods, std::string tid), (const));
template < typename Array_t >
tl::expected< Method, PamAction > create(const Array_t & methods) const {}
MethodFactoryCreate_t create(const Array_t & methods, const std::string & tid) const {
std::vector< std::string > _methods;
std::transform(std::begin(methods), std::end(methods), std::back_inserter(_methods), [](const auto & el) {
return std::string{el.GetString()};
});
return create_mocked(_methods, tid);
}
};
class InitTestable : public Init< MethodFactoryMock, PamInfoMock > {
@ -61,6 +87,9 @@ class InitTestable : public Init< MethodFactoryMock, PamInfoMock > {
PamInfoMock & pam() {
return _pamInfo;
}
MethodFactoryMock<PamInfoMock> & methodFactory(){
return _methodFactory;
}
};
class RublonHttpInitTest : public testing::Test {
@ -69,17 +98,20 @@ class RublonHttpInitTest : public testing::Test {
EXPECT_CALL(pam, ip()).WillOnce(Return("192.168.0.1"));
EXPECT_CALL(pam, username()).WillOnce(Return("bwi"));
}
RublonHttpInitTest() : coreHandler{}, sut{conf}, pam{sut.pam()}, methodFactoryMock{sut.methodFactory()} {
expectDefaultPamInfo();
}
RublonHttpInitTest() : coreHandler{}, sut{conf}, pam{sut.pam()} {}
CoreHandlerMock coreHandler;
InitTestable sut{conf};
PamInfoMock & pam;
MethodFactoryMock<PamInfoMock> &methodFactoryMock;
};
using CoreReturn = tl::expected< Document, CoreHandlerError >;
TEST_F(RublonHttpInitTest, initializationSendsRequestOnGoodPath) {
expectDefaultPamInfo();
EXPECT_CALL(coreHandler, request("/api/transaction/init", _))
.WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::BadSigature}}));
sut.handle(coreHandler);
@ -90,26 +122,27 @@ MATCHER_P(HoldsPamAction, action, "") {
}
TEST_F(RublonHttpInitTest, rublon_Accept_pamLoginWhenThereIsNoConnection) {
expectDefaultPamInfo();
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::ConnectionError}}));
EXPECT_THAT(sut.handle(coreHandler), HoldsPamAction(PamAction::decline));
}
TEST_F(RublonHttpInitTest, rublon_Decline_pamLoginWhenServerHasBadSignature) {
expectDefaultPamInfo();
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::BadSigature}}));
EXPECT_THAT(sut.handle(coreHandler), HoldsPamAction(PamAction::decline));
}
TEST_F(RublonHttpInitTest, rublon_Decline_pamLoginWhenServerReturnsBrokenData) {
expectDefaultPamInfo();
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::BrokenData}}));
EXPECT_THAT(sut.handle(coreHandler), HoldsPamAction(PamAction::decline));
}
TEST_F(RublonHttpInitTest, rublon_Decline_pamLoginWhenServerReturnsCoreException) {
expectDefaultPamInfo();
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::CoreException}}));
EXPECT_THAT(sut.handle(coreHandler), HoldsPamAction(PamAction::decline));
}
TEST_F(RublonHttpInitTest, AllNeededInformationNeedsToBePassedToMethodFactory) {
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(coreHandler.statusPending().methods({"sms", "otp"}).tid("transaction ID").create()));
EXPECT_CALL(methodFactoryMock, create_mocked(_,"transaction ID") );
sut.handle(coreHandler);
}