mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-31 10:47:48 +00:00 
			
		
		
		
	Compare commits
	
		
			65 Commits
		
	
	
		
			feature/wi
			...
			v2.4.0-RC5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 4510cd034f | ||
|   | af5774ce36 | ||
|   | 2573b8cd4f | ||
|   | 9c5b18a536 | ||
|   | 768c428a67 | ||
|   | 389ceb8b7d | ||
|   | 157f18c117 | ||
|   | 2538f9c768 | ||
|   | 85d998ad76 | ||
|   | a407f2e38d | ||
|   | d0d2be0870 | ||
|   | 78cba562e6 | ||
|   | 350df38c3f | ||
|   | 9e79b73e20 | ||
|   | eb4dfc25f2 | ||
|   | bedec254c5 | ||
|   | 96a566a2b5 | ||
|   | ad2eb1711e | ||
|   | 7244bcb455 | ||
|   | 1db5201418 | ||
|   | 1bc635f553 | ||
|   | 257ac42d7c | ||
|   | acb38e5313 | ||
|   | 7940f0bd85 | ||
|   | 62c06d0bad | ||
|   | 494a199610 | ||
|   | 5307b0b35a | ||
|   | c58728f38e | ||
|   | 1f09c3b619 | ||
|   | d9c6388502 | ||
|   | 5e35906aec | ||
|   | 773618ae07 | ||
|   | cca4441ac7 | ||
|   | 730ca7b292 | ||
|   | 5b4dbb088f | ||
|   | bc11a19ee4 | ||
|   | c835e4d0b9 | ||
|   | f1a2ba90f6 | ||
|   | 5b96ef396f | ||
|   | c204d34bf4 | ||
|   | 4b982bf64b | ||
|   | 37298cc600 | ||
|   | 03619cc900 | ||
|   | f4fc6975e1 | ||
|   | 1f1d596c5a | ||
|   | a5802bf631 | ||
|   | 6471eabc82 | ||
|   | ab6fbaca11 | ||
|   | 1e8e5c18b2 | ||
|   | 3cf23af068 | ||
|   | 1a0b549731 | ||
|   | a835d2e571 | ||
|   | ff7455af24 | ||
|   | 48610bac5d | ||
|   | 7bd5b4d4e6 | ||
|   | e1a51c2a91 | ||
|   | cd0222f765 | ||
|   | 12fddd8bc4 | ||
|   | 9095d831db | ||
|   | 4e8f97df9b | ||
|   | 28808eae93 | ||
|   | 6c24a23863 | ||
|   | 5931c91054 | ||
|   | 9d956c13f7 | ||
|   | ea1adde361 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -18,3 +18,4 @@ _deps | |||||||
| *.csr | *.csr | ||||||
| /cmake-build/ | /cmake-build/ | ||||||
| /smake-build-debug/ | /smake-build-debug/ | ||||||
|  | test_scripts/curl/result.json | ||||||
|   | |||||||
| @@ -30,9 +30,20 @@ else() | |||||||
|     file(WRITE build ${BUILD_NUM}) |     file(WRITE build ${BUILD_NUM}) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| set(BUILD_SHARED_LIBS 1) | 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) | ||||||
|  |  | ||||||
| add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}") | set(BUILD_SHARED_LIBS 1) | ||||||
| add_definitions(-DTIP_SECURITY_SERVICE="1") | add_definitions(-DTIP_SECURITY_SERVICE="1") | ||||||
|  |  | ||||||
| set(Boost_USE_STATIC_LIBS OFF) | set(Boost_USE_STATIC_LIBS OFF) | ||||||
| @@ -50,8 +61,11 @@ 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) | 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 | add_executable( owsec | ||||||
|         build |         build | ||||||
|  |         src/ow_version.h.in | ||||||
|         src/framework/CountryCodes.h |         src/framework/CountryCodes.h | ||||||
|         src/framework/KafkaTopics.h |         src/framework/KafkaTopics.h | ||||||
|         src/framework/MicroService.h |         src/framework/MicroService.h | ||||||
| @@ -90,7 +104,7 @@ add_executable( owsec | |||||||
|         src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h |         src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h | ||||||
|         src/storage/storage_tokens.h |         src/storage/storage_tokens.h | ||||||
|         src/ActionLinkManager.cpp src/ActionLinkManager.h |         src/ActionLinkManager.cpp src/ActionLinkManager.h | ||||||
|         ) |         src/ACLProcessor.h) | ||||||
|  |  | ||||||
| if(NOT SMALL_BUILD) | if(NOT SMALL_BUILD) | ||||||
|     target_link_libraries(owsec PUBLIC |     target_link_libraries(owsec PUBLIC | ||||||
|   | |||||||
| @@ -53,9 +53,12 @@ RUN cmake .. | |||||||
| RUN make | RUN make | ||||||
| RUN make install | RUN make install | ||||||
|  |  | ||||||
|  |  | ||||||
| ADD CMakeLists.txt build /owsec/ | ADD CMakeLists.txt build /owsec/ | ||||||
| ADD cmake /owsec/cmake | ADD cmake /owsec/cmake | ||||||
| ADD src /owsec/src | ADD src /owsec/src | ||||||
|  | ADD .git /owsec/.git | ||||||
|  |  | ||||||
|  |  | ||||||
| WORKDIR /owsec | WORKDIR /owsec | ||||||
| RUN mkdir cmake-build | RUN mkdir cmake-build | ||||||
| @@ -91,6 +94,7 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr | |||||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem |     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem | ||||||
|  |  | ||||||
| COPY readiness_check /readiness_check | COPY readiness_check /readiness_check | ||||||
|  | COPY test_scripts/curl/cli /cli | ||||||
|  |  | ||||||
| EXPOSE 16001 17001 16101 | EXPOSE 16001 17001 16101 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								README.md
									
									
									
									
									
								
							| @@ -98,6 +98,40 @@ to get a sample. The default is | |||||||
| ### `authentication.oldpasswords` | ### `authentication.oldpasswords` | ||||||
| The number of older passwords to keep. Default is 5. | The number of older passwords to keep. Default is 5. | ||||||
|  |  | ||||||
|  | ### Changing default password | ||||||
|  |  | ||||||
|  | On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests. | ||||||
|  |  | ||||||
|  | You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint | ||||||
|  | #export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates) | ||||||
|  | export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username' | ||||||
|  | export OWSEC_DEFAULT_PASSWORD=weLoveWifi # default password __in cleartext__ from property 'authentication.default.password' | ||||||
|  | export OWSEC_NEW_PASSWORD=NewPass123% # new password that must be set for the user (must comply with 'authentication.validation.expression') | ||||||
|  | test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | CLI is also included in Docker image if you want to run it this way: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | export OWSEC=openwifi.wlan.local:16001 | ||||||
|  | #export FLAGS="-k" | ||||||
|  | export OWSEC_DEFAULT_USERNAME=root@system.com | ||||||
|  | export OWSEC_DEFAULT_PASSWORD=weLoveWifi | ||||||
|  | export OWSEC_NEW_PASSWORD=NewPass123% | ||||||
|  | docker run --rm -ti \ | ||||||
|  |   --network=host \ | ||||||
|  |   --env OWSEC \ | ||||||
|  |   --env FLAGS \ | ||||||
|  |   --env OWSEC_DEFAULT_USERNAME \ | ||||||
|  |   --env OWSEC_DEFAULT_PASSWORD \ | ||||||
|  |   --env OWSEC_NEW_PASSWORD \ | ||||||
|  |   tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:main \ | ||||||
|  |   /cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ### Kafka integration | ### Kafka integration | ||||||
| This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running | This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running | ||||||
| in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure. | in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure. | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ fullnameOverride: "" | |||||||
| images: | images: | ||||||
|   owsec: |   owsec: | ||||||
|     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec |     repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec | ||||||
|     tag: main |     tag: v2.4.0-RC5 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
| #    regcred: | #    regcred: | ||||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
|   | |||||||
| @@ -61,6 +61,8 @@ components: | |||||||
|                   - 6     # INTERNAL_ERROR, |                   - 6     # INTERNAL_ERROR, | ||||||
|                   - 7     # ACCESS_DENIED, |                   - 7     # ACCESS_DENIED, | ||||||
|                   - 8     # INVALID_TOKEN |                   - 8     # INVALID_TOKEN | ||||||
|  |                   - 9     # expired token | ||||||
|  |                   - 10    # rate limit exceeded | ||||||
|               ErrorDetails: |               ErrorDetails: | ||||||
|                 type: string |                 type: string | ||||||
|               ErrorDescription: |               ErrorDescription: | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec | |||||||
| openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem | openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem | ||||||
| openwifi.service.key.password = mypassword | openwifi.service.key.password = mypassword | ||||||
|  |  | ||||||
|  | smssender.enabled = false | ||||||
| smssender.provider = aws | smssender.provider = aws | ||||||
| smssender.aws.secretkey = *************************************** | smssender.aws.secretkey = *************************************** | ||||||
| smssender.aws.accesskey = *************************************** | smssender.aws.accesskey = *************************************** | ||||||
| @@ -53,6 +54,7 @@ smssender.aws.region = ************** | |||||||
| # | # | ||||||
| # Security Microservice Specific Section | # Security Microservice Specific Section | ||||||
| # | # | ||||||
|  | mailer.enabled = false | ||||||
| mailer.hostname = smtp.gmail.com | mailer.hostname = smtp.gmail.com | ||||||
| mailer.username = ************************ | mailer.username = ************************ | ||||||
| mailer.password = ************************ | mailer.password = ************************ | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								src/ACLProcessor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/ACLProcessor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | // | ||||||
|  | // 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 | ||||||
| @@ -18,8 +18,8 @@ namespace OpenWifi { | |||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         static ActionLinkManager * instance() { |         static ActionLinkManager * instance() { | ||||||
|             static ActionLinkManager instance; |             static auto * instance_ = new ActionLinkManager; | ||||||
|             return &instance; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int Start() final; |         int Start() final; | ||||||
|   | |||||||
| @@ -56,9 +56,10 @@ namespace OpenWifi { | |||||||
| 		Logger_.notice("Stopping..."); | 		Logger_.notice("Stopping..."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) | 	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) | ||||||
|     { |     { | ||||||
|         std::lock_guard	Guard(Mutex_); |         std::lock_guard	Guard(Mutex_); | ||||||
|  |         Expired = false; | ||||||
| 		try { | 		try { | ||||||
| 		    std::string CallToken; | 		    std::string CallToken; | ||||||
| 		    Poco::Net::OAuth20Credentials Auth(Request); | 		    Poco::Net::OAuth20Credentials Auth(Request); | ||||||
| @@ -67,27 +68,29 @@ namespace OpenWifi { | |||||||
| 		    } | 		    } | ||||||
|  |  | ||||||
| 		    if(!CallToken.empty()) { | 		    if(!CallToken.empty()) { | ||||||
| 		        if(StorageService()->IsTokenRevoked(CallToken)) | 		        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; | 		                    return false; | ||||||
| 		        auto Client = UserCache_.find(CallToken); | 		                Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr); | ||||||
| 		        if( Client == UserCache_.end() ) { | 		                if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) { | ||||||
| 		            if(StorageService()->GetToken(SessionToken,UInfo)) { | 		                    UInfo.webtoken = UInfo2.webtoken; | ||||||
| 		                if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) { | 		                    UserCache_.update(CallToken, UInfo); | ||||||
| 		                    UserCache_[UInfo.webtoken.access_token_] = UInfo; |  | ||||||
| 		                    return true; |  | ||||||
| 		                } |  | ||||||
| 		            } |  | ||||||
| 		            return false; |  | ||||||
| 		        } |  | ||||||
|  |  | ||||||
| 		        if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) { |  | ||||||
| 		                    SessionToken = CallToken; | 		                    SessionToken = CallToken; | ||||||
| 		            UInfo = Client->second ; |  | ||||||
| 		                    return true; | 		                    return true; | ||||||
| 		                } | 		                } | ||||||
|  | 		            } | ||||||
| 		        UserCache_.erase(Client); | 		            return false; | ||||||
| 		        StorageService()->RevokeToken(CallToken); | 		        } | ||||||
|  | 		        if(!Expired) { | ||||||
|  | 		            SessionToken = CallToken; | ||||||
|  | 		            UInfo = *Client ; | ||||||
|  | 		            return true; | ||||||
|  | 		        } | ||||||
|  |                 RevokeToken(CallToken); | ||||||
| 		        return false; | 		        return false; | ||||||
| 		    } | 		    } | ||||||
| 		} catch(const Poco::Exception &E) { | 		} catch(const Poco::Exception &E) { | ||||||
| @@ -96,16 +99,24 @@ namespace OpenWifi { | |||||||
| 		return false; | 		return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void AuthService::RevokeToken(std::string & Token) { | ||||||
|  |         UserCache_.remove(Token); | ||||||
|  |         StorageService()->RevokeToken(Token); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     bool AuthService::DeleteUserFromCache(const std::string &UserName) { |     bool AuthService::DeleteUserFromCache(const std::string &UserName) { | ||||||
|         std::lock_guard		Guard(Mutex_); |         std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|         for(auto i=UserCache_.begin();i!=UserCache_.end();) { |         std::vector<std::string>    OldTokens; | ||||||
|             if (i->second.userinfo.email==UserName) { |  | ||||||
|                 Logout(i->first, false); |         UserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void | ||||||
|                 i = UserCache_.erase(i); |         { if(O.userinfo.email==UserName) | ||||||
|             } else { |             OldTokens.push_back(token); | ||||||
|                 ++i; |         }); | ||||||
|             } |  | ||||||
|  |         for(const auto &i:OldTokens) { | ||||||
|  |             Logout(i,false); | ||||||
|  |             UserCache_.remove(i); | ||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @@ -121,9 +132,6 @@ namespace OpenWifi { | |||||||
|     void AuthService::Logout(const std::string &token, bool EraseFromCache) { |     void AuthService::Logout(const std::string &token, bool EraseFromCache) { | ||||||
| 		std::lock_guard		Guard(Mutex_); | 		std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
| 		if(EraseFromCache) |  | ||||||
| 		    UserCache_.erase(token); |  | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             Poco::JSON::Object Obj; |             Poco::JSON::Object Obj; | ||||||
|             Obj.set("event", "remove-token"); |             Obj.set("event", "remove-token"); | ||||||
| @@ -132,7 +140,7 @@ namespace OpenWifi { | |||||||
|             std::stringstream ResultText; |             std::stringstream ResultText; | ||||||
|             Poco::JSON::Stringifier::stringify(Obj, ResultText); |             Poco::JSON::Stringifier::stringify(Obj, ResultText); | ||||||
|             std::string Tmp{token}; |             std::string Tmp{token}; | ||||||
|             StorageService()->RevokeToken(Tmp); |             RevokeToken(Tmp); | ||||||
|             KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(), |             KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(), | ||||||
|                                         false); |                                         false); | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
| @@ -183,9 +191,9 @@ namespace OpenWifi { | |||||||
|         UInfo.webtoken.username_ = UserName; |         UInfo.webtoken.username_ = UserName; | ||||||
|         UInfo.webtoken.errorCode = 0; |         UInfo.webtoken.errorCode = 0; | ||||||
|         UInfo.webtoken.userMustChangePassword = false; |         UInfo.webtoken.userMustChangePassword = false; | ||||||
|         UserCache_[UInfo.webtoken.access_token_] = UInfo; |         UserCache_.update(UInfo.webtoken.access_token_,UInfo); | ||||||
|         StorageService()->SetLastLogin(UInfo.userinfo.Id); |         StorageService()->SetLastLogin(UInfo.userinfo.Id); | ||||||
|         StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_, |         StorageService()->AddToken(UInfo.userinfo.Id, UInfo.webtoken.access_token_, | ||||||
|                             UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, |                             UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, | ||||||
|                                 UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); |                                 UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); | ||||||
|     } |     } | ||||||
| @@ -253,7 +261,7 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ) |     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) | ||||||
|     { |     { | ||||||
|         std::lock_guard		Guard(Mutex_); |         std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
| @@ -291,6 +299,7 @@ namespace OpenWifi { | |||||||
|             UInfo.userinfo.lastLogin=std::time(nullptr); |             UInfo.userinfo.lastLogin=std::time(nullptr); | ||||||
|             StorageService()->SetLastLogin(UInfo.userinfo.Id); |             StorageService()->SetLastLogin(UInfo.userinfo.Id); | ||||||
|             CreateToken(UserName, UInfo ); |             CreateToken(UserName, UInfo ); | ||||||
|  |  | ||||||
|             return SUCCESS; |             return SUCCESS; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -337,7 +346,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; |         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; | ||||||
|         A.userId = UInfo.email; |         A.userId = UInfo.email; | ||||||
|         A.id = MicroService::instance().CreateUUID(); |         A.id = MicroService::CreateUUID(); | ||||||
|         A.created = std::time(nullptr); |         A.created = std::time(nullptr); | ||||||
|         A.expires = A.created + 24*60*60; |         A.expires = A.created + 24*60*60; | ||||||
|         StorageService()->CreateAction(A); |         StorageService()->CreateAction(A); | ||||||
| @@ -345,16 +354,39 @@ namespace OpenWifi { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo) { |     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { | ||||||
|         std::lock_guard G(Mutex_); |         std::lock_guard G(Mutex_); | ||||||
|         auto It = UserCache_.find(Token); |  | ||||||
|  |  | ||||||
|         if(It==UserCache_.end()) |         Expired = false; | ||||||
|             return false; |  | ||||||
|         WebToken = It->second.webtoken; |         auto Client = UserCache_.get(Token); | ||||||
|         UserInfo = It->second.userinfo; |         if(!Client.isNull()) { | ||||||
|  |             Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr); | ||||||
|  |             WebToken = Client->webtoken; | ||||||
|  |             UserInfo = Client->userinfo; | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         std::string TToken{Token}; | ||||||
|  |         if(StorageService()->IsTokenRevoked(TToken)) { | ||||||
|  |             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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| }  // end of namespace | }  // end of namespace | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| #include "Poco/SHA2Engine.h" | #include "Poco/SHA2Engine.h" | ||||||
| #include "Poco/Crypto/DigestEngine.h" | #include "Poco/Crypto/DigestEngine.h" | ||||||
| #include "Poco/HMACEngine.h" | #include "Poco/HMACEngine.h" | ||||||
|  | #include "Poco/ExpireLRUCache.h" | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
| @@ -44,15 +45,15 @@ namespace OpenWifi{ | |||||||
|         static int AccessTypeToInt(ACCESS_TYPE T); |         static int AccessTypeToInt(ACCESS_TYPE T); | ||||||
|  |  | ||||||
|         static AuthService *instance() { |         static AuthService *instance() { | ||||||
|             static AuthService instance; |             static auto * instance_ = new AuthService; | ||||||
|             return &instance; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int Start() override; |         int Start() override; | ||||||
|         void Stop() override; |         void Stop() override; | ||||||
|  |  | ||||||
|         [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ); |         [[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 ); |         [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); | ||||||
|         void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); |         void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|         [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); |         [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); | ||||||
|         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; |         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; | ||||||
| @@ -60,8 +61,7 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|         bool ValidatePassword(const std::string &pwd); |         bool ValidatePassword(const std::string &pwd); | ||||||
|  |  | ||||||
|         [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo); |         [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); | ||||||
|         [[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request); |  | ||||||
|         [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); |         [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); | ||||||
|         [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); |         [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); | ||||||
|  |  | ||||||
| @@ -75,19 +75,21 @@ namespace OpenWifi{ | |||||||
|         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); | ||||||
|         [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName); |         [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName); | ||||||
|         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); |         [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|  |         void RevokeToken(std::string & Token); | ||||||
|  |  | ||||||
|         [[nodiscard]] static inline const std::string GetLogoAssetURI() { |         [[nodiscard]] static inline const std::string GetLogoAssetURI() { | ||||||
|             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; |             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [[nodiscard]] static inline const std::string GetLogoAssetFileName() { |         [[nodiscard]] static inline const std::string GetLogoAssetFileName() { | ||||||
|             return MicroService::instance().DataDir() + "/wwwassets/the_logo.png"; |             return MicroService::instance().WWWAssetsDir() + "/the_logo.png"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
| 		Poco::JWT::Signer	Signer_; | 		Poco::JWT::Signer	Signer_; | ||||||
| 		Poco::SHA2Engine	SHA2_; | 		Poco::SHA2Engine	SHA2_; | ||||||
| 		SecurityObjects::UserInfoCache UserCache_; | 		Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy>    UserCache_{2048,1200000}; | ||||||
|  | 		// SecurityObjects::UserInfoCache UserCache_; | ||||||
|         std::string         PasswordValidationStr_; |         std::string         PasswordValidationStr_; | ||||||
| 		std::regex          PasswordValidation_; | 		std::regex          PasswordValidation_; | ||||||
| 		uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | 		uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | ||||||
| @@ -119,8 +121,8 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|     inline AuthService * AuthService() { return AuthService::instance(); } |     inline AuthService * AuthService() { return AuthService::instance(); } | ||||||
|  |  | ||||||
|     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) { |     [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired) { | ||||||
|         return AuthService()->IsAuthorized(Request, SessionToken, UInfo ); |         return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } // end of namespace | } // end of namespace | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ namespace OpenWifi { | |||||||
|             return false; |             return false; | ||||||
|  |  | ||||||
|         std::string Challenge = MakeChallenge(); |         std::string Challenge = MakeChallenge(); | ||||||
|         std::string uuid = MicroService::instance().CreateUUID(); |         std::string uuid = MicroService::CreateUUID(); | ||||||
|         uint64_t Created = std::time(nullptr); |         uint64_t Created = std::time(nullptr); | ||||||
|  |  | ||||||
|         ChallengeStart.set("uuid",uuid); |         ChallengeStart.set("uuid",uuid); | ||||||
| @@ -71,8 +71,9 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         auto uuid = ChallengeResponse->get("uuid").toString(); |         auto uuid = ChallengeResponse->get("uuid").toString(); | ||||||
|         auto Hint = Cache_.find(uuid); |         auto Hint = Cache_.find(uuid); | ||||||
|         if(Hint == end(Cache_)) |         if(Hint == end(Cache_)) { | ||||||
|             return false; |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         auto answer = ChallengeResponse->get("answer").toString(); |         auto answer = ChallengeResponse->get("answer").toString(); | ||||||
|         if(Hint->second.Answer!=answer) { |         if(Hint->second.Answer!=answer) { | ||||||
|   | |||||||
| @@ -24,8 +24,8 @@ namespace OpenWifi { | |||||||
|         int Start() override; |         int Start() override; | ||||||
|         void Stop() override; |         void Stop() override; | ||||||
|         static MFAServer *instance() { |         static MFAServer *instance() { | ||||||
|             static MFAServer instance; |             static auto * instance_ = new MFAServer; | ||||||
|             return &instance; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); |         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 bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); | ||||||
|  |  | ||||||
|         static inline std::string MakeChallenge() { |         static inline std::string MakeChallenge() { | ||||||
|             return std::to_string(rand() % 999999); |             return std::to_string(MicroService::instance().Random(1,999999)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ namespace OpenWifi { | |||||||
|                                         Server, |                                         Server, | ||||||
|                                         Internal, |                                         Internal, | ||||||
|                                         false, |                                         false, | ||||||
|                                         true, RateLimit{.Interval=1000,.MaxCalls=5}) {} |                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; }; | ||||||
|         void RequestResetPassword(SecurityObjects::ActionLink &Link); |         void RequestResetPassword(SecurityObjects::ActionLink &Link); | ||||||
|         void CompleteResetPassword(); |         void CompleteResetPassword(); | ||||||
|   | |||||||
| @@ -17,23 +17,38 @@ | |||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     static void FilterCredentials(SecurityObjects::UserInfo & U) { | ||||||
|  |         U.currentPassword.clear(); | ||||||
|  |         U.lastPasswords.clear(); | ||||||
|  |         U.oauthType.clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| 	void RESTAPI_oauth2Handler::DoGet() { | 	void RESTAPI_oauth2Handler::DoGet() { | ||||||
|         if (!IsAuthorized()) { | 	    bool Expired = false; | ||||||
|  |         if (!IsAuthorized(Expired)) { | ||||||
|  |             if(Expired) | ||||||
|  |                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||||
|             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); |             return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); | ||||||
|         } |         } | ||||||
|         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); |         bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); | ||||||
|         if(GetMe) { |         if(GetMe) { | ||||||
|             Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); |             Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); | ||||||
|             Poco::JSON::Object Me; |             Poco::JSON::Object Me; | ||||||
|             UserInfo_.userinfo.to_json(Me); |             SecurityObjects::UserInfo   ReturnedUser = UserInfo_.userinfo; | ||||||
|  |             FilterCredentials(ReturnedUser); | ||||||
|  |             ReturnedUser.to_json(Me); | ||||||
|             return ReturnObject(Me); |             return ReturnObject(Me); | ||||||
|         } |         } | ||||||
|         BadRequest(RESTAPI::Errors::UnrecognizedRequest); |         BadRequest(RESTAPI::Errors::UnrecognizedRequest); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     void RESTAPI_oauth2Handler::DoDelete() { |     void RESTAPI_oauth2Handler::DoDelete() { | ||||||
|         if (!IsAuthorized()) { | 	    bool Expired = false; | ||||||
|             return UnAuthorized("Not authorized."); | 	    if (!IsAuthorized(Expired)) { | ||||||
|  | 	        if(Expired) | ||||||
|  | 	            return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||||
|  | 	        return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
|         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); |         auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); | ||||||
| @@ -71,7 +86,7 @@ namespace OpenWifi { | |||||||
|                 SecurityObjects::ActionLink NewLink; |                 SecurityObjects::ActionLink NewLink; | ||||||
|  |  | ||||||
|                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; |                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; | ||||||
|                 NewLink.id = MicroService::instance().CreateUUID(); |                 NewLink.id = MicroService::CreateUUID(); | ||||||
|                 NewLink.userId = UInfo1.Id; |                 NewLink.userId = UInfo1.Id; | ||||||
|                 NewLink.created = std::time(nullptr); |                 NewLink.created = std::time(nullptr); | ||||||
|                 NewLink.expires = NewLink.created + (24*60*60); |                 NewLink.expires = NewLink.created + (24*60*60); | ||||||
| @@ -93,8 +108,8 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { | ||||||
|             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); |             Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||||
|             if(Obj->has(RESTAPI::Protocol::UUID)) { |             if(Obj->has("uuid")) { | ||||||
|                 auto uuid = Obj->get(RESTAPI::Protocol::UUID).toString(); |                 auto uuid = Obj->get("uuid").toString(); | ||||||
|                 if(MFAServer().ResendCode(uuid)) |                 if(MFAServer().ResendCode(uuid)) | ||||||
|                     return OK(); |                     return OK(); | ||||||
|             } |             } | ||||||
| @@ -103,7 +118,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||||
|             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); |             Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||||
|             if(Obj->has(RESTAPI::Protocol::UUID)) { |             if(Obj->has("uuid")) { | ||||||
|                 SecurityObjects::UserInfoAndPolicy UInfo; |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|                 if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) { |                 if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) { | ||||||
|                     Poco::JSON::Object ReturnObj; |                     Poco::JSON::Object ReturnObj; | ||||||
| @@ -115,7 +130,8 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfoAndPolicy UInfo; |         SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|         auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo); |         bool Expired=false; | ||||||
|  |         auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired); | ||||||
|         if (Code==SUCCESS) { |         if (Code==SUCCESS) { | ||||||
|             Poco::JSON::Object ReturnObj; |             Poco::JSON::Object ReturnObj; | ||||||
|             if(AuthService()->RequiresMFA(UInfo)) { |             if(AuthService()->RequiresMFA(UInfo)) { | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ namespace OpenWifi { | |||||||
|                                                       Poco::Net::HTTPRequest::HTTP_GET, |                                                       Poco::Net::HTTPRequest::HTTP_GET, | ||||||
| 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | 													  Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
| 													  Server, | 													  Server, | ||||||
| 													  Internal, false, true , RateLimit{.Interval=2000,.MaxCalls=5}) {} | 													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||||
| 		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | 		static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; | ||||||
| 		void DoGet() final; | 		void DoGet() final; | ||||||
| 		void DoPost() final; | 		void DoPost() final; | ||||||
|   | |||||||
| @@ -7,8 +7,16 @@ | |||||||
| #include "Poco/JSON/Parser.h" | #include "Poco/JSON/Parser.h" | ||||||
| #include "framework/RESTAPI_errors.h" | #include "framework/RESTAPI_errors.h" | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
|  | #include "ACLProcessor.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     static void FilterCredentials(SecurityObjects::UserInfo & U) { | ||||||
|  |         U.currentPassword.clear(); | ||||||
|  |         U.lastPasswords.clear(); | ||||||
|  |         U.oauthType.clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void RESTAPI_user_handler::DoGet() { |     void RESTAPI_user_handler::DoGet() { | ||||||
|         std::string Id = GetBinding("id", ""); |         std::string Id = GetBinding("id", ""); | ||||||
|         if(Id.empty()) { |         if(Id.empty()) { | ||||||
| @@ -27,9 +35,7 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|         UInfo.currentPassword.clear(); |         FilterCredentials(UInfo); | ||||||
|         UInfo.lastPasswords.clear(); |  | ||||||
|         UInfo.oauthType.clear(); |  | ||||||
|         UInfo.to_json(UserInfoObject); |         UInfo.to_json(UserInfoObject); | ||||||
|         ReturnObject(UserInfoObject); |         ReturnObject(UserInfoObject); | ||||||
|     } |     } | ||||||
| @@ -40,20 +46,12 @@ namespace OpenWifi { | |||||||
|             return BadRequest(RESTAPI::Errors::MissingUserID); |             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; |         SecurityObjects::UserInfo UInfo; | ||||||
|         if(!StorageService()->GetUserById(Id,UInfo)) { |         if(!StorageService()->GetUserById(Id,UInfo)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UInfo.userRole==SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) { |         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) { | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -64,6 +62,9 @@ namespace OpenWifi { | |||||||
|         if(AuthService()->DeleteUserFromCache(UInfo.email)) { |         if(AuthService()->DeleteUserFromCache(UInfo.email)) { | ||||||
|             // nothing to do |             // nothing to do | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); | ||||||
|  |  | ||||||
|         Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); |         Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); | ||||||
|         StorageService()->RevokeAllTokens(UInfo.email); |         StorageService()->RevokeAllTokens(UInfo.email); | ||||||
|         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); |         Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); | ||||||
| @@ -76,57 +77,52 @@ namespace OpenWifi { | |||||||
|             return BadRequest(RESTAPI::Errors::IdMustBe0); |             return BadRequest(RESTAPI::Errors::IdMustBe0); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   NewUser; | ||||||
|         RESTAPI_utils::from_request(UInfo,*Request); |         RESTAPI_utils::from_request(NewUser,*Request); | ||||||
|  |  | ||||||
|         if(UInfo.userRole == SecurityObjects::UNKNOWN) { |         if(NewUser.userRole == SecurityObjects::UNKNOWN) { | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidUserRole); |             return BadRequest(RESTAPI::Errors::InvalidUserRole); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { |         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); |             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && UInfo.userRole == SecurityObjects::ROOT) { |         Poco::toLowerInPlace(NewUser.email); | ||||||
|             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); |         if(!Utils::ValidEMailAddress(NewUser.email)) { | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UInfo.email); |  | ||||||
|         if(!Utils::ValidEMailAddress(UInfo.email)) { |  | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); |             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!UInfo.currentPassword.empty()) { |         if(!NewUser.currentPassword.empty()) { | ||||||
|             if(!AuthService()->ValidatePassword(UInfo.currentPassword)) { |             if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { | ||||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); |                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UInfo.name.empty()) |         if(NewUser.name.empty()) | ||||||
|             UInfo.name = UInfo.email; |             NewUser.name = NewUser.email; | ||||||
|  |  | ||||||
|         if(!StorageService()->CreateUser(UInfo.email,UInfo)) { |         if(!StorageService()->CreateUser(NewUser.email,NewUser)) { | ||||||
|             Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email)); |             Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); | ||||||
|             return BadRequest(RESTAPI::Errors::RecordNotCreated); |             return BadRequest(RESTAPI::Errors::RecordNotCreated); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(GetParameter("email_verification","false")=="true") { |         if(GetParameter("email_verification","false")=="true") { | ||||||
|             if(AuthService::VerifyEmail(UInfo)) |             if(AuthService::VerifyEmail(NewUser)) | ||||||
|                 Logger_.information(Poco::format("Verification e-mail requested for %s",UInfo.email)); |                 Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); | ||||||
|             StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UInfo.Id,UInfo); |             StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) { |         if(!StorageService()->GetUserByEmail(NewUser.email, NewUser)) { | ||||||
|             Logger_.information(Poco::format("User '%s' but not retrieved.",UInfo.email)); |             Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|         UInfo.to_json(UserInfoObject); |         FilterCredentials(NewUser); | ||||||
|  |         NewUser.to_json(UserInfoObject); | ||||||
|         ReturnObject(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() { |     void RESTAPI_user_handler::DoPut() { | ||||||
| @@ -140,12 +136,8 @@ namespace OpenWifi { | |||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { |         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole == SecurityObjects::ROOT) { |  | ||||||
|             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewUser; |         SecurityObjects::UserInfo   NewUser; | ||||||
| @@ -224,15 +216,23 @@ namespace OpenWifi { | |||||||
|                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); |                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(NewUser.userTypeProprietaryInfo.mfa.method=="email") { |             if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) { | ||||||
|  |                 if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) { | ||||||
|  |                     return BadRequest("Unknown MFA method"); | ||||||
|  |                 } | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method; |                 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)) { |         if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { | ||||||
|             SecurityObjects::UserInfo   NewUserInfo; |             SecurityObjects::UserInfo   NewUserInfo; | ||||||
|             StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); |             StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); | ||||||
|             Poco::JSON::Object  ModifiedObject; |             Poco::JSON::Object  ModifiedObject; | ||||||
|  |             FilterCredentials(NewUserInfo); | ||||||
|             NewUserInfo.to_json(ModifiedObject); |             NewUserInfo.to_json(ModifiedObject); | ||||||
|             return ReturnObject(ModifiedObject); |             return ReturnObject(ModifiedObject); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ namespace OpenWifi { | |||||||
|             if (i.first == "token") { |             if (i.first == "token") { | ||||||
|                 //  can we find this token? |                 //  can we find this token? | ||||||
|                 SecurityObjects::UserInfoAndPolicy SecObj; |                 SecurityObjects::UserInfoAndPolicy SecObj; | ||||||
|                 if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo)) { |                 bool Expired = false; | ||||||
|  |                 if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) { | ||||||
|                     Poco::JSON::Object Obj; |                     Poco::JSON::Object Obj; | ||||||
|                     SecObj.to_json(Obj); |                     SecObj.to_json(Obj); | ||||||
|                     return ReturnObject(Obj); |                     return ReturnObject(Obj); | ||||||
|   | |||||||
| @@ -562,7 +562,7 @@ namespace OpenWifi::ProvObjects { | |||||||
|         } |         } | ||||||
|         I.notes = N; |         I.notes = N; | ||||||
|         I.modified = I.created = Now; |         I.modified = I.created = Now; | ||||||
|         I.id = MicroService::instance().CreateUUID(); |         I.id = MicroService::CreateUUID(); | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -59,15 +59,15 @@ namespace OpenWifi::SecurityObjects { | |||||||
|  |  | ||||||
| 	struct MobilePhoneNumber { | 	struct MobilePhoneNumber { | ||||||
| 	    std::string number; | 	    std::string number; | ||||||
| 	    bool verified; | 	    bool verified = false; | ||||||
| 	    bool primary; | 	    bool primary = false; | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct MfaAuthInfo { | 	struct MfaAuthInfo { | ||||||
| 	    bool enabled; | 	    bool enabled = false; | ||||||
| 	    std::string method; | 	    std::string method; | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
| @@ -86,7 +86,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    std::string uuid; | 	    std::string uuid; | ||||||
| 	    std::string question; | 	    std::string question; | ||||||
| 	    std::string method; | 	    std::string method; | ||||||
| 	    uint64_t    created; | 	    uint64_t    created = std::time(nullptr); | ||||||
|  |  | ||||||
| 	    void to_json(Poco::JSON::Object &Obj) const; | 	    void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
|   | |||||||
| @@ -16,13 +16,16 @@ | |||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     int SMSSender::Start() { |     int SMSSender::Start() { | ||||||
|         Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws"); |         Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false); | ||||||
|  |         if(Enabled_) { | ||||||
|  |             Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws"); | ||||||
|             if(Provider_=="aws") { |             if(Provider_=="aws") { | ||||||
|                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); |                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); | ||||||
|             } else if(Provider_=="twilio") { |             } else if(Provider_=="twilio") { | ||||||
|                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); |                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); | ||||||
|             } |             } | ||||||
|             Enabled_ = ProviderImpl_->Initialize(); |             Enabled_ = ProviderImpl_->Initialize(); | ||||||
|  |         } | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,15 +18,15 @@ namespace OpenWifi { | |||||||
|         std::string Number; |         std::string Number; | ||||||
|         std::string Code; |         std::string Code; | ||||||
|         std::string UserName; |         std::string UserName; | ||||||
|         uint64_t    Created; |         uint64_t    Created = std::time(nullptr); | ||||||
|         bool        Validated=false; |         bool        Validated = false; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class SMSSender : public SubSystemServer { |     class SMSSender : public SubSystemServer { | ||||||
|         public: |         public: | ||||||
|             static SMSSender *instance() { |             static SMSSender *instance() { | ||||||
|                 static SMSSender instance; |                 static auto *instance_ = new SMSSender; | ||||||
|                 return &instance; |                 return instance_; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             int  Start() final; |             int  Start() final; | ||||||
|   | |||||||
| @@ -43,6 +43,7 @@ namespace OpenWifi { | |||||||
|         if(!Running_) |         if(!Running_) | ||||||
|             return false; |             return false; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|             Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_); |             Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_); | ||||||
|             Aws::SNS::Model::PublishRequest psms_req; |             Aws::SNS::Model::PublishRequest psms_req; | ||||||
|             psms_req.SetMessage(Message.c_str()); |             psms_req.SetMessage(Message.c_str()); | ||||||
| @@ -56,6 +57,11 @@ namespace OpenWifi { | |||||||
|             std::string ErrMsg{psms_out.GetError().GetMessage()}; |             std::string ErrMsg{psms_out.GetError().GetMessage()}; | ||||||
|             Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); |             Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); | ||||||
|             return false; |             return false; | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         Logger_.debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber)); | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -9,12 +9,9 @@ | |||||||
| #include "Poco/Net/SMTPClientSession.h" | #include "Poco/Net/SMTPClientSession.h" | ||||||
| #include "Poco/Net/SecureSMTPClientSession.h" | #include "Poco/Net/SecureSMTPClientSession.h" | ||||||
| #include "Poco/Net/StringPartSource.h" | #include "Poco/Net/StringPartSource.h" | ||||||
| #include "Poco/Path.h" |  | ||||||
| #include "Poco/Exception.h" | #include "Poco/Exception.h" | ||||||
| #include "Poco/Net/SSLManager.h" | #include "Poco/Net/SSLManager.h" | ||||||
| #include "Poco/Net/Context.h" | #include "Poco/Net/Context.h" | ||||||
| #include "Poco/Net/InvalidCertificateHandler.h" |  | ||||||
| #include "Poco/Net/AcceptCertificateHandler.h" |  | ||||||
|  |  | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| @@ -23,6 +20,8 @@ | |||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     void SMTPMailerService::LoadMyConfig() { |     void SMTPMailerService::LoadMyConfig() { | ||||||
|  |         Enabled_ = MicroService::instance().ConfigGetBool("mailer.enabled",false); | ||||||
|  |         if(Enabled_) { | ||||||
|             MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname"); |             MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname"); | ||||||
|             SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username"); |             SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username"); | ||||||
|             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); |             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); | ||||||
| @@ -30,8 +29,11 @@ namespace OpenWifi { | |||||||
|             LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); |             LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); | ||||||
|             MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); |             MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); | ||||||
|             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); |             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()); |             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     int SMTPMailerService::Start() { |     int SMTPMailerService::Start() { | ||||||
|         LoadMyConfig(); |         LoadMyConfig(); | ||||||
| @@ -53,57 +55,46 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { |     bool SMTPMailerService::SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs) { | ||||||
|         std::lock_guard G(Mutex_); |         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, |                                             .LastTry=0, | ||||||
|                                             .Sent=0, |                                             .Sent=0, | ||||||
|                                             .File=Poco::File(TemplateDir_ + "/" +Name), |                                             .File=Poco::File(TemplateDir_ + "/" +Name), | ||||||
|                                             .Attrs=Attrs}); |                                             .Attrs=Attrs}); | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void SMTPMailerService::run() { |     void SMTPMailerService::run() { | ||||||
|  |  | ||||||
|         Running_ = true; |         Running_ = true; | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|  |  | ||||||
|             Poco::Thread::trySleep(10000); |             Poco::Thread::trySleep(10000); | ||||||
|             if(!Running_) |             if(!Running_) | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             { |             { | ||||||
|                 std::lock_guard G(Mutex_); |                 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); |                 uint64_t Now = std::time(nullptr); | ||||||
|  |                 if((i->LastTry==0 || (Now-i->LastTry)>MailRetry_)) { | ||||||
|                 for(auto &i:Messages_) { |                     if (SendIt(*i)) { | ||||||
|                     if(i.Sent==0 && (i.LastTry==0 || (Now-i.LastTry)>120)) { |                         Logger_.information(Poco::format("Attempting to deliver for mail '%s'.", Recipient)); | ||||||
|                         if (SendIt(i)) { |                         i = Messages_.erase(i); | ||||||
|                             i.LastTry = i.Sent = std::time(nullptr); |                     } else { | ||||||
|                         } else |                         i->LastTry = Now; | ||||||
|                             i.LastTry = std::time(nullptr); |                         ++i; | ||||||
|                     } |                     } | ||||||
|  |                 } 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)));}); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -115,10 +106,12 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { |     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||||
|  |         std::string             Recipient; | ||||||
|  |  | ||||||
|         try |         try | ||||||
|         { |         { | ||||||
|             Poco::Net::MailMessage  Message; |             Poco::Net::MailMessage  Message; | ||||||
|             std::string             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; |             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||||
|  |  | ||||||
|             auto H1 = Msg.Attrs.find(SENDER); |             auto H1 = Msg.Attrs.find(SENDER); | ||||||
|             std::string TheSender; |             std::string TheSender; | ||||||
| @@ -129,7 +122,6 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|             Message.setSender( TheSender ); |             Message.setSender( TheSender ); | ||||||
|             Logger_.information(Poco::format("Sending message to:%s from %s",Recipient,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.addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, Recipient)); | ||||||
|             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); |             Message.setSubject(Msg.Attrs.find(SUBJECT)->second); | ||||||
|  |  | ||||||
| @@ -146,21 +138,26 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             auto Logo = Msg.Attrs.find(LOGO); |             auto Logo = Msg.Attrs.find(LOGO); | ||||||
|             if(Logo!=Msg.Attrs.end()) { |             if(Logo!=Msg.Attrs.end()) { | ||||||
|  |                 try { | ||||||
|                     Poco::File          LogoFile(AuthService::GetLogoAssetFileName()); |                     Poco::File          LogoFile(AuthService::GetLogoAssetFileName()); | ||||||
|                     std::ifstream       IF(LogoFile.path()); |                     std::ifstream       IF(LogoFile.path()); | ||||||
|                     std::ostringstream  OS; |                     std::ostringstream  OS; | ||||||
|                     Poco::StreamCopier::copyStream(IF, OS); |                     Poco::StreamCopier::copyStream(IF, OS); | ||||||
|                 Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/jpeg")); |                     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::SharedPtr<Poco::Net::AcceptCertificateHandler>  ptrHandler_ = new Poco::Net::AcceptCertificateHandler(false); | ||||||
|  |  | ||||||
|             Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_); |             Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_); | ||||||
|             Poco::Net::Context::Params P; |  | ||||||
|             auto ptrContext = Poco::AutoPtr<Poco::Net::Context> |             auto ptrContext = Poco::AutoPtr<Poco::Net::Context> | ||||||
|                     (new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", |                     (new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", | ||||||
|                                                             Poco::Net::Context::VERIFY_RELAXED, 9, true, |                                                             Poco::Net::Context::VERIFY_RELAXED, 9, true, | ||||||
|                                                             "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH")); |                                                             "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH")); | ||||||
|             Poco::Net::SSLManager::instance().initializeClient(nullptr, |             Poco::Net::SSLManager::instance().initializeClient(nullptr, | ||||||
|                                                                &ptrHandler_, |                                                                ptrHandler_, | ||||||
|                                                                ptrContext); |                                                                ptrContext); | ||||||
|             session.login(); |             session.login(); | ||||||
|             session.startTLS(ptrContext); |             session.startTLS(ptrContext); | ||||||
| @@ -177,6 +174,9 @@ namespace OpenWifi { | |||||||
|         { |         { | ||||||
|             Logger_.log(E); |             Logger_.log(E); | ||||||
|         } |         } | ||||||
|  |         catch (const std::exception &E) { | ||||||
|  |             Logger_.warning(Poco::format("Cannot send message to:%s, error: %s",Recipient, E.what())); | ||||||
|  |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -59,8 +59,8 @@ namespace OpenWifi { | |||||||
|     class SMTPMailerService : public SubSystemServer, Poco::Runnable { |     class SMTPMailerService : public SubSystemServer, Poco::Runnable { | ||||||
|         public: |         public: | ||||||
|            static SMTPMailerService *instance() { |            static SMTPMailerService *instance() { | ||||||
|                static SMTPMailerService     instance; |                static auto * instance_ = new SMTPMailerService; | ||||||
|                return & instance; |                return instance_; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             struct MessageEvent { |             struct MessageEvent { | ||||||
| @@ -71,41 +71,35 @@ namespace OpenWifi { | |||||||
|                MessageAttributes    Attrs; |                MessageAttributes    Attrs; | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             struct MessageCacheEntry { |  | ||||||
|                uint64_t         LastRequest=0; |  | ||||||
|                uint64_t         HowManyRequests=0; |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             void run() override; |             void run() override; | ||||||
|  |  | ||||||
|             int Start() override; |             int Start() override; | ||||||
|             void Stop() override; |             void Stop() override; | ||||||
|  |  | ||||||
|             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); |             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); | ||||||
|             bool SendIt(const MessageEvent &Msg); |             bool SendIt(const MessageEvent &Msg); | ||||||
|             void LoadMyConfig(); |             void LoadMyConfig(); | ||||||
|             void reinitialize(Poco::Util::Application &self) override; |             void reinitialize(Poco::Util::Application &self) override; | ||||||
|             bool Enabled() const { return Enabled_; } |             bool Enabled() const { return Enabled_; } | ||||||
|  |  | ||||||
|         private: |         private: | ||||||
|             std::string             MailHost_; |             std::string             MailHost_; | ||||||
|             std::string             Sender_; |             std::string             Sender_; | ||||||
|             int                     MailHostPort_=25; |             int                     MailHostPort_=25; | ||||||
|  |             int                     MailRetry_=2*60; | ||||||
|  |             int                     MailAbandon_=2*60*20; | ||||||
|             std::string             SenderLoginUserName_; |             std::string             SenderLoginUserName_; | ||||||
|             std::string             SenderLoginPassword_; |             std::string             SenderLoginPassword_; | ||||||
|             std::string             LoginMethod_ = "login"; |             std::string             LoginMethod_ = "login"; | ||||||
|             std::string             LogoFileName_; |  | ||||||
|             std::string             TemplateDir_; |             std::string             TemplateDir_; | ||||||
|             std::list<MessageEvent> Messages_; |             std::list<MessageEvent> Messages_; | ||||||
|             std::map<std::string,MessageCacheEntry> Cache_; |             std::list<MessageEvent> PendingMessages_; | ||||||
|             Poco::Thread            SenderThr_; |             Poco::Thread            SenderThr_; | ||||||
|             std::atomic_bool        Running_=false; |             std::atomic_bool        Running_=false; | ||||||
|             bool                    Enabled_=false; |             bool                    Enabled_=false; | ||||||
|             Poco::Net::AcceptCertificateHandler  ptrHandler_; |  | ||||||
|  |  | ||||||
|             SMTPMailerService() noexcept: |             SMTPMailerService() noexcept: | ||||||
|                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer"), |                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer") | ||||||
|                 ptrHandler_(false) |  | ||||||
|             { |             { | ||||||
|                 std::string E{"SHA512"}; |  | ||||||
|             } |             } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,12 +16,28 @@ namespace OpenWifi { | |||||||
| 		StorageClass::Start(); | 		StorageClass::Start(); | ||||||
| 		Create_Tables(); | 		Create_Tables(); | ||||||
| 		InitializeDefaultUser(); | 		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; | 		return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Storage::Stop() { |     void Storage::Stop() { | ||||||
|         Logger_.notice("Stopping."); |         Logger_.notice("Stopping."); | ||||||
|  |         Timer_.stop(); | ||||||
|         StorageClass::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 | // namespace | ||||||
| @@ -13,6 +13,8 @@ | |||||||
| #include "framework/StorageClass.h" | #include "framework/StorageClass.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
|  |  | ||||||
|  | #include "Poco/Timer.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     static const std::string AllEmailTemplatesFieldsForCreation { |     static const std::string AllEmailTemplatesFieldsForCreation { | ||||||
| @@ -27,6 +29,12 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     class Archiver { | ||||||
|  |     public: | ||||||
|  |         void onTimer(Poco::Timer & timer); | ||||||
|  |     private: | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     class Storage : public StorageClass { |     class Storage : public StorageClass { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
| @@ -76,8 +84,8 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         static Storage *instance() { |         static Storage *instance() { | ||||||
|             static Storage instance; |             static auto * instance_ = new Storage; | ||||||
|             return &instance; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int 	Start() override; |         int 	Start() override; | ||||||
| @@ -104,12 +112,12 @@ namespace OpenWifi { | |||||||
|         bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); |         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 DeleteAvatar(const std::string & Admin, std::string &Id); | ||||||
|  |  | ||||||
|         bool AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut); |         bool AddToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut); | ||||||
|         bool RevokeToken( std::string & Token ); |         bool RevokeToken( std::string & Token ); | ||||||
|         bool IsTokenRevoked( std::string & Token ); |         bool IsTokenRevoked( std::string & Token ); | ||||||
|         bool CleanRevokedTokens( uint64_t Oldest ); |         bool CleanExpiredTokens(); | ||||||
|         bool RevokeAllTokens( std::string & UserName ); |         bool RevokeAllTokens( std::string & UserName ); | ||||||
|         bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo); |         bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate); | ||||||
|  |  | ||||||
|         /* |         /* | ||||||
|          *  All ActionLinks functions |          *  All ActionLinks functions | ||||||
| @@ -121,6 +129,7 @@ namespace OpenWifi { | |||||||
|         bool SentAction(std::string &ActionId); |         bool SentAction(std::string &ActionId); | ||||||
|         bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A); |         bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A); | ||||||
|         bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200); |         bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200); | ||||||
|  |         void CleanOldActionLinks(); | ||||||
|  |  | ||||||
| 	  private: | 	  private: | ||||||
|         int Create_Tables(); |         int Create_Tables(); | ||||||
| @@ -128,6 +137,13 @@ namespace OpenWifi { | |||||||
|         int Create_AvatarTable(); |         int Create_AvatarTable(); | ||||||
|         int Create_TokensTable(); |         int Create_TokensTable(); | ||||||
|         int Create_ActionLinkTable(); |         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(); }; |     inline Storage * StorageService() { return Storage::instance(); }; | ||||||
|   | |||||||
							
								
								
									
										2479
									
								
								src/framework/ConfigurationValidator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2479
									
								
								src/framework/ConfigurationValidator.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										46
									
								
								src/framework/ConfigurationValidator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/framework/ConfigurationValidator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | // | ||||||
|  | // 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 | ||||||
| @@ -69,6 +69,8 @@ using namespace std::chrono_literals; | |||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
| #include "nlohmann/json.hpp" | #include "nlohmann/json.hpp" | ||||||
|  |  | ||||||
|  | #include "ow_version.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     enum UNAUTHORIZED_REASON { |     enum UNAUTHORIZED_REASON { | ||||||
| @@ -80,7 +82,9 @@ namespace OpenWifi { | |||||||
|         PASSWORD_INVALID, |         PASSWORD_INVALID, | ||||||
|         INTERNAL_ERROR, |         INTERNAL_ERROR, | ||||||
|         ACCESS_DENIED, |         ACCESS_DENIED, | ||||||
|         INVALID_TOKEN |         INVALID_TOKEN, | ||||||
|  |         EXPIRED_TOKEN, | ||||||
|  |         RATE_LIMIT_EXCEEDED | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| 	class AppServiceRegistry { | 	class AppServiceRegistry { | ||||||
| @@ -88,8 +92,8 @@ namespace OpenWifi { | |||||||
| 		inline AppServiceRegistry(); | 		inline AppServiceRegistry(); | ||||||
|  |  | ||||||
| 		static AppServiceRegistry & instance() { | 		static AppServiceRegistry & instance() { | ||||||
| 			static AppServiceRegistry instance; | 		    static AppServiceRegistry *instance_= new AppServiceRegistry; | ||||||
| 			return instance; | 			return *instance_; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		inline ~AppServiceRegistry() { | 		inline ~AppServiceRegistry() { | ||||||
| @@ -1433,8 +1437,8 @@ namespace OpenWifi { | |||||||
| 	    }; | 	    }; | ||||||
|  |  | ||||||
| 	    static RESTAPI_RateLimiter *instance() { | 	    static RESTAPI_RateLimiter *instance() { | ||||||
| 	        static RESTAPI_RateLimiter instance; | 	        static RESTAPI_RateLimiter * instance_ = new RESTAPI_RateLimiter; | ||||||
| 	        return &instance; | 	        return instance_; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline int Start() final { return 0;}; | 	    inline int Start() final { return 0;}; | ||||||
| @@ -1444,18 +1448,18 @@ namespace OpenWifi { | |||||||
| 	        Poco::URI   uri(R.getURI()); | 	        Poco::URI   uri(R.getURI()); | ||||||
| 	        auto H = str_hash(uri.getPath() + R.clientAddress().host().toString()); | 	        auto H = str_hash(uri.getPath() + R.clientAddress().host().toString()); | ||||||
| 	        auto E = Cache_.get(H); | 	        auto E = Cache_.get(H); | ||||||
| 	        const auto p1 = std::chrono::system_clock::now(); | 	        auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); | ||||||
| 	        auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(p1.time_since_epoch()).count(); |  | ||||||
| 	        if(E.isNull()) { | 	        if(E.isNull()) { | ||||||
| 	            Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1}); | 	            Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1}); | ||||||
| 	            Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString())); |  | ||||||
| 	            return false; | 	            return false; | ||||||
| 	        } | 	        } | ||||||
| 	        if((Now-E->Start)<Period) { | 	        if((Now-E->Start)<Period) { | ||||||
| 	            E->Count++; | 	            E->Count++; | ||||||
| 	            Cache_.update(H,E); | 	            Cache_.update(H,E); | ||||||
| 	            if(E->Count > MaxCalls) | 	            if(E->Count > MaxCalls) { | ||||||
|  | 	                Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString())); | ||||||
| 	                return true; | 	                return true; | ||||||
|  | 	            } | ||||||
| 	            return false; | 	            return false; | ||||||
| 	        } | 	        } | ||||||
| 	        E->Start = Now; | 	        E->Start = Now; | ||||||
| @@ -1523,20 +1527,23 @@ namespace OpenWifi { | |||||||
| 	            Request = &RequestIn; | 	            Request = &RequestIn; | ||||||
| 	            Response = &ResponseIn; | 	            Response = &ResponseIn; | ||||||
|  |  | ||||||
| 	            if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) | 	            if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) { | ||||||
| 	                return; | 	                return UnAuthorized("Rate limit exceeded.",RATE_LIMIT_EXCEEDED); | ||||||
|  | 	            } | ||||||
|  |  | ||||||
| 	            if (!ContinueProcessing()) | 	            if (!ContinueProcessing()) | ||||||
| 	                return; | 	                return; | ||||||
|  |  | ||||||
| 	            if (AlwaysAuthorize_ && !IsAuthorized()) { | 	            bool Expired=false; | ||||||
| 	                return; | 	            if (AlwaysAuthorize_ && !IsAuthorized(Expired)) { | ||||||
|  | 	                if(Expired) | ||||||
|  | 	                    return UnAuthorized(RESTAPI::Errors::ExpiredToken, EXPIRED_TOKEN); | ||||||
|  | 	                return UnAuthorized(RESTAPI::Errors::InvalidCredentials, ACCESS_DENIED); | ||||||
| 	            } | 	            } | ||||||
|  |  | ||||||
| 	            std::string Reason; | 	            std::string Reason; | ||||||
| 	            if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) { | 	            if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) { | ||||||
|                     UnAuthorized(Reason, ACCESS_DENIED); |                     return UnAuthorized(Reason, ACCESS_DENIED); | ||||||
|                     return; |  | ||||||
| 	            } | 	            } | ||||||
|  |  | ||||||
| 	            ParseParameters(); | 	            ParseParameters(); | ||||||
| @@ -1874,7 +1881,7 @@ namespace OpenWifi { | |||||||
| 	        return true; | 	        return true; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline bool IsAuthorized(); | 	    inline bool IsAuthorized(bool & Expired); | ||||||
|  |  | ||||||
| 	        inline void ReturnObject(Poco::JSON::Object &Object) { | 	        inline void ReturnObject(Poco::JSON::Object &Object) { | ||||||
| 	            PrepareResponse(); | 	            PrepareResponse(); | ||||||
| @@ -1895,7 +1902,7 @@ namespace OpenWifi { | |||||||
| 	            QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, ""); | 	            QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||||
| 	            QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0); | 	            QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0); | ||||||
| 	            QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0); | 	            QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0); | ||||||
| 	            QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 1); | 	            QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0); | ||||||
| 	            QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100); | 	            QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100); | ||||||
| 	            QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, ""); | 	            QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, ""); | ||||||
| 	            QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, ""); | 	            QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, ""); | ||||||
| @@ -1907,7 +1914,7 @@ namespace OpenWifi { | |||||||
| 	            QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false); | 	            QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false); | ||||||
|  |  | ||||||
| 	            if(QB_.Offset<1) | 	            if(QB_.Offset<1) | ||||||
| 	                QB_.Offset=1; | 	                QB_.Offset=0; | ||||||
| 	            return true; | 	            return true; | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
| @@ -2076,6 +2083,50 @@ namespace OpenWifi { | |||||||
| 	    Poco::JSON::Object      Body_; | 	    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 { | 	class KafkaManager : public SubSystemServer { | ||||||
| 	public: | 	public: | ||||||
| 	    struct KMessage { | 	    struct KMessage { | ||||||
| @@ -2084,33 +2135,32 @@ namespace OpenWifi { | |||||||
| 	        PayLoad; | 	        PayLoad; | ||||||
| 	    }; | 	    }; | ||||||
|  |  | ||||||
|  | 	    friend class KafkaConsumer; | ||||||
|  | 	    friend class KafkaProducer; | ||||||
|  |  | ||||||
| 	    inline void initialize(Poco::Util::Application & self) override; | 	    inline void initialize(Poco::Util::Application & self) override; | ||||||
|  |  | ||||||
| 	    static KafkaManager *instance() { | 	    static KafkaManager *instance() { | ||||||
| 	        static KafkaManager instance; | 	        static KafkaManager * instance_ = new KafkaManager; | ||||||
| 	        return &instance; | 	        return instance_; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline int Start() override { | 	    inline int Start() override { | ||||||
| 	        if(!KafkaEnabled_) | 	        if(!KafkaEnabled_) | ||||||
| 	            return 0; | 	            return 0; | ||||||
| 	        ProducerThr_ = std::make_unique<std::thread>([this]() { this->ProducerThr(); }); | 	        ConsumerThr_.Start(); | ||||||
| 	        ConsumerThr_ = std::make_unique<std::thread>([this]() { this->ConsumerThr(); }); | 	        ProducerThr_.Start(); | ||||||
| 	        return 0; | 	        return 0; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline void Stop() override { | 	    inline void Stop() override { | ||||||
| 	        if(KafkaEnabled_) { | 	        if(KafkaEnabled_) { | ||||||
| 	            ProducerRunning_ = ConsumerRunning_ = false; | 	            ProducerThr_.Stop(); | ||||||
| 	            ProducerThr_->join(); | 	            ConsumerThr_.Stop(); | ||||||
| 	            ConsumerThr_->join(); |  | ||||||
| 	            return; | 	            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  ) { | 	    inline void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true  ) { | ||||||
| 	        if(KafkaEnabled_) { | 	        if(KafkaEnabled_) { | ||||||
| 	            std::lock_guard G(Mutex_); | 	            std::lock_guard G(Mutex_); | ||||||
| @@ -2163,18 +2213,13 @@ namespace OpenWifi { | |||||||
| 	    // void WakeUp(); | 	    // void WakeUp(); | ||||||
|  |  | ||||||
| 	private: | 	private: | ||||||
| 	    std::mutex 						ProducerMutex_; |  | ||||||
| 	    std::mutex						ConsumerMutex_; |  | ||||||
| 	    bool 							KafkaEnabled_ = false; | 	    bool 							KafkaEnabled_ = false; | ||||||
| 	    std::atomic_bool 				ProducerRunning_ = false; |  | ||||||
| 	    std::atomic_bool 				ConsumerRunning_ = false; |  | ||||||
| 	    std::queue<KMessage>			Queue_; | 	    std::queue<KMessage>			Queue_; | ||||||
| 	    std::string 					SystemInfoWrapper_; | 	    std::string 					SystemInfoWrapper_; | ||||||
| 	    std::unique_ptr<std::thread>	ConsumerThr_; |  | ||||||
| 	    std::unique_ptr<std::thread>	ProducerThr_; |  | ||||||
| 	    int                       		FunctionId_=1; | 	    int                       		FunctionId_=1; | ||||||
| 	    Types::NotifyTable        		Notifiers_; | 	    Types::NotifyTable        		Notifiers_; | ||||||
| 	    std::unique_ptr<cppkafka::Configuration>    Config_; | 	    KafkaProducer                   ProducerThr_; | ||||||
|  | 	    KafkaConsumer                   ConsumerThr_; | ||||||
|  |  | ||||||
| 	    inline void PartitionAssignment(const cppkafka::TopicPartitionList& partitions) { | 	    inline void PartitionAssignment(const cppkafka::TopicPartitionList& partitions) { | ||||||
| 	        Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition())); | 	        Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition())); | ||||||
| @@ -2199,8 +2244,8 @@ namespace OpenWifi { | |||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    static AuthClient *instance() { | 	    static AuthClient *instance() { | ||||||
| 	        static AuthClient instance; | 	        static AuthClient * instance_ = new AuthClient; | ||||||
| 	        return &instance; | 	        return instance_; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline int Start() override { | 	    inline int Start() override { | ||||||
| @@ -2208,25 +2253,20 @@ namespace OpenWifi { | |||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline void Stop() override { | 	    inline void Stop() override { | ||||||
|  | 	        Cache_.clear(); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline void RemovedCachedToken(const std::string &Token) { | 	    inline void RemovedCachedToken(const std::string &Token) { | ||||||
| 	        std::lock_guard	G(Mutex_); | 	        std::lock_guard	G(Mutex_); | ||||||
| 	        UserCache_.erase(Token); | 	        Cache_.remove(Token); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) { | 	    inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) { | ||||||
| 	        return ((T.expires_in_+T.created_)<std::time(nullptr)); | 	        return ((T.expires_in_+T.created_)<std::time(nullptr)); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline bool IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) { | 	    inline bool RetrieveTokenInformation(const std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) { | ||||||
| 	        std::lock_guard G(Mutex_); | 	        try { | ||||||
|  |  | ||||||
| 	        auto User = UserCache_.find(SessionToken); |  | ||||||
| 	        if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) { |  | ||||||
| 	            UInfo = User->second; |  | ||||||
| 	            return true; |  | ||||||
| 	        } else { |  | ||||||
| 	            Types::StringPairVec QueryData; | 	            Types::StringPairVec QueryData; | ||||||
| 	            QueryData.push_back(std::make_pair("token",SessionToken)); | 	            QueryData.push_back(std::make_pair("token",SessionToken)); | ||||||
| 	            OpenAPIRequestGet	Req(    uSERVICE_SECURITY, | 	            OpenAPIRequestGet	Req(    uSERVICE_SECURITY, | ||||||
| @@ -2236,49 +2276,39 @@ namespace OpenWifi { | |||||||
| 	            Poco::JSON::Object::Ptr Response; | 	            Poco::JSON::Object::Ptr Response; | ||||||
| 	            if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) { | 	            if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) { | ||||||
| 	                if(Response->has("tokenInfo") && Response->has("userInfo")) { | 	                if(Response->has("tokenInfo") && Response->has("userInfo")) { | ||||||
| 	                    SecurityObjects::UserInfoAndPolicy	P; | 	                    UInfo.from_json(Response); | ||||||
| 	                    P.from_json(Response); | 	                    if(IsTokenExpired(UInfo.webtoken)) { | ||||||
| 	                    UserCache_[SessionToken] = P; | 	                        Expired = true; | ||||||
| 	                    UInfo = P; | 	                        return false; | ||||||
| 	                    } | 	                    } | ||||||
|  | 	                    Expired = false; | ||||||
|  | 	                    Cache_.update(SessionToken, UInfo); | ||||||
| 	                    return true; | 	                    return true; | ||||||
| 	                } | 	                } | ||||||
|  | 	            } | ||||||
|  | 	        } catch (...) { | ||||||
|  |  | ||||||
| 	        } | 	        } | ||||||
|  | 	        Expired = false; | ||||||
| 	        return false; | 	        return false; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline bool IsTokenAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo) { |         inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) { | ||||||
| 	        std::lock_guard G(Mutex_); | 	        auto User = Cache_.get(SessionToken); | ||||||
|  | 	        if(!User.isNull()) { | ||||||
| 	        auto User = UserCache_.find(SessionToken); | 	            if(IsTokenExpired(User->webtoken)) { | ||||||
| 	        if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) { | 	                Expired = true; | ||||||
| 	            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; |  | ||||||
| 	            } |  | ||||||
|  |  | ||||||
| 	        } |  | ||||||
| 	                return false; | 	                return false; | ||||||
| 	            } | 	            } | ||||||
|  | 	            Expired = false; | ||||||
|  |                 UInfo = *User; | ||||||
|  |                 return true; | ||||||
|  | 	        } | ||||||
|  | 	        return RetrieveTokenInformation(SessionToken, UInfo, Expired); | ||||||
|  | 	    } | ||||||
|  |  | ||||||
| 	private: | 	private: | ||||||
| 	    OpenWifi::SecurityObjects::UserInfoCache 		UserCache_; | 	    Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy>      Cache_{1024,1200000 }; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline AuthClient * AuthClient() { return AuthClient::instance(); } | 	inline AuthClient * AuthClient() { return AuthClient::instance(); } | ||||||
| @@ -2338,14 +2368,14 @@ namespace OpenWifi { | |||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    static ALBHealthCheckServer *instance() { | 	    static ALBHealthCheckServer *instance() { | ||||||
| 	        static ALBHealthCheckServer instance; | 	        static ALBHealthCheckServer * instance = new ALBHealthCheckServer; | ||||||
| 	        return &instance; | 	        return instance; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline int Start() override; | 	    inline int Start() override; | ||||||
|  |  | ||||||
| 	    inline void Stop() override { | 	    inline void Stop() override { | ||||||
| 	        if(Server_) | 	        if(Running_) | ||||||
| 	            Server_->stop(); | 	            Server_->stop(); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| @@ -2353,6 +2383,7 @@ namespace OpenWifi { | |||||||
| 	    std::unique_ptr<Poco::Net::HTTPServer>   	Server_; | 	    std::unique_ptr<Poco::Net::HTTPServer>   	Server_; | ||||||
| 	    std::unique_ptr<Poco::Net::ServerSocket> 	Socket_; | 	    std::unique_ptr<Poco::Net::ServerSocket> 	Socket_; | ||||||
| 	    int                                     	Port_ = 0; | 	    int                                     	Port_ = 0; | ||||||
|  | 	    std::atomic_bool                            Running_=false; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } | 	inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } | ||||||
| @@ -2364,23 +2395,24 @@ namespace OpenWifi { | |||||||
|                                                             Poco::Logger & L, RESTAPI_GenericServer & S); |                                                             Poco::Logger & L, RESTAPI_GenericServer & S); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	class RESTAPI_server : public SubSystemServer { | 	class RESTAPI_ExtServer : public SubSystemServer { | ||||||
| 	public: | 	public: | ||||||
| 	    static RESTAPI_server *instance() { | 	    static RESTAPI_ExtServer *instance() { | ||||||
| 	        static RESTAPI_server instance; | 	        static RESTAPI_ExtServer *instance_ = new RESTAPI_ExtServer; | ||||||
| 	        return &instance; | 	        return instance_; | ||||||
| 	    } | 	    } | ||||||
| 	    int Start() override; | 	    int Start() override; | ||||||
| 	    inline void Stop() override { | 	    inline void Stop() override { | ||||||
| 	        Logger_.information("Stopping "); | 	        Logger_.information("Stopping "); | ||||||
| 	        for( const auto & svr : RESTServers_ ) | 	        for( const auto & svr : RESTServers_ ) | ||||||
| 	            svr->stop(); | 	            svr->stop(); | ||||||
|  | 	        Pool_.joinAll(); | ||||||
| 	        RESTServers_.clear(); | 	        RESTServers_.clear(); | ||||||
|  |  | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline void reinitialize(Poco::Util::Application &self) override; | 	    inline void reinitialize(Poco::Util::Application &self) override; | ||||||
|  |  | ||||||
| 	    inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) { | 	    inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path, uint64_t Id) { | ||||||
| 	        RESTAPIHandler::BindingMap Bindings; | 	        RESTAPIHandler::BindingMap Bindings; | ||||||
| 	        return RESTAPI_external_server(Path, Bindings, Logger_, Server_); | 	        return RESTAPI_external_server(Path, Bindings, Logger_, Server_); | ||||||
| 	    } | 	    } | ||||||
| @@ -2390,18 +2422,18 @@ namespace OpenWifi { | |||||||
| 	    Poco::ThreadPool	    Pool_; | 	    Poco::ThreadPool	    Pool_; | ||||||
| 	    RESTAPI_GenericServer   Server_; | 	    RESTAPI_GenericServer   Server_; | ||||||
|  |  | ||||||
| 	    RESTAPI_server() noexcept: | 	    RESTAPI_ExtServer() noexcept: | ||||||
| 	    SubSystemServer("RESTAPIServer", "RESTAPIServer", "openwifi.restapi") | 	    SubSystemServer("RESTAPIServer", "RESTAPIServer", "openwifi.restapi") | ||||||
|             { |             { | ||||||
|             } |             } | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline RESTAPI_server * RESTAPI_server() { return RESTAPI_server::instance(); }; | 	inline RESTAPI_ExtServer * RESTAPI_ExtServer() { return RESTAPI_ExtServer::instance(); }; | ||||||
|  |  | ||||||
| 	class RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { | 	class ExtRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { | ||||||
| 	public: | 	public: | ||||||
| 	    RequestHandlerFactory(RESTAPI_GenericServer & Server) : | 	  	explicit ExtRequestHandlerFactory(RESTAPI_GenericServer & Server) : | ||||||
| 	    Logger_(RESTAPI_server::instance()->Logger()), | 			Logger_(RESTAPI_ExtServer::instance()->Logger()), | ||||||
| 			Server_(Server) | 			Server_(Server) | ||||||
| 	    { | 	    { | ||||||
|  |  | ||||||
| @@ -2410,15 +2442,16 @@ namespace OpenWifi { | |||||||
| 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | ||||||
| 	        Poco::URI uri(Request.getURI()); | 	        Poco::URI uri(Request.getURI()); | ||||||
| 	        auto *Path = uri.getPath().c_str(); | 	        auto *Path = uri.getPath().c_str(); | ||||||
| 	        return RESTAPI_server()->CallServer(Path); | 	        return RESTAPI_ExtServer()->CallServer(Path, TransactionId_++); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	private: | 	private: | ||||||
|  | 		static inline std::atomic_uint64_t  TransactionId_ = 1; | ||||||
| 	    Poco::Logger            			&Logger_; | 	    Poco::Logger            			&Logger_; | ||||||
| 	    RESTAPI_GenericServer   			&Server_; | 	    RESTAPI_GenericServer   			&Server_; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline int RESTAPI_server::Start() { | 	inline int RESTAPI_ExtServer::Start() { | ||||||
| 	    Logger_.information("Starting."); | 	    Logger_.information("Starting."); | ||||||
| 	    Server_.InitLogging(); | 	    Server_.InitLogging(); | ||||||
|  |  | ||||||
| @@ -2432,12 +2465,12 @@ namespace OpenWifi { | |||||||
| 	        if(!Svr.RootCA().empty()) | 	        if(!Svr.RootCA().empty()) | ||||||
| 	            Svr.LogCas(Logger_); | 	            Svr.LogCas(Logger_); | ||||||
|  |  | ||||||
| 	        auto Params = new Poco::Net::HTTPServerParams; | 	        Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams; | ||||||
| 	        Params->setMaxThreads(50); | 	        Params->setMaxThreads(50); | ||||||
| 	        Params->setMaxQueued(200); | 	        Params->setMaxQueued(200); | ||||||
| 	        Params->setKeepAlive(true); | 	        Params->setKeepAlive(true); | ||||||
|  |  | ||||||
| 	        auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new RequestHandlerFactory(Server_), Pool_, Sock, Params); | 	        auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory(Server_), Pool_, Sock, Params); | ||||||
| 	        NewServer->start(); | 	        NewServer->start(); | ||||||
| 	        RESTServers_.push_back(std::move(NewServer)); | 	        RESTServers_.push_back(std::move(NewServer)); | ||||||
| 	    } | 	    } | ||||||
| @@ -2445,12 +2478,12 @@ namespace OpenWifi { | |||||||
| 	    return 0; | 	    return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	class RESTAPI_InternalServer : public SubSystemServer { | 	class RESTAPI_IntServer : public SubSystemServer { | ||||||
|  |  | ||||||
| 	public: | 	public: | ||||||
| 	    static RESTAPI_InternalServer *instance() { | 	    static RESTAPI_IntServer *instance() { | ||||||
| 	        static RESTAPI_InternalServer instance; | 	        static RESTAPI_IntServer *instance_ = new RESTAPI_IntServer; | ||||||
| 	        return &instance; | 	        return instance_; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline int Start() override; | 	    inline int Start() override; | ||||||
| @@ -2458,12 +2491,13 @@ namespace OpenWifi { | |||||||
| 	        Logger_.information("Stopping "); | 	        Logger_.information("Stopping "); | ||||||
| 	        for( const auto & svr : RESTServers_ ) | 	        for( const auto & svr : RESTServers_ ) | ||||||
| 	            svr->stop(); | 	            svr->stop(); | ||||||
|  | 			Pool_.joinAll(); | ||||||
| 			RESTServers_.clear(); | 			RESTServers_.clear(); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    inline void reinitialize(Poco::Util::Application &self) override; | 	    inline void reinitialize(Poco::Util::Application &self) override; | ||||||
|  |  | ||||||
| 	    inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) { | 	    inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path, uint64_t Id) { | ||||||
| 	        RESTAPIHandler::BindingMap Bindings; | 	        RESTAPIHandler::BindingMap Bindings; | ||||||
| 	        return RESTAPI_internal_server(Path, Bindings, Logger_, Server_); | 	        return RESTAPI_internal_server(Path, Bindings, Logger_, Server_); | ||||||
| 	    } | 	    } | ||||||
| @@ -2472,31 +2506,31 @@ namespace OpenWifi { | |||||||
| 	    Poco::ThreadPool	    Pool_; | 	    Poco::ThreadPool	    Pool_; | ||||||
| 	    RESTAPI_GenericServer   Server_; | 	    RESTAPI_GenericServer   Server_; | ||||||
|  |  | ||||||
| 	    RESTAPI_InternalServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi") | 	    RESTAPI_IntServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi") | ||||||
| 	    { | 	    { | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); }; | 	inline RESTAPI_IntServer * RESTAPI_IntServer() { return RESTAPI_IntServer::instance(); }; | ||||||
|  |  | ||||||
| 	class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { | 	class IntRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { | ||||||
| 	public: | 	public: | ||||||
| 	    InternalRequestHandlerFactory(RESTAPI_GenericServer & Server) : | 	  	explicit IntRequestHandlerFactory(RESTAPI_GenericServer & Server) : | ||||||
| 	    Logger_(RESTAPI_InternalServer()->Logger()), | 	    Logger_(RESTAPI_IntServer()->Logger()), | ||||||
| 	    Server_(Server){} | 	    Server_(Server){} | ||||||
|  |  | ||||||
| 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | 	    inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { | ||||||
| 	        Poco::URI uri(Request.getURI()); | 	        Poco::URI uri(Request.getURI()); | ||||||
| 	        auto *Path = uri.getPath().c_str(); | 	        auto *Path = uri.getPath().c_str(); | ||||||
| 	        return RESTAPI_InternalServer()->CallServer(Path); | 	        return RESTAPI_IntServer()->CallServer(Path, TransactionId_++); | ||||||
| 	    } | 	    } | ||||||
| 	private: | 	private: | ||||||
|  | 		static inline std::atomic_uint64_t  TransactionId_ = 1; | ||||||
| 	    Poco::Logger    & Logger_; | 	    Poco::Logger    & Logger_; | ||||||
| 	    RESTAPI_GenericServer   &Server_; | 	    RESTAPI_GenericServer   & Server_; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline int RESTAPI_InternalServer::Start() { | 	inline int RESTAPI_IntServer::Start() { | ||||||
| 	    Logger_.information("Starting."); | 	    Logger_.information("Starting."); | ||||||
| 	    Server_.InitLogging(); | 	    Server_.InitLogging(); | ||||||
|  |  | ||||||
| @@ -2514,7 +2548,7 @@ namespace OpenWifi { | |||||||
| 	        Params->setMaxQueued(200); | 	        Params->setMaxQueued(200); | ||||||
| 	        Params->setKeepAlive(true); | 	        Params->setKeepAlive(true); | ||||||
|  |  | ||||||
| 	        auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new InternalRequestHandlerFactory(Server_), Pool_, Sock, Params); | 	        auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory(Server_), Pool_, Sock, Params); | ||||||
| 	        NewServer->start(); | 	        NewServer->start(); | ||||||
| 	        RESTServers_.push_back(std::move(NewServer)); | 	        RESTServers_.push_back(std::move(NewServer)); | ||||||
| 	    } | 	    } | ||||||
| @@ -2554,11 +2588,13 @@ namespace OpenWifi { | |||||||
| 			DAEMON_BUS_TIMER(BusTimer), | 			DAEMON_BUS_TIMER(BusTimer), | ||||||
| 			SubSystems_(std::move(Subsystems)) { | 			SubSystems_(std::move(Subsystems)) { | ||||||
| 		    instance_ = this; | 		    instance_ = this; | ||||||
|  | 		    RandomEngine_.seed(std::chrono::steady_clock::now().time_since_epoch().count()); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		[[nodiscard]] std::string Version() { return Version_; } | 		[[nodiscard]] std::string Version() { return Version_; } | ||||||
| 		[[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; } | 		[[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; } | ||||||
| 		[[nodiscard]] inline const std::string & DataDir() { return DataDir_; } | 		[[nodiscard]] inline const std::string & DataDir() { return DataDir_; } | ||||||
|  | 		[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; } | ||||||
| 		[[nodiscard]] bool Debug() const { return DebugMode_; } | 		[[nodiscard]] bool Debug() const { return DebugMode_; } | ||||||
| 		[[nodiscard]] uint64_t ID() const { return ID_; } | 		[[nodiscard]] uint64_t ID() const { return ID_; } | ||||||
| 		[[nodiscard]] std::string Hash() const { return MyHash_; }; | 		[[nodiscard]] std::string Hash() const { return MyHash_; }; | ||||||
| @@ -2571,6 +2607,13 @@ namespace OpenWifi { | |||||||
| 		static inline uint64_t GetPID() { return Poco::Process::id(); }; | 		static inline uint64_t GetPID() { return Poco::Process::id(); }; | ||||||
| 		[[nodiscard]] inline const std::string GetPublicAPIEndPoint() { return MyPublicEndPoint_ + "/api/v1"; }; | 		[[nodiscard]] inline const std::string GetPublicAPIEndPoint() { return MyPublicEndPoint_ + "/api/v1"; }; | ||||||
| 		[[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;}; | 		[[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 Exit(int Reason); | ||||||
| 		inline void BusMessageReceived(const std::string &Key, const std::string & Message); | 		inline void BusMessageReceived(const std::string &Key, const std::string & Message); | ||||||
| @@ -2592,7 +2635,7 @@ namespace OpenWifi { | |||||||
| 		inline void InitializeSubSystemServers(); | 		inline void InitializeSubSystemServers(); | ||||||
| 		inline void StartSubSystemServers(); | 		inline void StartSubSystemServers(); | ||||||
| 		inline void StopSubSystemServers(); | 		inline void StopSubSystemServers(); | ||||||
| 		[[nodiscard]] inline std::string CreateUUID(); | 		[[nodiscard]] static inline std::string CreateUUID(); | ||||||
| 		inline bool SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level); | 		inline bool SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level); | ||||||
| 		inline void Reload(const std::string &Sub); | 		inline void Reload(const std::string &Sub); | ||||||
| 		inline Types::StringVec GetSubSystems() const; | 		inline Types::StringVec GetSubSystems() const; | ||||||
| @@ -2622,9 +2665,10 @@ namespace OpenWifi { | |||||||
| 		std::string                 ConfigFileName_; | 		std::string                 ConfigFileName_; | ||||||
| 		Poco::UUIDGenerator         UUIDGenerator_; | 		Poco::UUIDGenerator         UUIDGenerator_; | ||||||
| 		uint64_t                    ID_ = 1; | 		uint64_t                    ID_ = 1; | ||||||
| 		Poco::SharedPtr<Poco::Crypto::RSAKey>	AppKey_ = nullptr; | 		Poco::SharedPtr<Poco::Crypto::RSAKey>	AppKey_; | ||||||
| 		bool                        DebugMode_ = false; | 		bool                        DebugMode_ = false; | ||||||
| 		std::string 				DataDir_; | 		std::string 				DataDir_; | ||||||
|  | 		std::string                 WWWAssetsDir_; | ||||||
| 		SubSystemVec			    SubSystems_; | 		SubSystemVec			    SubSystems_; | ||||||
| 		Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); | 		Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); | ||||||
| 		Poco::Crypto::Cipher        * Cipher_ = nullptr; | 		Poco::Crypto::Cipher        * Cipher_ = nullptr; | ||||||
| @@ -2634,9 +2678,10 @@ namespace OpenWifi { | |||||||
| 		std::string 				MyPrivateEndPoint_; | 		std::string 				MyPrivateEndPoint_; | ||||||
| 		std::string 				MyPublicEndPoint_; | 		std::string 				MyPublicEndPoint_; | ||||||
| 		std::string                 UIURI_; | 		std::string                 UIURI_; | ||||||
| 		std::string 				Version_{std::string(APP_VERSION) + "("+ BUILD_NUMBER + ")"}; | 		std::string 				Version_{ OW_VERSION::VERSION + "("+ OW_VERSION::BUILD + ")" + " - " + OW_VERSION::HASH }; | ||||||
| 		BusEventManager				BusEventManager_; | 		BusEventManager				BusEventManager_; | ||||||
| 		std::mutex 					InfraMutex_; | 		std::mutex 					InfraMutex_; | ||||||
|  | 		std::default_random_engine  RandomEngine_; | ||||||
|  |  | ||||||
| 		std::string DAEMON_PROPERTIES_FILENAME; | 		std::string DAEMON_PROPERTIES_FILENAME; | ||||||
| 		std::string DAEMON_ROOT_ENV_VAR; | 		std::string DAEMON_ROOT_ENV_VAR; | ||||||
| @@ -2784,8 +2829,8 @@ namespace OpenWifi { | |||||||
| 	    // add the default services | 	    // add the default services | ||||||
| 	    SubSystems_.push_back(KafkaManager()); | 	    SubSystems_.push_back(KafkaManager()); | ||||||
| 	    SubSystems_.push_back(ALBHealthCheckServer()); | 	    SubSystems_.push_back(ALBHealthCheckServer()); | ||||||
| 	    SubSystems_.push_back(RESTAPI_server()); | 	    SubSystems_.push_back(RESTAPI_ExtServer()); | ||||||
| 	    SubSystems_.push_back(RESTAPI_InternalServer()); | 	    SubSystems_.push_back(RESTAPI_IntServer()); | ||||||
|  |  | ||||||
| 	    Poco::Net::initializeSSL(); | 	    Poco::Net::initializeSSL(); | ||||||
| 	    Poco::Net::HTTPStreamFactory::registerFactory(); | 	    Poco::Net::HTTPStreamFactory::registerFactory(); | ||||||
| @@ -2813,6 +2858,9 @@ namespace OpenWifi { | |||||||
| 	            logger().log(E); | 	            logger().log(E); | ||||||
| 	        } | 	        } | ||||||
| 	    } | 	    } | ||||||
|  | 	    WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets",""); | ||||||
|  | 	    if(WWWAssetsDir_.empty()) | ||||||
|  | 	        WWWAssetsDir_ = DataDir_; | ||||||
|  |  | ||||||
| 	    LoadMyConfig(); | 	    LoadMyConfig(); | ||||||
|  |  | ||||||
| @@ -2919,12 +2967,41 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 	inline void MicroService::StopSubSystemServers() { | 	inline void MicroService::StopSubSystemServers() { | ||||||
| 	    BusEventManager_.Stop(); | 	    BusEventManager_.Stop(); | ||||||
| 	    for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) | 	    for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) { | ||||||
| 			(*i)->Stop(); | 			(*i)->Stop(); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	[[nodiscard]] inline std::string MicroService::CreateUUID() { | 	[[nodiscard]] inline std::string MicroService::CreateUUID() { | ||||||
| 	    return UUIDGenerator_.create().toString(); |         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(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	inline bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) { | 	inline bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) { | ||||||
| @@ -2938,7 +3015,6 @@ namespace OpenWifi { | |||||||
| 	            } | 	            } | ||||||
| 	            return true; | 	            return true; | ||||||
| 	        } else { | 	        } else { | ||||||
| 	            // std::cout << "Sub:" << SubSystem << " Level:" << Level << std::endl; |  | ||||||
| 	            for (auto i : SubSystems_) { | 	            for (auto i : SubSystems_) { | ||||||
| 	                if (Sub == Poco::toLower(i->Name())) { | 	                if (Sub == Poco::toLower(i->Name())) { | ||||||
| 	                    i->Logger().setLevel(P); | 	                    i->Logger().setLevel(P); | ||||||
| @@ -3088,7 +3164,6 @@ namespace OpenWifi { | |||||||
| 	        StartSubSystemServers(); | 	        StartSubSystemServers(); | ||||||
| 	        waitForTerminationRequest(); | 	        waitForTerminationRequest(); | ||||||
| 	        StopSubSystemServers(); | 	        StopSubSystemServers(); | ||||||
|  |  | ||||||
| 	        logger.notice(Poco::format("Stopped %s...",DAEMON_APP_NAME)); | 	        logger.notice(Poco::format("Stopped %s...",DAEMON_APP_NAME)); | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| @@ -3168,6 +3243,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
| 	inline int ALBHealthCheckServer::Start() { | 	inline int ALBHealthCheckServer::Start() { | ||||||
| 	    if(MicroService::instance().ConfigGetBool("alb.enable",false)) { | 	    if(MicroService::instance().ConfigGetBool("alb.enable",false)) { | ||||||
|  | 	        Running_=true; | ||||||
| 	        Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); | 	        Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); | ||||||
| 	        Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_); | 	        Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_); | ||||||
| 	        auto Params = new Poco::Net::HTTPServerParams; | 	        auto Params = new Poco::Net::HTTPServerParams; | ||||||
| @@ -3212,41 +3288,42 @@ namespace OpenWifi { | |||||||
| 	    KafkaEnabled_ = MicroService::instance().ConfigGetBool("openwifi.kafka.enable",false); | 	    KafkaEnabled_ = MicroService::instance().ConfigGetBool("openwifi.kafka.enable",false); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline void KafkaManager::ProducerThr() { | 	inline void KafkaProducer::run() { | ||||||
| 	    cppkafka::Configuration Config({ | 	    cppkafka::Configuration Config({ | ||||||
| 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | ||||||
| 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } | 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } | ||||||
| 	    }); | 	    }); | ||||||
| 	    SystemInfoWrapper_ = 	R"lit({ "system" : { "id" : )lit" + | 	    KafkaManager()->SystemInfoWrapper_ = 	R"lit({ "system" : { "id" : )lit" + | ||||||
| 	            std::to_string(MicroService::instance().ID()) + | 	            std::to_string(MicroService::instance().ID()) + | ||||||
| 	            R"lit( , "host" : ")lit" + MicroService::instance().PrivateEndPoint() + | 	            R"lit( , "host" : ")lit" + MicroService::instance().PrivateEndPoint() + | ||||||
| 	            R"lit(" } , "payload" : )lit" ; | 	            R"lit(" } , "payload" : )lit" ; | ||||||
| 	    cppkafka::Producer	Producer(Config); | 	    cppkafka::Producer	Producer(Config); | ||||||
| 	    ProducerRunning_ = true; | 	    Running_ = true; | ||||||
| 	    while(ProducerRunning_) { | 	    while(Running_) { | ||||||
| 	        std::this_thread::sleep_for(std::chrono::milliseconds(200)); | 	        std::this_thread::sleep_for(std::chrono::milliseconds(200)); | ||||||
| 	        try | 	        try | ||||||
| 	        { | 	        { | ||||||
| 	            std::lock_guard G(ProducerMutex_); | 	            std::lock_guard G(Mutex_); | ||||||
| 	            auto Num=0; | 	            auto Num=0; | ||||||
| 	            while (!Queue_.empty()) { | 	            while (!KafkaManager()->Queue_.empty()) { | ||||||
| 	                const auto M = Queue_.front(); | 	                const auto M = KafkaManager()->Queue_.front(); | ||||||
| 	                Producer.produce( | 	                Producer.produce( | ||||||
| 	                        cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad)); | 	                        cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad)); | ||||||
| 	                Queue_.pop(); | 	                KafkaManager()->Queue_.pop(); | ||||||
| 	                Num++; | 	                Num++; | ||||||
| 	            } | 	            } | ||||||
| 	            if(Num) | 	            if(Num) | ||||||
| 	                Producer.flush(); | 	                Producer.flush(); | ||||||
| 	        } catch (const cppkafka::HandleException &E ) { | 	        } catch (const cppkafka::HandleException &E ) { | ||||||
| 	            Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()})); | 	            KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()})); | ||||||
| 	        } catch (const Poco::Exception &E) { | 	        } catch (const Poco::Exception &E) { | ||||||
| 	            Logger_.log(E); | 	            KafkaManager()->Logger_.log(E); | ||||||
| 	        } | 	        } | ||||||
| 	    } | 	    } | ||||||
|  | 	    Producer.flush(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline void KafkaManager::ConsumerThr() { | 	inline void KafkaConsumer::run() { | ||||||
| 	    cppkafka::Configuration Config({ | 	    cppkafka::Configuration Config({ | ||||||
| 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | 	        { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, | ||||||
| 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, | 	        { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, | ||||||
| @@ -3266,13 +3343,13 @@ namespace OpenWifi { | |||||||
| 	    cppkafka::Consumer Consumer(Config); | 	    cppkafka::Consumer Consumer(Config); | ||||||
| 	    Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) { | 	    Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) { | ||||||
| 	        if(!partitions.empty()) { | 	        if(!partitions.empty()) { | ||||||
| 	            Logger_.information(Poco::format("Partition assigned: %Lu...", | 	            KafkaManager()->Logger_.information(Poco::format("Partition assigned: %Lu...", | ||||||
|                                                  (uint64_t)partitions.front().get_partition())); |                                                  (uint64_t)partitions.front().get_partition())); | ||||||
| 	        } | 	        } | ||||||
| 	    }); | 	    }); | ||||||
| 	    Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) { | 	    Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) { | ||||||
| 	        if(!partitions.empty()) { | 	        if(!partitions.empty()) { | ||||||
| 	            Logger_.information(Poco::format("Partition revocation: %Lu...", | 	            KafkaManager()->Logger_.information(Poco::format("Partition revocation: %Lu...", | ||||||
|                                                  (uint64_t)partitions.front().get_partition())); |                                                  (uint64_t)partitions.front().get_partition())); | ||||||
| 	        } | 	        } | ||||||
| 	    }); | 	    }); | ||||||
| @@ -3281,13 +3358,13 @@ namespace OpenWifi { | |||||||
| 	    auto BatchSize = MicroService::instance().ConfigGetInt("openwifi.kafka.consumer.batchsize",20); | 	    auto BatchSize = MicroService::instance().ConfigGetInt("openwifi.kafka.consumer.batchsize",20); | ||||||
|  |  | ||||||
| 	    Types::StringVec    Topics; | 	    Types::StringVec    Topics; | ||||||
| 	    for(const auto &i:Notifiers_) | 	    for(const auto &i:KafkaManager()->Notifiers_) | ||||||
| 	        Topics.push_back(i.first); | 	        Topics.push_back(i.first); | ||||||
|  |  | ||||||
| 	    Consumer.subscribe(Topics); | 	    Consumer.subscribe(Topics); | ||||||
|  |  | ||||||
| 	    ConsumerRunning_ = true; | 	    Running_ = true; | ||||||
| 	    while(ConsumerRunning_) { | 	    while(Running_) { | ||||||
| 	        try { | 	        try { | ||||||
| 	            std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200)); | 	            std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200)); | ||||||
| 	            for(auto const &Msg:MsgVec) { | 	            for(auto const &Msg:MsgVec) { | ||||||
| @@ -3295,14 +3372,14 @@ namespace OpenWifi { | |||||||
| 	                    continue; | 	                    continue; | ||||||
| 	                if (Msg.get_error()) { | 	                if (Msg.get_error()) { | ||||||
| 	                    if (!Msg.is_eof()) { | 	                    if (!Msg.is_eof()) { | ||||||
| 	                        Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string())); | 	                        KafkaManager()->Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string())); | ||||||
| 	                    }if(!AutoCommit) | 	                    }if(!AutoCommit) | ||||||
| 	                        Consumer.async_commit(Msg); | 	                        Consumer.async_commit(Msg); | ||||||
| 	                    continue; | 	                    continue; | ||||||
| 	                } | 	                } | ||||||
| 	                std::lock_guard G(ConsumerMutex_); | 	                std::lock_guard G(Mutex_); | ||||||
| 	                auto It = Notifiers_.find(Msg.get_topic()); | 	                auto It = KafkaManager()->Notifiers_.find(Msg.get_topic()); | ||||||
| 	                if (It != Notifiers_.end()) { | 	                if (It != KafkaManager()->Notifiers_.end()) { | ||||||
| 	                    Types::TopicNotifyFunctionList &FL = It->second; | 	                    Types::TopicNotifyFunctionList &FL = It->second; | ||||||
| 	                    std::string Key{Msg.get_key()}; | 	                    std::string Key{Msg.get_key()}; | ||||||
| 	                    std::string Payload{Msg.get_payload()}; | 	                    std::string Payload{Msg.get_payload()}; | ||||||
| @@ -3315,21 +3392,22 @@ namespace OpenWifi { | |||||||
| 	                    Consumer.async_commit(Msg); | 	                    Consumer.async_commit(Msg); | ||||||
| 	            } | 	            } | ||||||
| 	        } catch (const cppkafka::HandleException &E) { | 	        } catch (const cppkafka::HandleException &E) { | ||||||
| 	            Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()})); | 	            KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()})); | ||||||
| 	        } catch (const Poco::Exception &E) { | 	        } catch (const Poco::Exception &E) { | ||||||
| 	            Logger_.log(E); | 	            KafkaManager()->Logger_.log(E); | ||||||
| 	        } | 	        } | ||||||
| 	    } | 	    } | ||||||
|  | 	    Consumer.unsubscribe(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inline void RESTAPI_server::reinitialize(Poco::Util::Application &self) { | 	inline void RESTAPI_ExtServer::reinitialize(Poco::Util::Application &self) { | ||||||
| 	    MicroService::instance().LoadConfigurationFile(); | 	    MicroService::instance().LoadConfigurationFile(); | ||||||
| 	    Logger_.information("Reinitializing."); | 	    Logger_.information("Reinitializing."); | ||||||
| 	    Stop(); | 	    Stop(); | ||||||
| 	    Start(); | 	    Start(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void RESTAPI_InternalServer::reinitialize(Poco::Util::Application &self) { | 	void RESTAPI_IntServer::reinitialize(Poco::Util::Application &self) { | ||||||
| 	    MicroService::instance().LoadConfigurationFile(); | 	    MicroService::instance().LoadConfigurationFile(); | ||||||
| 	    Logger_.information("Reinitializing."); | 	    Logger_.information("Reinitializing."); | ||||||
| 	    Stop(); | 	    Stop(); | ||||||
| @@ -3540,11 +3618,9 @@ namespace OpenWifi { | |||||||
|                 if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { |                 if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { | ||||||
|                     Poco::JSON::Parser	P; |                     Poco::JSON::Parser	P; | ||||||
|                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); |                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); | ||||||
|                     //	                std::cout << "Response OK" << std::endl; |  | ||||||
|                 } else { |                 } else { | ||||||
|                     Poco::JSON::Parser	P; |                     Poco::JSON::Parser	P; | ||||||
|                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); |                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); | ||||||
|                     //	                std::cout << "Response: " << Response.getStatus() << std::endl; |  | ||||||
|                 } |                 } | ||||||
|                 return Response.getStatus(); |                 return Response.getStatus(); | ||||||
|             } |             } | ||||||
| @@ -3590,11 +3666,9 @@ namespace OpenWifi { | |||||||
|                 if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { |                 if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { | ||||||
|                     Poco::JSON::Parser	P; |                     Poco::JSON::Parser	P; | ||||||
|                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); |                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); | ||||||
|                     //	                std::cout << "Response OK" << std::endl; |  | ||||||
|                 } else { |                 } else { | ||||||
|                     Poco::JSON::Parser	P; |                     Poco::JSON::Parser	P; | ||||||
|                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); |                     ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); | ||||||
|                     //	                std::cout << "Response: " << Response.getStatus() << std::endl; |  | ||||||
|                 } |                 } | ||||||
|                 return Response.getStatus(); |                 return Response.getStatus(); | ||||||
|             } |             } | ||||||
| @@ -3620,9 +3694,9 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
| #ifdef    TIP_SECURITY_SERVICE | #ifdef    TIP_SECURITY_SERVICE | ||||||
|     [[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ); |     [[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); | ||||||
| #endif | #endif | ||||||
|     inline bool RESTAPIHandler::IsAuthorized() { |     inline bool RESTAPIHandler::IsAuthorized( bool & Expired ) { | ||||||
|         if(Internal_) { |         if(Internal_) { | ||||||
|             auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); |             auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); | ||||||
|             if(!Allowed) { |             if(!Allowed) { | ||||||
| @@ -3652,12 +3726,12 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| #ifdef    TIP_SECURITY_SERVICE | #ifdef    TIP_SECURITY_SERVICE | ||||||
|             if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_)) { |             if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired)) { | ||||||
| #else | #else | ||||||
|             if (AuthClient()->IsAuthorized(*Request, SessionToken_, UserInfo_)) { |             if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired)) { | ||||||
| #endif | #endif | ||||||
|                 if(Server_.LogIt(Request->getMethod(),true)) { |                 if(Server_.LogIt(Request->getMethod(),true)) { | ||||||
|                     Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s", |                     Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s'", | ||||||
|                                                UserInfo_.userinfo.email, |                                                UserInfo_.userinfo.email, | ||||||
|                                                Utils::FormatIPv6(Request->clientAddress().toString()), |                                                Utils::FormatIPv6(Request->clientAddress().toString()), | ||||||
|                                                Request->clientAddress().toString(), |                                                Request->clientAddress().toString(), | ||||||
| @@ -3667,11 +3741,10 @@ namespace OpenWifi { | |||||||
|                 return true; |                 return true; | ||||||
|             } else { |             } else { | ||||||
|                 if(Server_.LogBadTokens(true)) { |                 if(Server_.LogBadTokens(true)) { | ||||||
|                     Logger_.debug(Poco::format("X-REQ-DENIED(%s): Method='%s' Path='%s", |                     Logger_.debug(Poco::format("X-REQ-DENIED(%s): Method='%s' Path='%s'", | ||||||
|                                                Utils::FormatIPv6(Request->clientAddress().toString()), |                                                Utils::FormatIPv6(Request->clientAddress().toString()), | ||||||
|                                                Request->getMethod(), Request->getURI())); |                                                Request->getMethod(), Request->getURI())); | ||||||
|                 } |                 } | ||||||
|                 UnAuthorized("Invalid token", INVALID_TOKEN); |  | ||||||
|             } |             } | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -59,6 +59,7 @@ namespace OpenWifi::RESTAPI::Errors { | |||||||
|     static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."}; |     static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."}; | ||||||
|     static const std::string MissingAuthenticationInformation{"Missing authentication information."}; |     static const std::string MissingAuthenticationInformation{"Missing authentication information."}; | ||||||
|     static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."}; |     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 | #endif //OWPROV_RESTAPI_ERRORS_H | ||||||
|   | |||||||
| @@ -2,8 +2,7 @@ | |||||||
| // Created by stephane bourque on 2021-10-06. | // Created by stephane bourque on 2021-10-06. | ||||||
| // | // | ||||||
|  |  | ||||||
| #ifndef OPENWIFI_STORAGE_H | #pragma once | ||||||
| #define OPENWIFI_STORAGE_H |  | ||||||
|  |  | ||||||
| #include "Poco/Data/Session.h" | #include "Poco/Data/Session.h" | ||||||
| #include "Poco/Data/SessionPool.h" | #include "Poco/Data/SessionPool.h" | ||||||
| @@ -26,13 +25,6 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     class StorageClass : public SubSystemServer { |     class StorageClass : public SubSystemServer { | ||||||
|     public: |     public: | ||||||
| /*        static StorageClass *instance() { |  | ||||||
|             if (instance_ == nullptr) { |  | ||||||
|                 instance_ = new StorageClass; |  | ||||||
|             } |  | ||||||
|             return instance_; |  | ||||||
|         } |  | ||||||
| */ |  | ||||||
|         StorageClass() noexcept: |         StorageClass() noexcept: | ||||||
|             SubSystemServer("StorageClass", "STORAGE-SVR", "storage") |             SubSystemServer("StorageClass", "STORAGE-SVR", "storage") | ||||||
|         { |         { | ||||||
| @@ -56,18 +48,18 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         void Stop() override { |         void Stop() override { | ||||||
|  |             Pool_->shutdown(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { |         [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { | ||||||
|             if(dbType_==sqlite) { |             if(dbType_==sqlite) { | ||||||
|                 return " LIMIT " + std::to_string(From-1) + ", " + std::to_string(HowMany) + " "; |                 return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " "; | ||||||
|             } else if(dbType_==pgsql) { |             } else if(dbType_==pgsql) { | ||||||
|                 return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; |                 return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; | ||||||
|             } else if(dbType_==mysql) { |             } else if(dbType_==mysql) { | ||||||
|                 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) + " "; |             return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string ConvertParams(const std::string & S) const { |         inline std::string ConvertParams(const std::string & S) const { | ||||||
| @@ -96,10 +88,10 @@ namespace OpenWifi { | |||||||
|         inline int Setup_PostgreSQL(); |         inline int Setup_PostgreSQL(); | ||||||
|  |  | ||||||
|     protected: |     protected: | ||||||
|         std::unique_ptr<Poco::Data::SessionPool>        	Pool_; |     	Poco::SharedPtr<Poco::Data::SessionPool>    Pool_; | ||||||
|         std::unique_ptr<Poco::Data::SQLite::Connector>  	SQLiteConn_; |         Poco::Data::SQLite::Connector  	            SQLiteConn_; | ||||||
|         std::unique_ptr<Poco::Data::PostgreSQL::Connector>  PostgresConn_; |         Poco::Data::PostgreSQL::Connector           PostgresConn_; | ||||||
|         std::unique_ptr<Poco::Data::MySQL::Connector>       MySQLConn_; |         Poco::Data::MySQL::Connector                MySQLConn_; | ||||||
|         DBType                                      dbType_ = sqlite; |         DBType                                      dbType_ = sqlite; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| @@ -114,9 +106,8 @@ namespace OpenWifi { | |||||||
|         auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); |         auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); | ||||||
|         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); |         auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); | ||||||
|         auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60); |         auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60); | ||||||
|         SQLiteConn_ = std::make_unique<Poco::Data::SQLite::Connector>(); |         SQLiteConn_.registerConnector(); | ||||||
|         SQLiteConn_->registerConnector(); |         Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 4, NumSessions, IdleTime)); | ||||||
|         Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_->name(), DBName, 4, NumSessions, IdleTime); |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -139,9 +130,8 @@ namespace OpenWifi { | |||||||
|                 ";port=" + Port + |                 ";port=" + Port + | ||||||
|                 ";compress=true;auto-reconnect=true"; |                 ";compress=true;auto-reconnect=true"; | ||||||
|  |  | ||||||
|         MySQLConn_ = std::make_unique<Poco::Data::MySQL::Connector>(); |         MySQLConn_.registerConnector(); | ||||||
|         MySQLConn_->registerConnector(); |         Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(MySQLConn_.name(), ConnectionStr, 4, NumSessions, IdleTime)); | ||||||
|         Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_->name(), ConnectionStr, 4, NumSessions, IdleTime); |  | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| @@ -166,14 +156,11 @@ namespace OpenWifi { | |||||||
|                 " port=" + Port + |                 " port=" + Port + | ||||||
|                 " connect_timeout=" + ConnectionTimeout; |                 " connect_timeout=" + ConnectionTimeout; | ||||||
|  |  | ||||||
|         PostgresConn_ = std::make_unique<Poco::Data::PostgreSQL::Connector>(); |         PostgresConn_.registerConnector(); | ||||||
|         PostgresConn_->registerConnector(); |         Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(PostgresConn_.name(), ConnectionStr, 4, NumSessions, IdleTime)); | ||||||
|         Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_->name(), ConnectionStr, 4, NumSessions, IdleTime); |  | ||||||
|  |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //OPENWIFI_STORAGE_H |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								src/ow_version.h.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/ow_version.h.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | // | ||||||
|  | // 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@"}; | ||||||
|  | } | ||||||
| @@ -183,4 +183,19 @@ namespace OpenWifi { | |||||||
|         return false; |         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); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -15,7 +15,7 @@ namespace OpenWifi { | |||||||
|     "RevocationDate 	BIGINT " |     "RevocationDate 	BIGINT " | ||||||
| */ | */ | ||||||
|  |  | ||||||
|     bool Storage::AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) { |     bool Storage::AddToken(std::string &UserID, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) { | ||||||
|         try { |         try { | ||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|             Poco::Data::Statement Insert(Sess); |             Poco::Data::Statement Insert(Sess); | ||||||
| @@ -29,7 +29,7 @@ namespace OpenWifi { | |||||||
|                 Poco::Data::Keywords::use(Token), |                 Poco::Data::Keywords::use(Token), | ||||||
|                 Poco::Data::Keywords::use(RefreshToken), |                 Poco::Data::Keywords::use(RefreshToken), | ||||||
|                 Poco::Data::Keywords::use(TokenType), |                 Poco::Data::Keywords::use(TokenType), | ||||||
|                 Poco::Data::Keywords::use(UserName), |                 Poco::Data::Keywords::use(UserID), | ||||||
|                 Poco::Data::Keywords::use(Now), |                 Poco::Data::Keywords::use(Now), | ||||||
|                 Poco::Data::Keywords::use(Expires), |                 Poco::Data::Keywords::use(Expires), | ||||||
|                 Poco::Data::Keywords::use(TimeOut), |                 Poco::Data::Keywords::use(TimeOut), | ||||||
| @@ -42,29 +42,24 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Storage::GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo) { |     bool Storage::GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate) { | ||||||
|         try { |         try { | ||||||
|  |  | ||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|             Poco::Data::Statement Select(Sess); |             Poco::Data::Statement Select(Sess); | ||||||
|  |             RevocationDate = 0 ; | ||||||
|             uint32_t RevocationDate = 0 ; |             std::string St2{"SELECT " + AllTokensFieldsForSelect + " From Tokens WHERE Token=?"}; | ||||||
|  |  | ||||||
|             std::string St2{"SELECT " + AllTokensValuesForSelect + " From Tokens WHERE Token=?"}; |  | ||||||
|             Select << ConvertParams(St2), |             Select << ConvertParams(St2), | ||||||
|                 Poco::Data::Keywords::into(UInfo.webtoken.access_token_), |                 Poco::Data::Keywords::into(UInfo.webtoken.access_token_), | ||||||
|                 Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_), |                 Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_), | ||||||
|                 Poco::Data::Keywords::into(UInfo.webtoken.token_type_), |                 Poco::Data::Keywords::into(UInfo.webtoken.token_type_), | ||||||
|                 Poco::Data::Keywords::into(UInfo.userinfo.email), |                 Poco::Data::Keywords::into(UInfo.userinfo.Id), | ||||||
|                 Poco::Data::Keywords::into(UInfo.webtoken.created_), |                 Poco::Data::Keywords::into(UInfo.webtoken.created_), | ||||||
|                 Poco::Data::Keywords::into(UInfo.webtoken.expires_in_), |                 Poco::Data::Keywords::into(UInfo.webtoken.expires_in_), | ||||||
|                 Poco::Data::Keywords::into(UInfo.webtoken.idle_timeout_), |                 Poco::Data::Keywords::into(UInfo.webtoken.idle_timeout_), | ||||||
|                 Poco::Data::Keywords::into(RevocationDate), |                 Poco::Data::Keywords::into(RevocationDate), | ||||||
|                 Poco::Data::Keywords::use(Token); |                 Poco::Data::Keywords::use(Token); | ||||||
|             Select.execute(); |             Select.execute(); | ||||||
|  |  | ||||||
|             if(RevocationDate>0) |  | ||||||
|                return false; |  | ||||||
|             return true; |             return true; | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
|             Logger_.log(E); |             Logger_.log(E); | ||||||
| @@ -116,15 +111,15 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Storage::CleanRevokedTokens(uint64_t Oldest) { |     bool Storage::CleanExpiredTokens() { | ||||||
|         try { |         try { | ||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|             Poco::Data::Statement Delete(Sess); |             Poco::Data::Statement Delete(Sess); | ||||||
|             uint64_t Now = std::time(nullptr); |             uint64_t Now = std::time(nullptr); | ||||||
|  |  | ||||||
|             std::string St2{"DELETE From Tokens WHERE Created <= ?"}; |             std::string St2{"DELETE From Tokens WHERE (Created+Expires) <= ?"}; | ||||||
|             Delete << ConvertParams(St2), |             Delete << ConvertParams(St2), | ||||||
|                 Poco::Data::Keywords::use(Oldest); |                 Poco::Data::Keywords::use(Now); | ||||||
|             Delete.execute(); |             Delete.execute(); | ||||||
|             return true; |             return true; | ||||||
|         } catch (const Poco::Exception &E) { |         } catch (const Poco::Exception &E) { | ||||||
| @@ -133,14 +128,14 @@ namespace OpenWifi { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Storage::RevokeAllTokens(std::string & username) { |     bool Storage::RevokeAllTokens(std::string & UserId) { | ||||||
|         try { |         try { | ||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|             Poco::Data::Statement Delete(Sess); |             Poco::Data::Statement Delete(Sess); | ||||||
|  |  | ||||||
|             std::string St2{"DELETE From Tokens WHERE Username=?"}; |             std::string St2{"DELETE From Tokens WHERE Username=?"}; | ||||||
|             Delete << ConvertParams(St2), |             Delete << ConvertParams(St2), | ||||||
|                 Poco::Data::Keywords::use(username); |             Poco::Data::Keywords::use(UserId); | ||||||
|             Delete.execute(); |             Delete.execute(); | ||||||
|             return true; |             return true; | ||||||
|         } catch(const Poco::Exception &E) { |         } catch(const Poco::Exception &E) { | ||||||
|   | |||||||
| @@ -80,7 +80,23 @@ namespace OpenWifi { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::string DefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"}; |     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 (...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     //  if we do not find a default user, then we need to create one based on the |     //  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. |     //  property file. We must set its flag to "must change password", this user has root privilege. | ||||||
| @@ -89,12 +105,13 @@ namespace OpenWifi { | |||||||
|         SecurityObjects::UserInfo   U; |         SecurityObjects::UserInfo   U; | ||||||
|         bool DefaultUserCreated = false; |         bool DefaultUserCreated = false; | ||||||
|  |  | ||||||
|  |         ReplaceOldDefaultUUID(); | ||||||
|         AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated); |         AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated); | ||||||
|         if(!GetUserById(DefaultUseridStockUUID,U) && !DefaultUserCreated) { |         if(!GetUserById(NewDefaultUseridStockUUID,U) && !DefaultUserCreated) { | ||||||
|             U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password",""); |             U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password",""); | ||||||
|             U.lastPasswords.push_back(U.currentPassword); |             U.lastPasswords.push_back(U.currentPassword); | ||||||
|             U.email = MicroService::instance().ConfigGetString("authentication.default.username",""); |             U.email = MicroService::instance().ConfigGetString("authentication.default.username",""); | ||||||
|             U.Id = DefaultUseridStockUUID; |             U.Id = NewDefaultUseridStockUUID; | ||||||
|             U.userRole = SecurityObjects::ROOT; |             U.userRole = SecurityObjects::ROOT; | ||||||
|             U.creationDate = std::time(nullptr); |             U.creationDate = std::time(nullptr); | ||||||
|             U.validated = true; |             U.validated = true; | ||||||
| @@ -132,7 +149,7 @@ namespace OpenWifi { | |||||||
|                 return false; |                 return false; | ||||||
|  |  | ||||||
|             if(!PasswordHashedAlready) { |             if(!PasswordHashedAlready) { | ||||||
|                 NewUser.Id = MicroService::instance().CreateUUID(); |                 NewUser.Id = MicroService::CreateUUID(); | ||||||
|                 NewUser.creationDate = std::time(nullptr); |                 NewUser.creationDate = std::time(nullptr); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,23 +15,23 @@ namespace OpenWifi { | |||||||
|             "description    varchar," |             "description    varchar," | ||||||
|             "avatar         varchar," |             "avatar         varchar," | ||||||
|             "email          varchar," |             "email          varchar," | ||||||
|             "validated      int," |             "validated      boolean," | ||||||
|             "validationEmail    varchar," |             "validationEmail    varchar," | ||||||
|             "validationDate bigint," |             "validationDate bigint," | ||||||
|             "creationDate   bigint," |             "creationDate   bigint," | ||||||
|             "validationURI  varchar," |             "validationURI  varchar," | ||||||
|             "changePassword int," |             "changePassword boolean," | ||||||
|             "lastLogin      bigint," |             "lastLogin      bigint," | ||||||
|             "currentLoginURI    varchar," |             "currentLoginURI    varchar," | ||||||
|             "lastPasswordChange bigint," |             "lastPasswordChange bigint," | ||||||
|             "lastEmailCheck     bigint," |             "lastEmailCheck     bigint," | ||||||
|             "waitingForEmailCheck   int," |             "waitingForEmailCheck   boolean," | ||||||
|             "locale             varchar," |             "locale             varchar," | ||||||
|             "notes              text," |             "notes              text," | ||||||
|             "location           varchar," |             "location           varchar," | ||||||
|             "owner              varchar," |             "owner              varchar," | ||||||
|             "suspended          int," |             "suspended          boolean," | ||||||
|             "blackListed        int," |             "blackListed        boolean," | ||||||
|             "userRole           varchar," |             "userRole           varchar," | ||||||
|             "userTypeProprietaryInfo    text," |             "userTypeProprietaryInfo    text," | ||||||
|             "securityPolicy     text," |             "securityPolicy     text," | ||||||
| @@ -111,23 +111,23 @@ namespace OpenWifi { | |||||||
|         std::string,    // description; |         std::string,    // description; | ||||||
|         std::string,    // avatar; |         std::string,    // avatar; | ||||||
|         std::string,    // email; |         std::string,    // email; | ||||||
|         uint64_t,       // bool validated = false; |         bool,       // bool validated = false; | ||||||
|         std::string,    // validationEmail; |         std::string,    // validationEmail; | ||||||
|         uint64_t,       // validationDate = 0; |         uint64_t,       // validationDate = 0; | ||||||
|         uint64_t,       // creationDate = 0; |         uint64_t,       // creationDate = 0; | ||||||
|         std::string,    // validationURI; |         std::string,    // validationURI; | ||||||
|         uint64_t,       // bool changePassword = true; |         bool,       // bool changePassword = true; | ||||||
|         uint64_t,       // lastLogin = 0; |         uint64_t,       // lastLogin = 0; | ||||||
|         std::string,    // currentLoginURI; |         std::string,    // currentLoginURI; | ||||||
|         uint64_t,       // lastPasswordChange = 0; |         uint64_t,       // lastPasswordChange = 0; | ||||||
|         uint64_t,       // lastEmailCheck = 0; |         uint64_t,       // lastEmailCheck = 0; | ||||||
|         uint64_t,      // bool waitingForEmailCheck = false; |         bool,      // bool waitingForEmailCheck = false; | ||||||
|         std::string,    // locale; |         std::string,    // locale; | ||||||
|         std::string,    // notes; |         std::string,    // notes; | ||||||
|         std::string,    // location; |         std::string,    // location; | ||||||
|         std::string,    // owner; |         std::string,    // owner; | ||||||
|         uint64_t,       // bool suspended = false; |         bool,       // bool suspended = false; | ||||||
|         uint64_t,       // bool blackListed = false; |         bool,       // bool blackListed = false; | ||||||
|         std::string,    // userRole; |         std::string,    // userRole; | ||||||
|         std::string,    // userTypeProprietaryInfo; |         std::string,    // userTypeProprietaryInfo; | ||||||
|         std::string,    // securityPolicy; |         std::string,    // securityPolicy; | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ fi | |||||||
| token="" | token="" | ||||||
| result_file=result.json | result_file=result.json | ||||||
| username="tip@ucentral.com" | username="tip@ucentral.com" | ||||||
| password="openwifi" | password="Snoopy99!!!" | ||||||
| #username="stephb@incognito.com" | #username="stephb@incognito.com" | ||||||
| #password="Snoopy98!" | #password="Snoopy98!" | ||||||
| browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl) | browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user