Fail when user gives wrong code
This commit is contained in:
parent
056b99f526
commit
c47e03f991
@ -14,8 +14,8 @@ set(CMAKE_CXX_EXTENSIONS NO)
|
||||
|
||||
add_compile_options(-Wall -Wextra -Wpedantic -Wno-format-security)
|
||||
|
||||
#add_compile_options(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer)
|
||||
#add_link_options(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer)
|
||||
add_compile_options(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer)
|
||||
add_link_options(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -fno-omit-frame-pointer)
|
||||
|
||||
option(ENABLE_TESTS "Enable tests" OFF)
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ class AuthenticationStep {
|
||||
log(LogLevel::Error, "Socker error, forcing override");
|
||||
return Error{PamBaypass{}};
|
||||
case Error::k_CoreHandlerError:
|
||||
return Error{PamBaypass{}};
|
||||
return Error{PamDeny{}};
|
||||
default:
|
||||
Critical{};
|
||||
}
|
||||
|
||||
@ -67,13 +67,14 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > {
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
tl::unexpected< Error > handleCoreException(std::string_view exceptionString) const {
|
||||
if(exceptionString == "UserBypassedException" or exceptionString == "UserNotFoundException")
|
||||
if(exceptionString == "UserBypassedException" or exceptionString == "UserNotFoundException") {
|
||||
return tl::unexpected{Error{PamBaypass{}}};
|
||||
else
|
||||
} else {
|
||||
return tl::unexpected{
|
||||
Error{CoreHandlerError{CoreHandlerError::CoreException, std::string{exceptionString.data(), exceptionString.size()}}}};
|
||||
}
|
||||
}
|
||||
|
||||
tl::unexpected< Error > handleHttpError() const {
|
||||
|
||||
@ -49,8 +49,8 @@ class Init : public AuthenticationStep< Init< MethodSelect_t > > {
|
||||
Value params{rapidjson::kObjectType};
|
||||
|
||||
params.AddMember("userIP", Value{pam.ip().get(), alloc}, alloc);
|
||||
params.AddMember("appVer", "v.0.0.1", alloc); /// TODO add version to cmake
|
||||
params.AddMember("os", Value{osNameImpl().c_str(), alloc}, alloc); /// TODO add version to cmake
|
||||
params.AddMember("appVer", "v.0.0.1", alloc); /// TODO add version to cmake
|
||||
params.AddMember("os", Value{osNameImpl().c_str(), alloc}, alloc);
|
||||
|
||||
coreRequest.AddMember("params", std::move(params), alloc);
|
||||
}
|
||||
|
||||
@ -27,13 +27,13 @@ class PasscodeBasedAuth : public AuthenticationStep< PasscodeBasedAuth > {
|
||||
|
||||
template < typename PamInfo_t = LinuxPam >
|
||||
tl::expected< std::reference_wrapper< Document >, Error > readPasscode(Document & body, const PamInfo_t & pam) const {
|
||||
auto & alloc = body.GetAllocator();
|
||||
auto & alloc = body.GetAllocator();
|
||||
auto vericode = pam.scan([](const char * userInput) { return std::string{userInput}; }, userMessage);
|
||||
|
||||
if(isProperLength(vericode) and hasDigitsOnly(vericode)) {
|
||||
body.AddMember("vericode", Value{vericode.c_str(), alloc}, alloc);
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
return tl::unexpected{Error{WerificationError{WerificationError::WrongCode}}};
|
||||
}
|
||||
@ -44,14 +44,17 @@ class PasscodeBasedAuth : public AuthenticationStep< PasscodeBasedAuth > {
|
||||
return readPasscode(body, pam);
|
||||
}
|
||||
|
||||
tl::expected< AuthenticationStatus, Error > checkAuthenticationStatus(const Document & coreResponse) const {
|
||||
template < typename PamInfo_t = LinuxPam >
|
||||
tl::expected< AuthenticationStatus, Error > checkAuthenticationStatus(const Document & coreResponse, const PamInfo_t & pam) const {
|
||||
RapidJSONPMRStackAlloc< 1024 > alloc;
|
||||
auto error = JSONPointer{"/result/error", &alloc}.Get(coreResponse);
|
||||
|
||||
if(error) {
|
||||
pam.print("Wrong code");
|
||||
return tl::unexpected{Error{WerificationError{WerificationError::WrongCode}}};
|
||||
}
|
||||
|
||||
|
||||
pam.print("Verification code validated");
|
||||
return AuthenticationStatus{AuthenticationStatus::Action::Confirmed};
|
||||
}
|
||||
|
||||
@ -66,9 +69,9 @@ class PasscodeBasedAuth : public AuthenticationStep< PasscodeBasedAuth > {
|
||||
RapidJSONPMRStackAlloc< 1024 > alloc{};
|
||||
Document body{rapidjson::kObjectType, &alloc};
|
||||
|
||||
const auto checkAuthenticationStatus = [this](const auto & coreResponse) { return this->checkAuthenticationStatus(coreResponse); };
|
||||
const auto requestAuthorization = [&](const auto & body) { return coreHandler.request(alloc, uri, body); };
|
||||
const auto askForPasscodeAgain = [&](const auto & /*error*/) { return this->askForPasscodeAgain(body, pam); };
|
||||
const auto checkCodeValidity = [&](const auto & coreResponse) { return this->checkAuthenticationStatus(coreResponse, pam); };
|
||||
const auto requestAuthorization = [&](const auto & body) { return coreHandler.request(alloc, uri, body); };
|
||||
const auto askForPasscodeAgain = [&](const auto & /*error*/) { return this->askForPasscodeAgain(body, pam); };
|
||||
|
||||
this->addSystemToken(body);
|
||||
this->addTid(body);
|
||||
@ -76,7 +79,7 @@ class PasscodeBasedAuth : public AuthenticationStep< PasscodeBasedAuth > {
|
||||
return readPasscode(body, pam) //
|
||||
.or_else(askForPasscodeAgain)
|
||||
.and_then(requestAuthorization)
|
||||
.and_then(checkAuthenticationStatus);
|
||||
.and_then(checkCodeValidity);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -48,33 +48,42 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
|
||||
|
||||
CoreHandler CH{rublonConfig.value()};
|
||||
|
||||
auto selectMethod = [&](const MethodSelect & selector) {
|
||||
rublon::log(LogLevel::Debug, "seelctor.create()");
|
||||
return selector.create(pam);
|
||||
};
|
||||
auto selectMethod = [&](const MethodSelect & selector) { return selector.create(pam); };
|
||||
auto confirmMethod = [&](const PostMethod & confirm) { return confirm.fire(CH); };
|
||||
auto verifi = [&](const MethodProxy & method) { return method.fire(CH, pam); };
|
||||
auto confirmCode = [&](const MethodProxy & method) { return method.fire(CH, pam); };
|
||||
|
||||
auto authStatus = Init{rublonConfig.value()}
|
||||
.fire(CH, pam) //
|
||||
.and_then(selectMethod)
|
||||
.and_then(confirmMethod)
|
||||
.and_then(verifi);
|
||||
auto allowLogin = [&](const AuthenticationStatus & status) -> tl::expected< int, Error > {
|
||||
if(status.userAuthorized()) {
|
||||
rublon::log(rublon::LogLevel::Info, "Auth OK");
|
||||
pam.print("RUBLON authentication SUCCESS!\n");
|
||||
return PAM_SUCCESS;
|
||||
}else{
|
||||
rublon::log(rublon::LogLevel::Info, "User unauthorized");
|
||||
pam.print("RUBLON authentication FAILED");
|
||||
return PAM_MAXTRIES;
|
||||
}
|
||||
};
|
||||
|
||||
if(authStatus.has_value()) {
|
||||
rublon::log(rublon::LogLevel::Info, "Auth OK");
|
||||
pam.print("RUBLON authentication SUCCESS!\n");
|
||||
return PAM_SUCCESS;
|
||||
} else {
|
||||
const auto & error = authStatus.error();
|
||||
auto mapError = [&](const Error & error) -> tl::expected<int, Error>
|
||||
{
|
||||
rublon::log(
|
||||
LogLevel::Error, "auth problems due to %d class and %d category", error.errorClass(), static_cast< int >(error.category()));
|
||||
if(error.is< PamBaypass >()) {
|
||||
pam.print("\n RUBLON authentication bypased");
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
}
|
||||
pam.print("RUBLON authentication Success");
|
||||
rublon::log(LogLevel::Warning, "User login failed");
|
||||
return PAM_SUCCESS;
|
||||
pam.print("RUBLON authentication FAILED");
|
||||
rublon::log(LogLevel::Warning, "User login failed");
|
||||
|
||||
return PAM_MAXTRIES;
|
||||
};
|
||||
|
||||
auto ret = Init{rublonConfig.value()}
|
||||
.fire(CH, pam) //
|
||||
.and_then(selectMethod)
|
||||
.and_then(confirmMethod)
|
||||
.and_then(confirmCode)
|
||||
.and_then(allowLogin).or_else(mapError);
|
||||
|
||||
return ret.value_or(PAM_MAXTRIES);
|
||||
}
|
||||
|
||||
@ -8,19 +8,15 @@ namespace mocks {
|
||||
|
||||
class CoreHandlerMock : public rublon::CoreHandlerInterface< CoreHandlerMock > {
|
||||
public:
|
||||
MOCK_METHOD(( tl::expected< rublon::Document, rublon::Error > ),
|
||||
request,
|
||||
( rublon::RapidJSONPMRAlloc &, std::string_view, const rublon::Document & ),
|
||||
(const));
|
||||
|
||||
MOCK_METHOD(( tl::expected< rublon::Document, rublon::Error > ),
|
||||
request,
|
||||
( std::string_view, const rublon::Document & ),
|
||||
(const));
|
||||
|
||||
// tl::expected< rublon::Document, rublon::Error > request(std::string_view a1, const rublon::Document & a2) const {
|
||||
// rublon::RapidJSONPMRAlloc alloc;
|
||||
// return request(alloc, a1, a2);
|
||||
// };
|
||||
tl::expected< rublon::Document, rublon::Error >
|
||||
request(rublon::RapidJSONPMRAlloc &alloc, std::string_view path, const rublon::Document & req) const {
|
||||
// const rublon::Document &doc = request(path, req).value();
|
||||
// rublon::Document ret{&alloc};
|
||||
// ret.CopyFrom(doc, alloc);
|
||||
return request(path, req);
|
||||
};
|
||||
|
||||
MOCK_METHOD(( tl::expected< rublon::Document, rublon::Error > ), request, ( std::string_view, const rublon::Document & ), (const));
|
||||
};
|
||||
} // namespace mocks
|
||||
|
||||
@ -20,7 +20,8 @@ rublon::Configuration conf{rublon::Configuration::Parameters{//
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false}};
|
||||
false,
|
||||
true}};
|
||||
rublon::Configuration confBypass{rublon::Configuration::Parameters{//
|
||||
"320BAB778C4D4262B54CD243CDEFFAFD",
|
||||
"39e8d771d83a2ed3cc728811911c25",
|
||||
@ -29,6 +30,7 @@ rublon::Configuration confBypass{rublon::Configuration::Parameters{//
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true}};
|
||||
|
||||
inline std::string randomTID() {
|
||||
@ -189,6 +191,11 @@ class ResponseBase {
|
||||
// options.error = rublon::Error{rublon::CoreHandlerError{rublon::CoreHandlerError::ConnectionError}};
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResponseBase & withBasSignature() {
|
||||
options.error = rublon::Error{rublon::CoreHandlerError{rublon::CoreHandlerError::BadSigature}};
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator auto() {
|
||||
return options.error.category() == rublon::Error::k_None ? static_cast< Generator * >(this)->generate() : tl::unexpected{error()};
|
||||
@ -205,8 +212,9 @@ class ResponseBase {
|
||||
class RawCoreResponse : public ResponseBase< RawCoreResponse > {
|
||||
public:
|
||||
tl::expected< rublon::Document, rublon::Error > generate() {
|
||||
static rublon::RapidJSONPMRAlloc alloc;
|
||||
auto jsonString = std::visit([&](const auto generator) { return generator.generate(options); }, _coreGenerator);
|
||||
rublon::Document doc;
|
||||
rublon::Document doc{&alloc};
|
||||
doc.Parse(jsonString.c_str());
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -48,10 +48,10 @@ TEST_F(RublonHttpInitTest, rublon_Accept_pamLoginWhenThereIsNoConnection) {
|
||||
AllOf(Not(HasValue()), IsPAMBaypass()));
|
||||
}
|
||||
|
||||
// TEST_F(RublonHttpInitTest, rublon_Decline_pamLoginWhenServerHasBadSignature) {
|
||||
// EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::BadSigature}}));
|
||||
// EXPECT_THAT(sut.handle(coreHandler, pam), HoldsPamAction(PamAction::decline));
|
||||
// }
|
||||
TEST_F(RublonHttpInitTest, rublon_Decline_pamLoginWhenServerHasBadSignature) {
|
||||
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(RawCoreResponse{}.withBasSignature()));
|
||||
EXPECT_THAT(sut.handle(coreHandler, pam), IsPAMDeny());
|
||||
}
|
||||
|
||||
// TEST_F(RublonHttpInitTest, rublon_Decline_pamLoginWhenServerReturnsBrokenData) {
|
||||
// EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(tl::unexpected{CoreHandlerError{CoreHandlerError::BrokenData}}));
|
||||
|
||||
@ -26,6 +26,7 @@ class PasscodeBasedAuthTest : public Test {
|
||||
TEST_F(PasscodeBasedAuthTest, wrongPasscodeShouldFail) {
|
||||
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(RawCoreResponse{}.codeConfirmationMessage().withWrongCodeResponse()));
|
||||
EXPECT_CALL(pam, scan_mock(_)).WillOnce(Return("123456"));
|
||||
EXPECT_CALL(pam, print_mock(_));
|
||||
|
||||
EXPECT_THAT(sut.handle(coreHandler, pam), Unexpected(WerificationError{WerificationError::WrongCode}));
|
||||
}
|
||||
@ -37,7 +38,7 @@ TEST_F(PasscodeBasedAuthTest, whenGivenBadPasscodeWeNeedToAskAgain) {
|
||||
.WillOnce(Return("1_3456"))
|
||||
.WillOnce(Return("123456"));
|
||||
|
||||
EXPECT_CALL(pam, print_mock(_) );
|
||||
EXPECT_CALL(pam, print_mock(_) ).Times(2);
|
||||
|
||||
EXPECT_THAT(sut.handle(coreHandler, pam), HasValue() );
|
||||
}
|
||||
@ -55,6 +56,7 @@ TEST_F(PasscodeBasedAuthTest, whenGiveenBadPasscodeMultipleTimesWeAbort) {
|
||||
TEST_F(PasscodeBasedAuthTest, goodPasscodeShouldPass){
|
||||
EXPECT_CALL(coreHandler, request(_, _)).WillOnce(Return(RawCoreResponse{}.codeConfirmationMessage()));
|
||||
EXPECT_CALL(pam, scan_mock(_)).WillOnce(Return("123456"));
|
||||
EXPECT_CALL(pam, print_mock(_));
|
||||
|
||||
EXPECT_THAT(sut.handle(coreHandler, pam), HasValue() );
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user