stephb9959
2022-11-07 15:00:39 -08:00
parent 1cba12b934
commit 5d66fe0d56
9 changed files with 130 additions and 20 deletions

2
build
View File

@@ -1 +1 @@
15 16

View File

@@ -68,4 +68,53 @@ namespace OpenWifi {
return RetrieveTokenInformation(SessionToken, UInfo, TID, Expired, Contacted, Sub); return RetrieveTokenInformation(SessionToken, UInfo, TID, Expired, Contacted, Sub);
} }
bool AuthClient::RetrieveApiKeyInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted) {
try {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("apikey",SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY,
"/api/v1/validateApiKey" ,
QueryData,
10000);
Poco::JSON::Object::Ptr Response;
auto StatusCode = Req.Do(Response);
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
Contacted = false;
return false;
}
Contacted = true;
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo") && Response->has("expiresOn")) {
UInfo.from_json(Response);
Expired = false;
ApiKeyCache_.update(SessionToken, ApiKeyCacheEntry{ .UserInfo = UInfo, .ExpiresOn = Response->get("expiresOn")});
return true;
} else {
return false;
}
}
} catch (...) {
poco_error(Logger(),fmt::format("Failed to retrieve api key={} for TID={}", SessionToken, TID));
}
Expired = false;
return false;
}
bool AuthClient::IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy &UInfo,
std::uint64_t TID, bool &Expired, bool &Contacted) {
auto User = ApiKeyCache_.get(SessionToken);
if (!User.isNull()) {
if(User->ExpiresOn < Utils::Now())
Expired = false;
UInfo = User->UserInfo;
return true;
}
return RetrieveApiKeyInformation(SessionToken, UInfo, TID, Expired, Contacted);
}
} // namespace OpenWifi } // namespace OpenWifi

View File

@@ -12,6 +12,7 @@
namespace OpenWifi { namespace OpenWifi {
class AuthClient : public SubSystemServer { class AuthClient : public SubSystemServer {
public: public:
explicit AuthClient() noexcept: explicit AuthClient() noexcept:
SubSystemServer("Authentication", "AUTH-CLNT", "authentication") SubSystemServer("Authentication", "AUTH-CLNT", "authentication")
@@ -23,7 +24,12 @@ namespace OpenWifi {
return instance_; return instance_;
} }
inline int Start() override { struct ApiKeyCacheEntry {
OpenWifi::SecurityObjects::UserInfoAndPolicy UserInfo;
std::uint64_t ExpiresOn;
};
inline int Start() override {
return 0; return 0;
} }
@@ -36,6 +42,7 @@ namespace OpenWifi {
inline void RemovedCachedToken(const std::string &Token) { inline void RemovedCachedToken(const std::string &Token) {
Cache_.remove(Token); Cache_.remove(Token);
ApiKeyCache_.remove(Token);
} }
inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) { inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) {
@@ -46,12 +53,24 @@ namespace OpenWifi {
SecurityObjects::UserInfoAndPolicy & UInfo, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID, std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub=false); bool & Expired, bool & Contacted, bool Sub=false);
bool RetrieveApiKeyInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted);
bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID, std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub = false); bool & Expired, bool & Contacted, bool Sub = false);
bool IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted);
private: private:
Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{512,1200000 }; Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{512,1200000 };
Poco::ExpireLRUCache<std::string,ApiKeyCacheEntry> ApiKeyCache_{512,1200000 };
}; };
inline auto AuthClient() { return AuthClient::instance(); } inline auto AuthClient() { return AuthClient::instance(); }

View File

@@ -246,27 +246,19 @@ namespace OpenWifi {
FileChannel->setProperty("purgeCount", "10"); FileChannel->setProperty("purgeCount", "10");
FileChannel->setProperty("path", LoggingLocation); FileChannel->setProperty("path", LoggingLocation);
if(UseAsyncLogs_) { if(UseAsyncLogs_) {
std::cout << __LINE__ << std::endl;
Poco::AutoPtr<Poco::AsyncChannel> Async_File( Poco::AutoPtr<Poco::AsyncChannel> Async_File(
new Poco::AsyncChannel(FileChannel)); new Poco::AsyncChannel(FileChannel));
std::cout << __LINE__ << std::endl;
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter); Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
std::cout << __LINE__ << std::endl;
Formatter->setProperty("pattern", LoggingFormat); Formatter->setProperty("pattern", LoggingFormat);
std::cout << __LINE__ << std::endl;
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel( Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(
new Poco::FormattingChannel(Formatter, Async_File)); new Poco::FormattingChannel(Formatter, Async_File));
std::cout << __LINE__ << std::endl;
if(DisableWebSocketLogging) { if(DisableWebSocketLogging) {
std::cout << __LINE__ << std::endl;
Poco::Logger::root().setChannel(FormattingChannel); Poco::Logger::root().setChannel(FormattingChannel);
} else { } else {
std::cout << __LINE__ << std::endl;
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger); Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel); Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger); Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel); Splitter->addChannel(FormattingChannel);
std::cout << __LINE__ << std::endl;
Poco::Logger::root().setChannel(Splitter); Poco::Logger::root().setChannel(Splitter);
} }
@@ -276,18 +268,14 @@ namespace OpenWifi {
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel( Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(
new Poco::FormattingChannel(Formatter, FileChannel)); new Poco::FormattingChannel(Formatter, FileChannel));
if(DisableWebSocketLogging) { if(DisableWebSocketLogging) {
std::cout << __LINE__ << std::endl;
Poco::Logger::root().setChannel(FormattingChannel); Poco::Logger::root().setChannel(FormattingChannel);
} else { } else {
std::cout << __LINE__ << std::endl;
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel); Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger); Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Splitter->addChannel(WSLogger); Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel); Splitter->addChannel(FormattingChannel);
std::cout << __LINE__ << std::endl;
Poco::Logger::root().setChannel(Splitter); Poco::Logger::root().setChannel(Splitter);
} }
std::cout << __LINE__ << std::endl;
} }
} }
auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug")); auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug"));

View File

@@ -26,6 +26,10 @@
#include "framework/AuthClient.h" #include "framework/AuthClient.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
#if defined(TIP_SECURITY_SERVICE)
#include "AuthService.h"
#endif
using namespace std::chrono_literals; using namespace std::chrono_literals;
namespace OpenWifi { namespace OpenWifi {
@@ -640,7 +644,8 @@ namespace OpenWifi {
}; };
#ifdef TIP_SECURITY_SERVICE #ifdef TIP_SECURITY_SERVICE
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired , bool Sub ); [[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired , bool Sub );
#endif #endif
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) { inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
if(Internal_ && Request->has("X-INTERNAL-NAME")) { if(Internal_ && Request->has("X-INTERNAL-NAME")) {
@@ -665,7 +670,36 @@ namespace OpenWifi {
} }
} }
return Allowed; return Allowed;
} else { } else if(!Internal_ && Request->has("X-API-KEY")) {
SessionToken_ = Request->get("X-API-KEY", "");
#ifdef TIP_SECURITY_SERVICE
std::uint64_t expiresOn;
if (AuthService()->IsValidApiKey(SessionToken_, UserInfo_.webtoken, UserInfo_.userinfo, Expired, expiresOn)) {
#else
if (AuthClient()->IsValidApiKey( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted)) {
#endif
REST_Requester_ = UserInfo_.userinfo.email;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): APIKEY-ACCESS TID={} User='{}@{}' Method={} Path={}",
UserInfo_.userinfo.email,
TransactionId_,
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->clientAddress().toString(),
Request->getMethod(),
Request->getURI()));
}
return true;
} else {
if(Server_.LogBadTokens(true)) {
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(),
Request->getURI()));
}
}
return false;
} else {
if (SessionToken_.empty()) { if (SessionToken_.empty()) {
try { try {
Poco::Net::OAuth20Credentials Auth(*Request); Poco::Net::OAuth20Credentials Auth(*Request);

View File

@@ -15,6 +15,10 @@
#include "fmt/format.h" #include "fmt/format.h"
#if defined(TIP_SECURITY_SERVICE)
#include "AuthService.h"
#endif
#define DBG { std::cout << __LINE__ << std::endl; } #define DBG { std::cout << __LINE__ << std::endl; }
namespace OpenWifi { namespace OpenWifi {
@@ -216,9 +220,16 @@ namespace OpenWifi {
if (!Client->second->Authenticated_) { if (!Client->second->Authenticated_) {
std::string Frame{IncomingFrame.begin()}; std::string Frame{IncomingFrame.begin()};
auto Tokens = Utils::Split(Frame, ':'); auto Tokens = Utils::Split(Frame, ':');
bool Expired = false, Contacted = false; bool Expired = false;
#if not defined(TIP_SECURITY_SERVICE)
bool Contacted = false;
#endif
if (Tokens.size() == 2 && if (Tokens.size() == 2 &&
AuthClient()->IsAuthorized(Tokens[1], Client->second->UserInfo_, 0, Expired, Contacted)) { #if defined(TIP_SECURITY_SERVICE)
AuthService()->IsAuthorized(Tokens[1], Client->second->UserInfo_, 0, Expired)) {
#else
AuthClient()->IsAuthorized(Tokens[1], Client->second->UserInfo_, 0, Expired, Contacted)) {
#endif
Client->second->Authenticated_ = true; Client->second->Authenticated_ = true;
Client->second->UserName_ = Client->second->UserInfo_.userinfo.email; Client->second->UserName_ = Client->second->UserInfo_.userinfo.email;
poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Client->second->Id_, Client->second->UserName_)); poco_debug(Logger(),fmt::format("START({}): {} UI Client is starting WS connection.", Client->second->Id_, Client->second->UserName_));
@@ -234,7 +245,6 @@ namespace OpenWifi {
std::ostringstream OS; std::ostringstream OS;
WelcomeMessage.stringify(OS); WelcomeMessage.stringify(OS);
Client->second->WS_->sendFrame(OS.str().c_str(), (int) OS.str().size()); Client->second->WS_->sendFrame(OS.str().c_str(), (int) OS.str().size());
Client->second->WS_->sendFrame(OS.str().c_str(), (int) OS.str().size());
return EndConnection(G, Client); return EndConnection(G, Client);
} }
} else { } else {

View File

@@ -222,6 +222,12 @@ namespace OpenWifi::RESTAPI::Errors {
static const struct msg DeviceRequiresSignature{1146,"Device requires device signature to be provided."}; static const struct msg DeviceRequiresSignature{1146,"Device requires device signature to be provided."};
static const struct msg ApiKeyNameAlreadyExists{1147,"API Key name must be unique."};
static const struct msg TooManyApiKeys{1148,"Too many API Keys have already been created."};
static const struct msg UserMustExist{1149,"User must exist."};
static const struct msg ApiKeyNameDoesNotExist{1150,"API Key name does not exist."};
static const struct msg ApiKeyDoesNotExist{1150,"API Key does not exist."};
} }

View File

@@ -520,4 +520,8 @@ bool ExtractBase64CompressedData(const std::string &CompressedData,
return false; return false;
} }
bool IsAlphaNumeric(const std::string &s) {
return std::all_of(s.begin(),s.end(),[](char c) -> bool { return isalnum(c); });
}
} }

View File

@@ -115,7 +115,7 @@ namespace OpenWifi::Utils {
[[nodiscard]] std::string BinaryFileToHexString(const Poco::File &F); [[nodiscard]] std::string BinaryFileToHexString(const Poco::File &F);
[[nodiscard]] std::string SecondsToNiceText(uint64_t Seconds); [[nodiscard]] std::string SecondsToNiceText(uint64_t Seconds);
[[nodiscard]] bool wgets(const std::string &URL, std::string &Response); [[nodiscard]] bool wgets(const std::string &URL, std::string &Response);
[[nodiscard]] bool IsAlphaNumeric(const std::string &s);
template< typename T > template< typename T >
std::string int_to_hex( T i ) std::string int_to_hex( T i )
{ {