Files
wlan-cloud-ucentralsec/src/MFAServer.cpp
2023-02-21 12:23:18 -08:00

126 lines
3.7 KiB
C++

//
// Created by stephane bourque on 2021-10-11.
//
#include "MFAServer.h"
#include "AuthService.h"
#include "SMSSender.h"
#include "SMTPMailerService.h"
#include "TotpCache.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
namespace OpenWifi {
int MFAServer::Start() { return 0; }
void MFAServer::Stop() {}
bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
Poco::JSON::Object &ChallengeStart) {
std::lock_guard G(Mutex_);
CleanCache();
if (!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
return false;
std::string Challenge = MakeChallenge();
std::string uuid = MicroServiceCreateUUID();
uint64_t Created = Utils::Now();
ChallengeStart.set("uuid", uuid);
ChallengeStart.set("created", Created);
ChallengeStart.set("question", "mfa challenge");
ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
Cache_[uuid] = MFACacheEntry{.UInfo = UInfo,
.Answer = Challenge,
.Created = Created,
.Method = UInfo.userinfo.userTypeProprietaryInfo.mfa.method};
return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
}
bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
const std::string &Method, const std::string &Challenge) {
if (Method == MFAMETHODS::SMS && SMSSender()->Enabled() &&
!UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
std::string Message = "This is your login code: " + Challenge +
" Please enter this in your login screen.";
return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number,
Message);
} else if (Method == MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() &&
!UInfo.userinfo.email.empty()) {
return AuthService()->SendEmailChallengeCode(UInfo, Challenge);
} else if (Method == MFAMETHODS::AUTHENTICATOR &&
!UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
return true;
}
return false;
}
bool MFAServer::ResendCode(const std::string &uuid) {
std::lock_guard G(Mutex_);
auto Hint = Cache_.find(uuid);
if (Hint == Cache_.end())
return false;
return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
}
bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
SecurityObjects::UserInfoAndPolicy &UInfo) {
std::lock_guard G(Mutex_);
if (!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
return false;
auto uuid = ChallengeResponse->get("uuid").toString();
auto Hint = Cache_.find(uuid);
if (Hint == end(Cache_)) {
return false;
}
auto answer = ChallengeResponse->get("answer").toString();
std::string Expecting;
if (Hint->second.Method == MFAMETHODS::AUTHENTICATOR) {
if (!TotpCache()->ValidateCode(
Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret, answer,
Expecting)) {
return false;
}
} else if (Hint->second.Answer != answer) {
return false;
}
UInfo = Hint->second.UInfo;
Cache_.erase(Hint);
return true;
}
bool MFAServer::MethodEnabled(const std::string &Method) {
if (Method == MFAMETHODS::SMS)
return SMSSender()->Enabled();
if (Method == MFAMETHODS::EMAIL)
return SMTPMailerService()->Enabled();
if (Method == MFAMETHODS::AUTHENTICATOR)
return true;
return false;
}
void MFAServer::CleanCache() {
// it is assumed that you have locked Cache_ at this point.
uint64_t Now = Utils::Now();
for (auto i = begin(Cache_); i != end(Cache_);) {
if ((Now - i->second.Created) > 300) {
i = Cache_.erase(i);
} else {
++i;
}
}
}
} // namespace OpenWifi