mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 02:37:56 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			126 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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
 | 
