Compare commits

..

1 Commits

Author SHA1 Message Date
Dmitry Dunaev
05d06fce53 [WIFI-5702] Add: README note on changing default password 2021-11-14 22:37:33 +03:00
37 changed files with 402 additions and 3176 deletions

View File

@@ -30,20 +30,9 @@ else()
file(WRITE build ${BUILD_NUM})
endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
set(BUILD_SHARED_LIBS 1)
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}")
add_definitions(-DTIP_SECURITY_SERVICE="1")
set(Boost_USE_STATIC_LIBS OFF)
@@ -61,11 +50,8 @@ find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataS
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_executable( owsec
build
src/ow_version.h.in
src/framework/CountryCodes.h
src/framework/KafkaTopics.h
src/framework/MicroService.h
@@ -104,7 +90,7 @@ add_executable( owsec
src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
src/storage/storage_tokens.h
src/ActionLinkManager.cpp src/ActionLinkManager.h
src/ACLProcessor.h)
)
if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC

View File

@@ -56,7 +56,6 @@ RUN make install
ADD CMakeLists.txt build /owsec/
ADD cmake /owsec/cmake
ADD src /owsec/src
ADD .git /owgw/.git
WORKDIR /owsec
RUN mkdir cmake-build

2
build
View File

@@ -1 +1 @@
108
47

View File

@@ -8,7 +8,7 @@ fullnameOverride: ""
images:
owsec:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
tag: v2.4.0-RC4
tag: main
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io

View File

@@ -61,8 +61,6 @@ components:
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # expired token
- 10 # rate limit exceeded
ErrorDetails:
type: string
ErrorDescription:

View File

@@ -40,7 +40,6 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
openwifi.service.key.password = mypassword
smssender.enabled = false
smssender.provider = aws
smssender.aws.secretkey = ***************************************
smssender.aws.accesskey = ***************************************
@@ -54,7 +53,6 @@ smssender.aws.region = **************
#
# Security Microservice Specific Section
#
mailer.enabled = false
mailer.hostname = smtp.gmail.com
mailer.username = ************************
mailer.password = ************************

View File

@@ -1,45 +0,0 @@
//
// Created by stephane bourque on 2021-11-12.
//
#ifndef OWSEC_ACLPROCESSOR_H
#define OWSEC_ACLPROCESSOR_H
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
class ACLProcessor {
public:
enum ACL_OPS {
READ,
MODIFY,
DELETE,
CREATE
};
static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) {
if(User.Id == Target.Id && Op==DELETE)
return false;
if(User.userRole==SecurityObjects::ROOT)
return true;
if(User.Id == Target.Id)
return true;
if(User.userRole!=SecurityObjects::ADMIN && User.userRole!=SecurityObjects::ROOT && Op!=READ)
return false;
if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
return false;
return true;
}
private:
};
}
#endif //OWSEC_ACLPROCESSOR_H

View File

@@ -18,8 +18,8 @@ namespace OpenWifi {
};
static ActionLinkManager * instance() {
static auto * instance_ = new ActionLinkManager;
return instance_;
static ActionLinkManager instance;
return &instance;
}
int Start() final;

View File

@@ -56,10 +56,9 @@ namespace OpenWifi {
Logger_.notice("Stopping...");
}
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo )
{
std::lock_guard Guard(Mutex_);
Expired = false;
try {
std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request);
@@ -68,29 +67,27 @@ namespace OpenWifi {
}
if(!CallToken.empty()) {
auto Client = UserCache_.get(CallToken);
if( Client.isNull() ) {
SecurityObjects::UserInfoAndPolicy UInfo2;
uint64_t RevocationDate=0;
if(StorageService()->GetToken(CallToken,UInfo2,RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr);
if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) {
UInfo.webtoken = UInfo2.webtoken;
UserCache_.update(CallToken, UInfo);
SessionToken = CallToken;
if(StorageService()->IsTokenRevoked(CallToken))
return false;
auto Client = UserCache_.find(CallToken);
if( Client == UserCache_.end() ) {
if(StorageService()->GetToken(SessionToken,UInfo)) {
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
return false;
}
if(!Expired) {
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken;
UInfo = *Client ;
UInfo = Client->second ;
return true;
}
RevokeToken(CallToken);
UserCache_.erase(Client);
StorageService()->RevokeToken(CallToken);
return false;
}
} catch(const Poco::Exception &E) {
@@ -99,24 +96,16 @@ namespace OpenWifi {
return false;
}
void AuthService::RevokeToken(std::string & Token) {
UserCache_.remove(Token);
StorageService()->RevokeToken(Token);
}
bool AuthService::DeleteUserFromCache(const std::string &UserName) {
std::lock_guard Guard(Mutex_);
std::vector<std::string> OldTokens;
UserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void
{ if(O.userinfo.email==UserName)
OldTokens.push_back(token);
});
for(const auto &i:OldTokens) {
Logout(i,false);
UserCache_.remove(i);
for(auto i=UserCache_.begin();i!=UserCache_.end();) {
if (i->second.userinfo.email==UserName) {
Logout(i->first, false);
i = UserCache_.erase(i);
} else {
++i;
}
}
return true;
}
@@ -132,6 +121,9 @@ namespace OpenWifi {
void AuthService::Logout(const std::string &token, bool EraseFromCache) {
std::lock_guard Guard(Mutex_);
if(EraseFromCache)
UserCache_.erase(token);
try {
Poco::JSON::Object Obj;
Obj.set("event", "remove-token");
@@ -140,7 +132,7 @@ namespace OpenWifi {
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText);
std::string Tmp{token};
RevokeToken(Tmp);
StorageService()->RevokeToken(Tmp);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(),
false);
} catch (const Poco::Exception &E) {
@@ -191,9 +183,9 @@ namespace OpenWifi {
UInfo.webtoken.username_ = UserName;
UInfo.webtoken.errorCode = 0;
UInfo.webtoken.userMustChangePassword = false;
UserCache_.update(UInfo.webtoken.access_token_,UInfo);
UserCache_[UInfo.webtoken.access_token_] = UInfo;
StorageService()->SetLastLogin(UInfo.userinfo.Id);
StorageService()->AddToken(UInfo.userinfo.Id, UInfo.webtoken.access_token_,
StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_,
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
}
@@ -261,7 +253,7 @@ namespace OpenWifi {
return false;
}
UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired )
UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
{
std::lock_guard Guard(Mutex_);
@@ -299,7 +291,6 @@ namespace OpenWifi {
UInfo.userinfo.lastLogin=std::time(nullptr);
StorageService()->SetLastLogin(UInfo.userinfo.Id);
CreateToken(UserName, UInfo );
return SUCCESS;
}
@@ -346,7 +337,7 @@ namespace OpenWifi {
A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
A.userId = UInfo.email;
A.id = MicroService::CreateUUID();
A.id = MicroService::instance().CreateUUID();
A.created = std::time(nullptr);
A.expires = A.created + 24*60*60;
StorageService()->CreateAction(A);
@@ -354,38 +345,15 @@ namespace OpenWifi {
return true;
}
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo) {
std::lock_guard G(Mutex_);
auto It = UserCache_.find(Token);
Expired = false;
auto Client = UserCache_.get(Token);
if(!Client.isNull()) {
Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr);
WebToken = Client->webtoken;
UserInfo = Client->userinfo;
return true;
}
std::string TToken{Token};
if(StorageService()->IsTokenRevoked(TToken)) {
if(It==UserCache_.end())
return false;
}
// get the token from disk...
SecurityObjects::UserInfoAndPolicy UInfo;
uint64_t RevocationDate=0;
if(StorageService()->GetToken(TToken, UInfo, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (UInfo.webtoken.created_ + UInfo.webtoken.expires_in_) < std::time(nullptr);
if(StorageService()->GetUserById(UInfo.userinfo.Id,UInfo.userinfo)) {
WebToken = UInfo.webtoken;
UserCache_.update(UInfo.webtoken.access_token_, UInfo);
return true;
}
}
return false;
WebToken = It->second.webtoken;
UserInfo = It->second.userinfo;
return true;
}

View File

@@ -18,7 +18,6 @@
#include "Poco/SHA2Engine.h"
#include "Poco/Crypto/DigestEngine.h"
#include "Poco/HMACEngine.h"
#include "Poco/ExpireLRUCache.h"
#include "framework/MicroService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
@@ -45,15 +44,15 @@ namespace OpenWifi{
static int AccessTypeToInt(ACCESS_TYPE T);
static AuthService *instance() {
static auto * instance_ = new AuthService;
return instance_;
static AuthService instance;
return &instance;
}
int Start() override;
void Stop() override;
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
[[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
[[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo );
void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
@@ -61,7 +60,8 @@ namespace OpenWifi{
bool ValidatePassword(const std::string &pwd);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo);
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
[[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
@@ -75,21 +75,19 @@ namespace OpenWifi{
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
[[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
void RevokeToken(std::string & Token);
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
}
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
return MicroService::instance().DataDir() + "/wwwassets/the_logo.png";
}
private:
Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_;
Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy> UserCache_{2048,1200000};
// SecurityObjects::UserInfoCache UserCache_;
SecurityObjects::UserInfoCache UserCache_;
std::string PasswordValidationStr_;
std::regex PasswordValidation_;
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
@@ -121,8 +119,8 @@ namespace OpenWifi{
inline AuthService * AuthService() { return AuthService::instance(); }
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired) {
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
return AuthService()->IsAuthorized(Request, SessionToken, UInfo );
}
} // end of namespace

View File

@@ -26,7 +26,7 @@ namespace OpenWifi {
return false;
std::string Challenge = MakeChallenge();
std::string uuid = MicroService::CreateUUID();
std::string uuid = MicroService::instance().CreateUUID();
uint64_t Created = std::time(nullptr);
ChallengeStart.set("uuid",uuid);
@@ -71,9 +71,8 @@ namespace OpenWifi {
auto uuid = ChallengeResponse->get("uuid").toString();
auto Hint = Cache_.find(uuid);
if(Hint == end(Cache_)) {
if(Hint == end(Cache_))
return false;
}
auto answer = ChallengeResponse->get("answer").toString();
if(Hint->second.Answer!=answer) {

View File

@@ -24,8 +24,8 @@ namespace OpenWifi {
int Start() override;
void Stop() override;
static MFAServer *instance() {
static auto * instance_ = new MFAServer;
return instance_;
static MFAServer instance;
return &instance;
}
bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
@@ -35,7 +35,7 @@ namespace OpenWifi {
static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
static inline std::string MakeChallenge() {
return std::to_string(MicroService::instance().Random(1,999999));
return std::to_string(rand() % 999999);
}
private:

View File

@@ -20,7 +20,7 @@ namespace OpenWifi {
Server,
Internal,
false,
true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
true, RateLimit{.Interval=1000,.MaxCalls=5}) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
void RequestResetPassword(SecurityObjects::ActionLink &Link);
void CompleteResetPassword();

View File

@@ -17,39 +17,24 @@
#include "StorageService.h"
namespace OpenWifi {
static void FilterCredentials(SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
void RESTAPI_oauth2Handler::DoGet() {
bool Expired = false;
if (!IsAuthorized(Expired)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
if (!IsAuthorized()) {
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
}
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
if(GetMe) {
Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
Poco::JSON::Object Me;
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
FilterCredentials(ReturnedUser);
ReturnedUser.to_json(Me);
UserInfo_.userinfo.to_json(Me);
return ReturnObject(Me);
}
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
}
void RESTAPI_oauth2Handler::DoDelete() {
bool Expired = false;
if (!IsAuthorized(Expired)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
}
if (!IsAuthorized()) {
return UnAuthorized("Not authorized.");
}
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
if (Token == SessionToken_) {
@@ -86,7 +71,7 @@ namespace OpenWifi {
SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
NewLink.id = MicroService::CreateUUID();
NewLink.id = MicroService::instance().CreateUUID();
NewLink.userId = UInfo1.Id;
NewLink.created = std::time(nullptr);
NewLink.expires = NewLink.created + (24*60*60);
@@ -108,8 +93,8 @@ namespace OpenWifi {
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) {
Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
auto uuid = Obj->get("uuid").toString();
if(Obj->has(RESTAPI::Protocol::UUID)) {
auto uuid = Obj->get(RESTAPI::Protocol::UUID).toString();
if(MFAServer().ResendCode(uuid))
return OK();
}
@@ -118,7 +103,7 @@ namespace OpenWifi {
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
if(Obj->has(RESTAPI::Protocol::UUID)) {
SecurityObjects::UserInfoAndPolicy UInfo;
if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
Poco::JSON::Object ReturnObj;
@@ -130,8 +115,7 @@ namespace OpenWifi {
}
SecurityObjects::UserInfoAndPolicy UInfo;
bool Expired=false;
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
if (Code==SUCCESS) {
Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) {

View File

@@ -21,7 +21,7 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {}
Internal, false, true , RateLimit{.Interval=2000,.MaxCalls=5}) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
void DoGet() final;
void DoPost() final;

View File

@@ -7,16 +7,8 @@
#include "Poco/JSON/Parser.h"
#include "framework/RESTAPI_errors.h"
#include "SMSSender.h"
#include "ACLProcessor.h"
namespace OpenWifi {
static void FilterCredentials(SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
void RESTAPI_user_handler::DoGet() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
@@ -35,7 +27,9 @@ namespace OpenWifi {
}
Poco::JSON::Object UserInfoObject;
FilterCredentials(UInfo);
UInfo.currentPassword.clear();
UInfo.lastPasswords.clear();
UInfo.oauthType.clear();
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
}
@@ -46,12 +40,20 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
if(UserInfo_.userinfo.userRole!= SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(UserInfo_.userinfo.Id == Id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound();
}
if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
if(UInfo.userRole==SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
@@ -62,9 +64,6 @@ namespace OpenWifi {
if(AuthService()->DeleteUserFromCache(UInfo.email)) {
// nothing to do
}
StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id);
Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
StorageService()->RevokeAllTokens(UInfo.email);
Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
@@ -77,52 +76,57 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::IdMustBe0);
}
SecurityObjects::UserInfo NewUser;
RESTAPI_utils::from_request(NewUser,*Request);
SecurityObjects::UserInfo UInfo;
RESTAPI_utils::from_request(UInfo,*Request);
if(NewUser.userRole == SecurityObjects::UNKNOWN) {
if(UInfo.userRole == SecurityObjects::UNKNOWN) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
Poco::toLowerInPlace(NewUser.email);
if(!Utils::ValidEMailAddress(NewUser.email)) {
if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && UInfo.userRole == SecurityObjects::ROOT) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
Poco::toLowerInPlace(UInfo.email);
if(!Utils::ValidEMailAddress(UInfo.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
}
if(!NewUser.currentPassword.empty()) {
if(!AuthService()->ValidatePassword(NewUser.currentPassword)) {
if(!UInfo.currentPassword.empty()) {
if(!AuthService()->ValidatePassword(UInfo.currentPassword)) {
return BadRequest(RESTAPI::Errors::InvalidPassword);
}
}
if(NewUser.name.empty())
NewUser.name = NewUser.email;
if(UInfo.name.empty())
UInfo.name = UInfo.email;
if(!StorageService()->CreateUser(NewUser.email,NewUser)) {
Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email));
if(!StorageService()->CreateUser(UInfo.email,UInfo)) {
Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email));
return BadRequest(RESTAPI::Errors::RecordNotCreated);
}
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifyEmail(NewUser))
Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email));
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser);
if(AuthService::VerifyEmail(UInfo))
Logger_.information(Poco::format("Verification e-mail requested for %s",UInfo.email));
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UInfo.Id,UInfo);
}
if(!StorageService()->GetUserByEmail(NewUser.email, NewUser)) {
Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email));
if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) {
Logger_.information(Poco::format("User '%s' but not retrieved.",UInfo.email));
return NotFound();
}
Poco::JSON::Object UserInfoObject;
FilterCredentials(NewUser);
NewUser.to_json(UserInfoObject);
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email));
Logger_.information(Poco::format("User '%s' has been added by '%s')",UInfo.email, UserInfo_.userinfo.email));
}
void RESTAPI_user_handler::DoPut() {
@@ -136,8 +140,12 @@ namespace OpenWifi {
return NotFound();
}
if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole == SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
SecurityObjects::UserInfo NewUser;
@@ -216,23 +224,15 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) {
if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) {
return BadRequest("Unknown MFA method");
}
if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
}
if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest("Illegal MFA method");
}
}
if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
SecurityObjects::UserInfo NewUserInfo;
StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject;
FilterCredentials(NewUserInfo);
NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject);
}

View File

@@ -13,8 +13,7 @@ namespace OpenWifi {
if (i.first == "token") {
// can we find this token?
SecurityObjects::UserInfoAndPolicy SecObj;
bool Expired = false;
if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) {
if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo)) {
Poco::JSON::Object Obj;
SecObj.to_json(Obj);
return ReturnObject(Obj);

View File

@@ -562,7 +562,7 @@ namespace OpenWifi::ProvObjects {
}
I.notes = N;
I.modified = I.created = Now;
I.id = MicroService::CreateUUID();
I.id = MicroService::instance().CreateUUID();
return true;
}

View File

@@ -59,15 +59,15 @@ namespace OpenWifi::SecurityObjects {
struct MobilePhoneNumber {
std::string number;
bool verified = false;
bool primary = false;
bool verified;
bool primary;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
struct MfaAuthInfo {
bool enabled = false;
bool enabled;
std::string method;
void to_json(Poco::JSON::Object &Obj) const;
@@ -86,7 +86,7 @@ namespace OpenWifi::SecurityObjects {
std::string uuid;
std::string question;
std::string method;
uint64_t created = std::time(nullptr);
uint64_t created;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);

View File

@@ -16,16 +16,13 @@
namespace OpenWifi {
int SMSSender::Start() {
Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false);
if(Enabled_) {
Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws");
if(Provider_=="aws") {
ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_);
} else if(Provider_=="twilio") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
}
Enabled_ = ProviderImpl_->Initialize();
Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws");
if(Provider_=="aws") {
ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_);
} else if(Provider_=="twilio") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
}
Enabled_ = ProviderImpl_->Initialize();
return 0;
}

View File

@@ -18,15 +18,15 @@ namespace OpenWifi {
std::string Number;
std::string Code;
std::string UserName;
uint64_t Created = std::time(nullptr);
bool Validated = false;
uint64_t Created;
bool Validated=false;
};
class SMSSender : public SubSystemServer {
public:
static SMSSender *instance() {
static auto *instance_ = new SMSSender;
return instance_;
static SMSSender instance;
return &instance;
}
int Start() final;
@@ -37,8 +37,8 @@ namespace OpenWifi {
bool IsNumberValid(const std::string &Number, const std::string &UserName);
[[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
private:
std::string Provider_;
bool Enabled_=false;
std::string Provider_;
bool Enabled_=false;
std::vector<SMSValidationCacheEntry> Cache_;
std::unique_ptr<SMS_provider> ProviderImpl_;

View File

@@ -43,24 +43,18 @@ namespace OpenWifi {
if(!Running_)
return false;
try {
Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
Aws::SNS::Model::PublishRequest psms_req;
psms_req.SetMessage(Message.c_str());
psms_req.SetPhoneNumber(PhoneNumber.c_str());
auto psms_out = sns.Publish(psms_req);
if (psms_out.IsSuccess()) {
Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber));
return true;
}
std::string ErrMsg{psms_out.GetError().GetMessage()};
Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
return false;
} catch (...) {
Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
Aws::SNS::Model::PublishRequest psms_req;
psms_req.SetMessage(Message.c_str());
psms_req.SetPhoneNumber(PhoneNumber.c_str());
auto psms_out = sns.Publish(psms_req);
if (psms_out.IsSuccess()) {
Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber));
return true;
}
Logger_.debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber));
std::string ErrMsg{psms_out.GetError().GetMessage()};
Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
return false;
}

View File

@@ -9,9 +9,12 @@
#include "Poco/Net/SMTPClientSession.h"
#include "Poco/Net/SecureSMTPClientSession.h"
#include "Poco/Net/StringPartSource.h"
#include "Poco/Path.h"
#include "Poco/Exception.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "SMTPMailerService.h"
#include "framework/MicroService.h"
@@ -20,19 +23,14 @@
namespace OpenWifi {
void SMTPMailerService::LoadMyConfig() {
Enabled_ = MicroService::instance().ConfigGetBool("mailer.enabled",false);
if(Enabled_) {
MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password");
Sender_ = MicroService::instance().ConfigGetString("mailer.sender");
LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod");
MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port");
TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir());
MailRetry_ = (int) MicroService::instance().ConfigGetInt("mailer.retry",2*60);
MailAbandon_ = (int) MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60);
Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty());
}
MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password");
Sender_ = MicroService::instance().ConfigGetString("mailer.sender");
LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod");
MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port");
TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir());
Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty());
}
int SMTPMailerService::Start() {
@@ -55,46 +53,57 @@ namespace OpenWifi {
bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) {
std::lock_guard G(Mutex_);
PendingMessages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr),
/*
uint64_t Now = std::time(nullptr);
std::string RecipientLower = Poco::toLower(Recipient);
auto CE = Cache_.find(RecipientLower);
if(CE!=Cache_.end()) {
// only allow messages to the same user within 2 minutes
if(!((CE->second.LastRequest-Now)<30 && CE->second.HowManyRequests<10))
return false;
if(CE->second.LastRequest-Now>30) {
CE->second.LastRequest = Now;
CE->second.HowManyRequests=0;
} else {
CE->second.HowManyRequests++;
}
} else {
Cache_[RecipientLower] = MessageCacheEntry{.LastRequest=Now, .HowManyRequests=0};
}
*/
Messages_.push_back(MessageEvent{.Posted=(uint64_t )std::time(nullptr),
.LastTry=0,
.Sent=0,
.File=Poco::File(TemplateDir_ + "/" +Name),
.Attrs=Attrs});
return true;
}
void SMTPMailerService::run() {
Running_ = true;
while(Running_) {
Poco::Thread::trySleep(10000);
if(!Running_)
break;
{
std::lock_guard G(Mutex_);
Messages_.splice(Messages_.end(),PendingMessages_);
}
for(auto i=Messages_.begin();i!=Messages_.end();) {
if(!Running_)
break;
auto Recipient = i->Attrs.find(RECIPIENT_EMAIL)->second;
uint64_t Now = std::time(nullptr);
if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) {
if (SendIt(*i)) {
Logger_.information(Poco::format("Attempting to deliver for mail '%s'.", Recipient));
i = Messages_.erase(i);
} else {
i->LastTry = Now;
++i;
for(auto &i:Messages_) {
if(i.Sent==0 && (i.LastTry==0 || (Now-i.LastTry)>120)) {
if (SendIt(i)) {
i.LastTry = i.Sent = std::time(nullptr);
} else
i.LastTry = std::time(nullptr);
}
} else if ((Now-i->Posted)>MailAbandon_) {
Logger_.information(Poco::format("Mail for '%s' has timed out and will not be sent.", Recipient));
i = Messages_.erase(i);
} else {
++i;
}
// Clean the list
std::remove_if(Messages_.begin(),Messages_.end(),[Now](MessageEvent &E){ return (E.Sent!=0 || ((Now-E.LastTry)>(15*60)));});
}
}
}
@@ -106,12 +115,10 @@ namespace OpenWifi {
}
bool SMTPMailerService::SendIt(const MessageEvent &Msg) {
std::string Recipient;
try
{
Poco::Net::MailMessage Message;
Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second;
std::string Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second;
auto H1 = Msg.Attrs.find(SENDER);
std::string TheSender;
@@ -122,6 +129,7 @@ namespace OpenWifi {
}
Message.setSender( TheSender );
Logger_.information(Poco::format("Sending message to:%s from %s",Recipient,TheSender));
Message.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient));
Message.setSubject(Msg.Attrs.find(SUBJECT)->second);
@@ -138,26 +146,21 @@ namespace OpenWifi {
auto Logo = Msg.Attrs.find(LOGO);
if(Logo!=Msg.Attrs.end()) {
try {
Poco::File LogoFile(AuthService::GetLogoAssetFileName());
std::ifstream IF(LogoFile.path());
std::ostringstream OS;
Poco::StreamCopier::copyStream(IF, OS);
Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png"));
} catch (...) {
Logger_.warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName()));
}
Poco::File LogoFile(AuthService::GetLogoAssetFileName());
std::ifstream IF(LogoFile.path());
std::ostringstream OS;
Poco::StreamCopier::copyStream(IF, OS);
Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/jpeg"));
}
Poco::SharedPtr<Poco::Net::AcceptCertificateHandler> ptrHandler_ = new Poco::Net::AcceptCertificateHandler(false);
Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_);
Poco::Net::Context::Params P;
auto ptrContext = Poco::AutoPtr<Poco::Net::Context>
(new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "",
Poco::Net::Context::VERIFY_RELAXED, 9, true,
"ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"));
Poco::Net::SSLManager::instance().initializeClient(nullptr,
ptrHandler_,
&ptrHandler_,
ptrContext);
session.login();
session.startTLS(ptrContext);
@@ -174,9 +177,6 @@ namespace OpenWifi {
{
Logger_.log(E);
}
catch (const std::exception &E) {
Logger_.warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what()));
}
return false;
}

View File

@@ -59,8 +59,8 @@ namespace OpenWifi {
class SMTPMailerService : public SubSystemServer, Poco::Runnable {
public:
static SMTPMailerService *instance() {
static auto * instance_ = new SMTPMailerService;
return instance_;
static SMTPMailerService instance;
return & instance;
}
struct MessageEvent {
@@ -71,35 +71,41 @@ namespace OpenWifi {
MessageAttributes Attrs;
};
struct MessageCacheEntry {
uint64_t LastRequest=0;
uint64_t HowManyRequests=0;
};
void run() override;
int Start() override;
void Stop() override;
bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs);
bool SendIt(const MessageEvent &Msg);
void LoadMyConfig();
void reinitialize(Poco::Util::Application &self) override;
bool Enabled() const { return Enabled_; }
private:
std::string MailHost_;
std::string Sender_;
int MailHostPort_=25;
int MailRetry_=2*60;
int MailAbandon_=2*60*20;
std::string SenderLoginUserName_;
std::string SenderLoginPassword_;
std::string LoginMethod_ = "login";
std::string LogoFileName_;
std::string TemplateDir_;
std::list<MessageEvent> Messages_;
std::list<MessageEvent> PendingMessages_;
std::map<std::string,MessageCacheEntry> Cache_;
Poco::Thread SenderThr_;
std::atomic_bool Running_=false;
bool Enabled_=false;
Poco::Net::AcceptCertificateHandler ptrHandler_;
SMTPMailerService() noexcept:
SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer")
SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer"),
ptrHandler_(false)
{
std::string E{"SHA512"};
}
};

View File

@@ -16,28 +16,12 @@ namespace OpenWifi {
StorageClass::Start();
Create_Tables();
InitializeDefaultUser();
Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer);
Timer_.setStartInterval( 5 * 60 * 1000); // first run in 5 minutes
Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours
Timer_.start(*Archivercallback_);
return 0;
}
void Storage::Stop() {
Logger_.notice("Stopping.");
Timer_.stop();
StorageClass::Stop();
}
void Archiver::onTimer(Poco::Timer &timer) {
Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER");
logger.information("Squiggy the DB: removing old tokens.");
StorageService()->CleanExpiredTokens();
logger.information("Squiggy the DB: removing old actionLinks.");
StorageService()->CleanOldActionLinks();
}
}
// namespace

View File

@@ -13,8 +13,6 @@
#include "framework/StorageClass.h"
#include "AuthService.h"
#include "Poco/Timer.h"
namespace OpenWifi {
static const std::string AllEmailTemplatesFieldsForCreation {
@@ -29,12 +27,6 @@ namespace OpenWifi {
};
class Archiver {
public:
void onTimer(Poco::Timer & timer);
private:
};
class Storage : public StorageClass {
public:
@@ -84,8 +76,8 @@ namespace OpenWifi {
}
static Storage *instance() {
static auto * instance_ = new Storage;
return instance_;
static Storage instance;
return &instance;
}
int Start() override;
@@ -112,12 +104,12 @@ namespace OpenWifi {
bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name);
bool DeleteAvatar(const std::string & Admin, std::string &Id);
bool AddToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut);
bool AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut);
bool RevokeToken( std::string & Token );
bool IsTokenRevoked( std::string & Token );
bool CleanExpiredTokens();
bool CleanRevokedTokens( uint64_t Oldest );
bool RevokeAllTokens( std::string & UserName );
bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate);
bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo);
/*
* All ActionLinks functions
@@ -129,7 +121,6 @@ namespace OpenWifi {
bool SentAction(std::string &ActionId);
bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A);
bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200);
void CleanOldActionLinks();
private:
int Create_Tables();
@@ -137,13 +128,6 @@ namespace OpenWifi {
int Create_AvatarTable();
int Create_TokensTable();
int Create_ActionLinkTable();
Poco::Timer Timer_;
Archiver Archiver_;
std::unique_ptr<Poco::TimerCallback<Archiver>> Archivercallback_;
/// This is to support a mistake that was deployed...
void ReplaceOldDefaultUUID();
};
inline Storage * StorageService() { return Storage::instance(); };

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +0,0 @@
//
// Created by stephane bourque on 2021-09-14.
//
#ifndef OWPROV_CONFIGURATIONVALIDATOR_H
#define OWPROV_CONFIGURATIONVALIDATOR_H
#include <nlohmann/json-schema.hpp>
#include "framework/MicroService.h"
using nlohmann::json;
using nlohmann::json_schema::json_validator;
namespace OpenWifi {
class ConfigurationValidator : public SubSystemServer {
public:
static ConfigurationValidator *instance() {
if(instance_== nullptr)
instance_ = new ConfigurationValidator;
return instance_;
}
bool Validate(const std::string &C, std::string &Error);
static void my_format_checker(const std::string &format, const std::string &value);
int Start() override;
void Stop() override;
void reinitialize(Poco::Util::Application &self) override;
private:
static ConfigurationValidator * instance_;
bool Initialized_=false;
bool Working_=false;
void Init();
std::unique_ptr<json_validator> Validator_=std::make_unique<json_validator>(nullptr, my_format_checker);
ConfigurationValidator():
SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") {
}
};
inline ConfigurationValidator * ConfigurationValidator() { return ConfigurationValidator::instance(); }
inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); }
}
#endif //OWPROV_CONFIGURATIONVALIDATOR_H

View File

@@ -69,8 +69,6 @@ using namespace std::chrono_literals;
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "nlohmann/json.hpp"
#include "ow_version.h"
namespace OpenWifi {
enum UNAUTHORIZED_REASON {
@@ -82,9 +80,7 @@ namespace OpenWifi {
PASSWORD_INVALID,
INTERNAL_ERROR,
ACCESS_DENIED,
INVALID_TOKEN,
EXPIRED_TOKEN,
RATE_LIMIT_EXCEEDED
INVALID_TOKEN
};
class AppServiceRegistry {
@@ -92,8 +88,8 @@ namespace OpenWifi {
inline AppServiceRegistry();
static AppServiceRegistry & instance() {
static AppServiceRegistry *instance_= new AppServiceRegistry;
return *instance_;
static AppServiceRegistry instance;
return instance;
}
inline ~AppServiceRegistry() {
@@ -1437,8 +1433,8 @@ namespace OpenWifi {
};
static RESTAPI_RateLimiter *instance() {
static RESTAPI_RateLimiter * instance_ = new RESTAPI_RateLimiter;
return instance_;
static RESTAPI_RateLimiter instance;
return &instance;
}
inline int Start() final { return 0;};
@@ -1448,18 +1444,18 @@ namespace OpenWifi {
Poco::URI uri(R.getURI());
auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
auto E = Cache_.get(H);
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
const auto p1 = std::chrono::system_clock::now();
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(p1.time_since_epoch()).count();
if(E.isNull()) {
Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString()));
return false;
}
if((Now-E->Start)<Period) {
E->Count++;
Cache_.update(H,E);
if(E->Count > MaxCalls) {
Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString()));
if(E->Count > MaxCalls)
return true;
}
return false;
}
E->Start = Now;
@@ -1527,23 +1523,20 @@ namespace OpenWifi {
Request = &RequestIn;
Response = &ResponseIn;
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) {
return UnAuthorized("Rate limit exceeded.",RATE_LIMIT_EXCEEDED);
}
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls))
return;
if (!ContinueProcessing())
return;
bool Expired=false;
if (AlwaysAuthorize_ && !IsAuthorized(Expired)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken, EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::InvalidCredentials, ACCESS_DENIED);
if (AlwaysAuthorize_ && !IsAuthorized()) {
return;
}
std::string Reason;
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
return UnAuthorized(Reason, ACCESS_DENIED);
UnAuthorized(Reason, ACCESS_DENIED);
return;
}
ParseParameters();
@@ -1881,7 +1874,7 @@ namespace OpenWifi {
return true;
}
inline bool IsAuthorized(bool & Expired);
inline bool IsAuthorized();
inline void ReturnObject(Poco::JSON::Object &Object) {
PrepareResponse();
@@ -1902,7 +1895,7 @@ namespace OpenWifi {
QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0);
QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0);
QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0);
QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 1);
QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100);
QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, "");
QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, "");
@@ -1914,7 +1907,7 @@ namespace OpenWifi {
QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false);
if(QB_.Offset<1)
QB_.Offset=0;
QB_.Offset=1;
return true;
}
@@ -2083,50 +2076,6 @@ namespace OpenWifi {
Poco::JSON::Object Body_;
};
class KafkaProducer : public Poco::Runnable {
public:
inline void run();
void Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void Stop() {
if(Running_) {
Running_=false;
Worker_.wakeUp();
Worker_.join();
}
}
private:
std::mutex Mutex_;
Poco::Thread Worker_;
std::atomic_bool Running_=false;
};
class KafkaConsumer : public Poco::Runnable {
public:
inline void run();
void Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void Stop() {
if(Running_) {
Running_=false;
Worker_.wakeUp();
Worker_.join();
}
}
private:
std::mutex Mutex_;
Poco::Thread Worker_;
std::atomic_bool Running_=false;
};
class KafkaManager : public SubSystemServer {
public:
struct KMessage {
@@ -2135,32 +2084,33 @@ namespace OpenWifi {
PayLoad;
};
friend class KafkaConsumer;
friend class KafkaProducer;
inline void initialize(Poco::Util::Application & self) override;
static KafkaManager *instance() {
static KafkaManager * instance_ = new KafkaManager;
return instance_;
static KafkaManager instance;
return &instance;
}
inline int Start() override {
if(!KafkaEnabled_)
return 0;
ConsumerThr_.Start();
ProducerThr_.Start();
ProducerThr_ = std::make_unique<std::thread>([this]() { this->ProducerThr(); });
ConsumerThr_ = std::make_unique<std::thread>([this]() { this->ConsumerThr(); });
return 0;
}
inline void Stop() override {
if(KafkaEnabled_) {
ProducerThr_.Stop();
ConsumerThr_.Stop();
ProducerRunning_ = ConsumerRunning_ = false;
ProducerThr_->join();
ConsumerThr_->join();
return;
}
}
inline void ProducerThr();
inline void ConsumerThr();
inline void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true ) {
if(KafkaEnabled_) {
std::lock_guard G(Mutex_);
@@ -2213,13 +2163,18 @@ namespace OpenWifi {
// void WakeUp();
private:
std::mutex ProducerMutex_;
std::mutex ConsumerMutex_;
bool KafkaEnabled_ = false;
std::atomic_bool ProducerRunning_ = false;
std::atomic_bool ConsumerRunning_ = false;
std::queue<KMessage> Queue_;
std::string SystemInfoWrapper_;
std::unique_ptr<std::thread> ConsumerThr_;
std::unique_ptr<std::thread> ProducerThr_;
int FunctionId_=1;
Types::NotifyTable Notifiers_;
KafkaProducer ProducerThr_;
KafkaConsumer ConsumerThr_;
std::unique_ptr<cppkafka::Configuration> Config_;
inline void PartitionAssignment(const cppkafka::TopicPartitionList& partitions) {
Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition()));
@@ -2244,8 +2199,8 @@ namespace OpenWifi {
}
static AuthClient *instance() {
static AuthClient * instance_ = new AuthClient;
return instance_;
static AuthClient instance;
return &instance;
}
inline int Start() override {
@@ -2253,20 +2208,25 @@ namespace OpenWifi {
}
inline void Stop() override {
Cache_.clear();
}
inline void RemovedCachedToken(const std::string &Token) {
std::lock_guard G(Mutex_);
Cache_.remove(Token);
UserCache_.erase(Token);
}
inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) {
return ((T.expires_in_+T.created_)<std::time(nullptr));
}
inline bool RetrieveTokenInformation(const std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) {
try {
inline bool IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
std::lock_guard G(Mutex_);
auto User = UserCache_.find(SessionToken);
if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) {
UInfo = User->second;
return true;
} else {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("token",SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY,
@@ -2276,39 +2236,49 @@ namespace OpenWifi {
Poco::JSON::Object::Ptr Response;
if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo")) {
UInfo.from_json(Response);
if(IsTokenExpired(UInfo.webtoken)) {
Expired = true;
return false;
}
Expired = false;
Cache_.update(SessionToken, UInfo);
return true;
SecurityObjects::UserInfoAndPolicy P;
P.from_json(Response);
UserCache_[SessionToken] = P;
UInfo = P;
}
return true;
}
} catch (...) {
}
Expired = false;
return false;
}
inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) {
auto User = Cache_.get(SessionToken);
if(!User.isNull()) {
if(IsTokenExpired(User->webtoken)) {
Expired = true;
return false;
inline bool IsTokenAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo) {
std::lock_guard G(Mutex_);
auto User = UserCache_.find(SessionToken);
if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) {
UInfo = User->second;
return true;
} else {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("token",SessionToken));
OpenAPIRequestGet Req(uSERVICE_SECURITY,
"/api/v1/validateToken",
QueryData,
5000);
Poco::JSON::Object::Ptr Response;
if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo")) {
SecurityObjects::UserInfoAndPolicy P;
P.from_json(Response);
UserCache_[SessionToken] = P;
UInfo = P;
}
return true;
}
Expired = false;
UInfo = *User;
return true;
}
return RetrieveTokenInformation(SessionToken, UInfo, Expired);
return false;
}
private:
Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{1024,1200000 };
OpenWifi::SecurityObjects::UserInfoCache UserCache_;
};
inline AuthClient * AuthClient() { return AuthClient::instance(); }
@@ -2368,14 +2338,14 @@ namespace OpenWifi {
}
static ALBHealthCheckServer *instance() {
static ALBHealthCheckServer * instance = new ALBHealthCheckServer;
return instance;
static ALBHealthCheckServer instance;
return &instance;
}
inline int Start() override;
inline void Stop() override {
if(Running_)
if(Server_)
Server_->stop();
}
@@ -2383,7 +2353,6 @@ namespace OpenWifi {
std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
int Port_ = 0;
std::atomic_bool Running_=false;
};
inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
@@ -2398,18 +2367,17 @@ namespace OpenWifi {
class RESTAPI_server : public SubSystemServer {
public:
static RESTAPI_server *instance() {
static RESTAPI_server *instance_ = new RESTAPI_server;
return instance_;
static RESTAPI_server instance;
return &instance;
}
int Start() override;
inline void Stop() override {
Logger_.information("Stopping ");
for( const auto & svr : RESTServers_ )
svr->stop();
Pool_.joinAll();
RESTServers_.clear();
}
}
inline void reinitialize(Poco::Util::Application &self) override;
inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) {
@@ -2464,7 +2432,7 @@ namespace OpenWifi {
if(!Svr.RootCA().empty())
Svr.LogCas(Logger_);
Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams;
auto Params = new Poco::Net::HTTPServerParams;
Params->setMaxThreads(50);
Params->setMaxQueued(200);
Params->setKeepAlive(true);
@@ -2481,8 +2449,8 @@ namespace OpenWifi {
public:
static RESTAPI_InternalServer *instance() {
static RESTAPI_InternalServer *instance_ = new RESTAPI_InternalServer;
return instance_;
static RESTAPI_InternalServer instance;
return &instance;
}
inline int Start() override;
@@ -2490,7 +2458,7 @@ namespace OpenWifi {
Logger_.information("Stopping ");
for( const auto & svr : RESTServers_ )
svr->stop();
Pool_.stopAll();
RESTServers_.clear();
}
inline void reinitialize(Poco::Util::Application &self) override;
@@ -2507,6 +2475,7 @@ namespace OpenWifi {
RESTAPI_InternalServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi")
{
}
};
inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); };
@@ -2524,7 +2493,7 @@ namespace OpenWifi {
}
private:
Poco::Logger & Logger_;
RESTAPI_GenericServer & Server_;
RESTAPI_GenericServer &Server_;
};
inline int RESTAPI_InternalServer::Start() {
@@ -2585,13 +2554,11 @@ namespace OpenWifi {
DAEMON_BUS_TIMER(BusTimer),
SubSystems_(std::move(Subsystems)) {
instance_ = this;
RandomEngine_.seed(std::chrono::steady_clock::now().time_since_epoch().count());
}
[[nodiscard]] std::string Version() { return Version_; }
[[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; }
[[nodiscard]] bool Debug() const { return DebugMode_; }
[[nodiscard]] uint64_t ID() const { return ID_; }
[[nodiscard]] std::string Hash() const { return MyHash_; };
@@ -2604,13 +2571,6 @@ namespace OpenWifi {
static inline uint64_t GetPID() { return Poco::Process::id(); };
[[nodiscard]] inline const std::string GetPublicAPIEndPoint() { return MyPublicEndPoint_ + "/api/v1"; };
[[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;};
[[nodiscard]] inline uint64_t Random(uint64_t ceiling) {
return (RandomEngine_() % ceiling);
}
[[nodiscard]] inline uint64_t Random(uint64_t min, uint64_t max) {
return ((RandomEngine_() % (max-min)) + min);
}
inline void Exit(int Reason);
inline void BusMessageReceived(const std::string &Key, const std::string & Message);
@@ -2632,7 +2592,7 @@ namespace OpenWifi {
inline void InitializeSubSystemServers();
inline void StartSubSystemServers();
inline void StopSubSystemServers();
[[nodiscard]] static inline std::string CreateUUID();
[[nodiscard]] inline std::string CreateUUID();
inline bool SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
inline void Reload(const std::string &Sub);
inline Types::StringVec GetSubSystems() const;
@@ -2662,10 +2622,9 @@ namespace OpenWifi {
std::string ConfigFileName_;
Poco::UUIDGenerator UUIDGenerator_;
uint64_t ID_ = 1;
Poco::SharedPtr<Poco::Crypto::RSAKey> AppKey_;
Poco::SharedPtr<Poco::Crypto::RSAKey> AppKey_ = nullptr;
bool DebugMode_ = false;
std::string DataDir_;
std::string WWWAssetsDir_;
SubSystemVec SubSystems_;
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
Poco::Crypto::Cipher * Cipher_ = nullptr;
@@ -2675,10 +2634,9 @@ namespace OpenWifi {
std::string MyPrivateEndPoint_;
std::string MyPublicEndPoint_;
std::string UIURI_;
std::string Version_{ OW_VERSION::VERSION + "("+ OW_VERSION::BUILD + ")" + " - " + OW_VERSION::HASH };
std::string Version_{std::string(APP_VERSION) + "("+ BUILD_NUMBER + ")"};
BusEventManager BusEventManager_;
std::mutex InfraMutex_;
std::default_random_engine RandomEngine_;
std::string DAEMON_PROPERTIES_FILENAME;
std::string DAEMON_ROOT_ENV_VAR;
@@ -2855,9 +2813,6 @@ namespace OpenWifi {
logger().log(E);
}
}
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets","");
if(WWWAssetsDir_.empty())
WWWAssetsDir_ = DataDir_;
LoadMyConfig();
@@ -2964,42 +2919,13 @@ namespace OpenWifi {
inline void MicroService::StopSubSystemServers() {
BusEventManager_.Stop();
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) {
(*i)->Stop();
}
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i)
(*i)->Stop();
}
[[nodiscard]] inline std::string MicroService::CreateUUID() {
static std::random_device rd;
static std::mt19937_64 gen(rd());
static std::uniform_int_distribution<> dis(0, 15);
static std::uniform_int_distribution<> dis2(8, 11);
std::stringstream ss;
int i;
ss << std::hex;
for (i = 0; i < 8; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 4; i++) {
ss << dis(gen);
}
ss << "-4";
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
ss << dis2(gen);
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 12; i++) {
ss << dis(gen);
};
return ss.str();
}
return UUIDGenerator_.create().toString();
}
inline bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
try {
@@ -3012,6 +2938,7 @@ namespace OpenWifi {
}
return true;
} else {
// std::cout << "Sub:" << SubSystem << " Level:" << Level << std::endl;
for (auto i : SubSystems_) {
if (Sub == Poco::toLower(i->Name())) {
i->Logger().setLevel(P);
@@ -3161,6 +3088,7 @@ namespace OpenWifi {
StartSubSystemServers();
waitForTerminationRequest();
StopSubSystemServers();
logger.notice(Poco::format("Stopped %s...",DAEMON_APP_NAME));
}
@@ -3240,7 +3168,6 @@ namespace OpenWifi {
inline int ALBHealthCheckServer::Start() {
if(MicroService::instance().ConfigGetBool("alb.enable",false)) {
Running_=true;
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
auto Params = new Poco::Net::HTTPServerParams;
@@ -3285,42 +3212,41 @@ namespace OpenWifi {
KafkaEnabled_ = MicroService::instance().ConfigGetBool("openwifi.kafka.enable",false);
}
inline void KafkaProducer::run() {
inline void KafkaManager::ProducerThr() {
cppkafka::Configuration Config({
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
});
KafkaManager()->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
std::to_string(MicroService::instance().ID()) +
R"lit( , "host" : ")lit" + MicroService::instance().PrivateEndPoint() +
R"lit(" } , "payload" : )lit" ;
cppkafka::Producer Producer(Config);
Running_ = true;
while(Running_) {
ProducerRunning_ = true;
while(ProducerRunning_) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
try
{
std::lock_guard G(Mutex_);
std::lock_guard G(ProducerMutex_);
auto Num=0;
while (!KafkaManager()->Queue_.empty()) {
const auto M = KafkaManager()->Queue_.front();
while (!Queue_.empty()) {
const auto M = Queue_.front();
Producer.produce(
cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad));
KafkaManager()->Queue_.pop();
Queue_.pop();
Num++;
}
if(Num)
Producer.flush();
} catch (const cppkafka::HandleException &E ) {
KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()}));
Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()}));
} catch (const Poco::Exception &E) {
KafkaManager()->Logger_.log(E);
Logger_.log(E);
}
}
Producer.flush();
}
inline void KafkaConsumer::run() {
inline void KafkaManager::ConsumerThr() {
cppkafka::Configuration Config({
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") },
@@ -3340,13 +3266,13 @@ namespace OpenWifi {
cppkafka::Consumer Consumer(Config);
Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) {
KafkaManager()->Logger_.information(Poco::format("Partition assigned: %Lu...",
Logger_.information(Poco::format("Partition assigned: %Lu...",
(uint64_t)partitions.front().get_partition()));
}
});
Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) {
KafkaManager()->Logger_.information(Poco::format("Partition revocation: %Lu...",
Logger_.information(Poco::format("Partition revocation: %Lu...",
(uint64_t)partitions.front().get_partition()));
}
});
@@ -3355,13 +3281,13 @@ namespace OpenWifi {
auto BatchSize = MicroService::instance().ConfigGetInt("openwifi.kafka.consumer.batchsize",20);
Types::StringVec Topics;
for(const auto &i:KafkaManager()->Notifiers_)
for(const auto &i:Notifiers_)
Topics.push_back(i.first);
Consumer.subscribe(Topics);
Running_ = true;
while(Running_) {
ConsumerRunning_ = true;
while(ConsumerRunning_) {
try {
std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200));
for(auto const &Msg:MsgVec) {
@@ -3369,14 +3295,14 @@ namespace OpenWifi {
continue;
if (Msg.get_error()) {
if (!Msg.is_eof()) {
KafkaManager()->Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string()));
Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string()));
}if(!AutoCommit)
Consumer.async_commit(Msg);
continue;
}
std::lock_guard G(Mutex_);
auto It = KafkaManager()->Notifiers_.find(Msg.get_topic());
if (It != KafkaManager()->Notifiers_.end()) {
std::lock_guard G(ConsumerMutex_);
auto It = Notifiers_.find(Msg.get_topic());
if (It != Notifiers_.end()) {
Types::TopicNotifyFunctionList &FL = It->second;
std::string Key{Msg.get_key()};
std::string Payload{Msg.get_payload()};
@@ -3389,12 +3315,11 @@ namespace OpenWifi {
Consumer.async_commit(Msg);
}
} catch (const cppkafka::HandleException &E) {
KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()}));
Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()}));
} catch (const Poco::Exception &E) {
KafkaManager()->Logger_.log(E);
Logger_.log(E);
}
}
Consumer.unsubscribe();
}
inline void RESTAPI_server::reinitialize(Poco::Util::Application &self) {
@@ -3615,9 +3540,11 @@ namespace OpenWifi {
if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response OK" << std::endl;
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response: " << Response.getStatus() << std::endl;
}
return Response.getStatus();
}
@@ -3663,9 +3590,11 @@ namespace OpenWifi {
if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response OK" << std::endl;
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response: " << Response.getStatus() << std::endl;
}
return Response.getStatus();
}
@@ -3691,9 +3620,9 @@ namespace OpenWifi {
}
#ifdef TIP_SECURITY_SERVICE
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
#endif
inline bool RESTAPIHandler::IsAuthorized( bool & Expired ) {
inline bool RESTAPIHandler::IsAuthorized() {
if(Internal_) {
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
if(!Allowed) {
@@ -3723,9 +3652,9 @@ namespace OpenWifi {
}
}
#ifdef TIP_SECURITY_SERVICE
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired)) {
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_)) {
#else
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired)) {
if (AuthClient()->IsAuthorized(*Request, SessionToken_, UserInfo_)) {
#endif
if(Server_.LogIt(Request->getMethod(),true)) {
Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s",
@@ -3742,6 +3671,7 @@ namespace OpenWifi {
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->getMethod(), Request->getURI()));
}
UnAuthorized("Invalid token", INVALID_TOKEN);
}
return false;
}

View File

@@ -59,7 +59,6 @@ namespace OpenWifi::RESTAPI::Errors {
static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
static const std::string MissingAuthenticationInformation{"Missing authentication information."};
static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
static const std::string ExpiredToken{"Token has expired, user must login."};
}
#endif //OWPROV_RESTAPI_ERRORS_H

View File

@@ -2,7 +2,8 @@
// Created by stephane bourque on 2021-10-06.
//
#pragma once
#ifndef OPENWIFI_STORAGE_H
#define OPENWIFI_STORAGE_H
#include "Poco/Data/Session.h"
#include "Poco/Data/SessionPool.h"
@@ -25,6 +26,13 @@ namespace OpenWifi {
class StorageClass : public SubSystemServer {
public:
/* static StorageClass *instance() {
if (instance_ == nullptr) {
instance_ = new StorageClass;
}
return instance_;
}
*/
StorageClass() noexcept:
SubSystemServer("StorageClass", "STORAGE-SVR", "storage")
{
@@ -48,18 +56,18 @@ namespace OpenWifi {
}
void Stop() override {
Pool_->shutdown();
}
[[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
if(dbType_==sqlite) {
return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " ";
return " LIMIT " + std::to_string(From-1) + ", " + std::to_string(HowMany) + " ";
} else if(dbType_==pgsql) {
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " ";
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " ";
} else if(dbType_==mysql) {
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " ";
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " ";
}
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " ";
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " ";
}
inline std::string ConvertParams(const std::string & S) const {
@@ -88,11 +96,11 @@ namespace OpenWifi {
inline int Setup_PostgreSQL();
protected:
Poco::SharedPtr<Poco::Data::SessionPool> Pool_;
Poco::Data::SQLite::Connector SQLiteConn_;
Poco::Data::PostgreSQL::Connector PostgresConn_;
Poco::Data::MySQL::Connector MySQLConn_;
DBType dbType_ = sqlite;
std::unique_ptr<Poco::Data::SessionPool> Pool_;
std::unique_ptr<Poco::Data::SQLite::Connector> SQLiteConn_;
std::unique_ptr<Poco::Data::PostgreSQL::Connector> PostgresConn_;
std::unique_ptr<Poco::Data::MySQL::Connector> MySQLConn_;
DBType dbType_ = sqlite;
};
#ifdef SMALL_BUILD
@@ -106,8 +114,9 @@ namespace OpenWifi {
auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db");
auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64);
auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60);
SQLiteConn_.registerConnector();
Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 4, NumSessions, IdleTime));
SQLiteConn_ = std::make_unique<Poco::Data::SQLite::Connector>();
SQLiteConn_->registerConnector();
Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_->name(), DBName, 4, NumSessions, IdleTime);
return 0;
}
@@ -130,8 +139,9 @@ namespace OpenWifi {
";port=" + Port +
";compress=true;auto-reconnect=true";
MySQLConn_.registerConnector();
Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(MySQLConn_.name(), ConnectionStr, 4, NumSessions, IdleTime));
MySQLConn_ = std::make_unique<Poco::Data::MySQL::Connector>();
MySQLConn_->registerConnector();
Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
return 0;
}
@@ -156,11 +166,14 @@ namespace OpenWifi {
" port=" + Port +
" connect_timeout=" + ConnectionTimeout;
PostgresConn_.registerConnector();
Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(PostgresConn_.name(), ConnectionStr, 4, NumSessions, IdleTime));
PostgresConn_ = std::make_unique<Poco::Data::PostgreSQL::Connector>();
PostgresConn_->registerConnector();
Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
return 0;
}
#endif
}
#endif //OPENWIFI_STORAGE_H

View File

@@ -1,13 +0,0 @@
//
// Created by stephane bourque on 2021-12-06.
//
#pragma once
#include <string>
namespace OW_VERSION {
inline static const std::string VERSION{"@CMAKE_PROJECT_VERSION@"};
inline static const std::string BUILD{"@BUILD_NUM@"};
inline static const std::string HASH{"@GIT_HASH@"};
}

View File

@@ -183,19 +183,4 @@ namespace OpenWifi {
return false;
}
void Storage::CleanOldActionLinks() {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
uint64_t CutOff = std::time(nullptr) - (30 * 24 * 60 * 60);
std::string St{"DELETE from ActionLinks where Created<=?"};
Delete << ConvertParams(St),
Poco::Data::Keywords::use(CutOff);
Delete.execute();
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
}
}

View File

@@ -15,7 +15,7 @@ namespace OpenWifi {
"RevocationDate BIGINT "
*/
bool Storage::AddToken(std::string &UserID, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) {
bool Storage::AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Insert(Sess);
@@ -29,7 +29,7 @@ namespace OpenWifi {
Poco::Data::Keywords::use(Token),
Poco::Data::Keywords::use(RefreshToken),
Poco::Data::Keywords::use(TokenType),
Poco::Data::Keywords::use(UserID),
Poco::Data::Keywords::use(UserName),
Poco::Data::Keywords::use(Now),
Poco::Data::Keywords::use(Expires),
Poco::Data::Keywords::use(TimeOut),
@@ -42,24 +42,29 @@ namespace OpenWifi {
return false;
}
bool Storage::GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate) {
bool Storage::GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
RevocationDate = 0 ;
std::string St2{"SELECT " + AllTokensFieldsForSelect + " From Tokens WHERE Token=?"};
uint32_t RevocationDate = 0 ;
std::string St2{"SELECT " + AllTokensValuesForSelect + " From Tokens WHERE Token=?"};
Select << ConvertParams(St2),
Poco::Data::Keywords::into(UInfo.webtoken.access_token_),
Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_),
Poco::Data::Keywords::into(UInfo.webtoken.token_type_),
Poco::Data::Keywords::into(UInfo.userinfo.Id),
Poco::Data::Keywords::into(UInfo.userinfo.email),
Poco::Data::Keywords::into(UInfo.webtoken.created_),
Poco::Data::Keywords::into(UInfo.webtoken.expires_in_),
Poco::Data::Keywords::into(UInfo.webtoken.idle_timeout_),
Poco::Data::Keywords::into(RevocationDate),
Poco::Data::Keywords::use(Token);
Select.execute();
if(RevocationDate>0)
return false;
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
@@ -111,15 +116,15 @@ namespace OpenWifi {
return false;
}
bool Storage::CleanExpiredTokens() {
bool Storage::CleanRevokedTokens(uint64_t Oldest) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
uint64_t Now = std::time(nullptr);
std::string St2{"DELETE From Tokens WHERE (Created+Expires) <= ?"};
std::string St2{"DELETE From Tokens WHERE Created <= ?"};
Delete << ConvertParams(St2),
Poco::Data::Keywords::use(Now);
Poco::Data::Keywords::use(Oldest);
Delete.execute();
return true;
} catch (const Poco::Exception &E) {
@@ -128,14 +133,14 @@ namespace OpenWifi {
return false;
}
bool Storage::RevokeAllTokens(std::string & UserId) {
bool Storage::RevokeAllTokens(std::string & username) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
std::string St2{"DELETE From Tokens WHERE Username=?"};
Delete << ConvertParams(St2),
Poco::Data::Keywords::use(UserId);
Poco::Data::Keywords::use(username);
Delete.execute();
return true;
} catch(const Poco::Exception &E) {

View File

@@ -80,23 +80,7 @@ namespace OpenWifi {
return true;
}
std::string OldDefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"};
std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"};
void Storage::ReplaceOldDefaultUUID() {
try {
Poco::Data::Session Sess = Pool_->get();
std::string St1{"update users set id=? where id=?"};
Poco::Data::Statement Update(Sess);
Update << ConvertParams(St1),
Poco::Data::Keywords::use(NewDefaultUseridStockUUID),
Poco::Data::Keywords::use(OldDefaultUseridStockUUID);
Update.execute();
} catch (...) {
}
}
std::string DefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"};
// if we do not find a default user, then we need to create one based on the
// property file. We must set its flag to "must change password", this user has root privilege.
@@ -105,13 +89,12 @@ namespace OpenWifi {
SecurityObjects::UserInfo U;
bool DefaultUserCreated = false;
ReplaceOldDefaultUUID();
AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated);
if(!GetUserById(NewDefaultUseridStockUUID,U) && !DefaultUserCreated) {
if(!GetUserById(DefaultUseridStockUUID,U) && !DefaultUserCreated) {
U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password","");
U.lastPasswords.push_back(U.currentPassword);
U.email = MicroService::instance().ConfigGetString("authentication.default.username","");
U.Id = NewDefaultUseridStockUUID;
U.Id = DefaultUseridStockUUID;
U.userRole = SecurityObjects::ROOT;
U.creationDate = std::time(nullptr);
U.validated = true;
@@ -149,7 +132,7 @@ namespace OpenWifi {
return false;
if(!PasswordHashedAlready) {
NewUser.Id = MicroService::CreateUUID();
NewUser.Id = MicroService::instance().CreateUUID();
NewUser.creationDate = std::time(nullptr);
}

View File

@@ -15,23 +15,23 @@ namespace OpenWifi {
"description varchar,"
"avatar varchar,"
"email varchar,"
"validated boolean,"
"validated int,"
"validationEmail varchar,"
"validationDate bigint,"
"creationDate bigint,"
"validationURI varchar,"
"changePassword boolean,"
"changePassword int,"
"lastLogin bigint,"
"currentLoginURI varchar,"
"lastPasswordChange bigint,"
"lastEmailCheck bigint,"
"waitingForEmailCheck boolean,"
"waitingForEmailCheck int,"
"locale varchar,"
"notes text,"
"location varchar,"
"owner varchar,"
"suspended boolean,"
"blackListed boolean,"
"suspended int,"
"blackListed int,"
"userRole varchar,"
"userTypeProprietaryInfo text,"
"securityPolicy text,"
@@ -111,23 +111,23 @@ namespace OpenWifi {
std::string, // description;
std::string, // avatar;
std::string, // email;
bool, // bool validated = false;
uint64_t, // bool validated = false;
std::string, // validationEmail;
uint64_t, // validationDate = 0;
uint64_t, // creationDate = 0;
std::string, // validationURI;
bool, // bool changePassword = true;
uint64_t, // bool changePassword = true;
uint64_t, // lastLogin = 0;
std::string, // currentLoginURI;
uint64_t, // lastPasswordChange = 0;
uint64_t, // lastEmailCheck = 0;
bool, // bool waitingForEmailCheck = false;
uint64_t, // bool waitingForEmailCheck = false;
std::string, // locale;
std::string, // notes;
std::string, // location;
std::string, // owner;
bool, // bool suspended = false;
bool, // bool blackListed = false;
uint64_t, // bool suspended = false;
uint64_t, // bool blackListed = false;
std::string, // userRole;
std::string, // userTypeProprietaryInfo;
std::string, // securityPolicy;

View File

@@ -35,7 +35,7 @@ fi
token=""
result_file=result.json
username="tip@ucentral.com"
password="Snoopy99!!!"
password="openwifi"
#username="stephb@incognito.com"
#password="Snoopy98!"
browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl)