Compare commits

..

45 Commits

Author SHA1 Message Date
Dmitry Dunaev
05d06fce53 [WIFI-5702] Add: README note on changing default password 2021-11-14 22:37:33 +03:00
stephb9959
eaac1f1625 Adding JSON to docker build 2021-11-11 21:49:54 -08:00
stephb9959
c5f4c067bb Adding JSON to docker build 2021-11-11 21:45:24 -08:00
stephb9959
31a9e4564b Adding JSON to docker build 2021-11-11 21:23:28 -08:00
stephb9959
a9affc29bb Introducing rules on userroles. 2021-11-11 21:13:11 -08:00
stephb9959
65fc0a1d10 Adding minimal user access rights. 2021-11-11 20:35:45 -08:00
stephb9959
82c01ce438 Adding minimal user access rights. 2021-11-11 18:17:24 -08:00
stephb9959
5f900883e8 Adding error codes on login. 2021-11-11 17:52:20 -08:00
stephb9959
e97b8e64be First iteration of default user credentials creation. 2021-11-11 15:57:09 -08:00
stephb9959
6c90c75708 First iteration of default user credentials creation. 2021-11-11 15:52:23 -08:00
stephb9959
a3d86c7cf9 First iteration of default user credentials creation. 2021-11-11 15:49:19 -08:00
stephb9959
50b6ac9522 First iteration of default user credentials creation. 2021-11-11 15:42:36 -08:00
stephb9959
15b947a34d Fixing ActionLinks 2021-11-11 13:43:46 -08:00
stephb9959
160bd00a99 Fixing ActionLinks 2021-11-10 13:22:57 -08:00
stephb9959
3c7daa537a Fixing ActionLinks 2021-11-10 11:44:09 -08:00
stephb9959
c5bab1d749 Fixing ActionLinks 2021-11-10 09:22:08 -08:00
stephb9959
96c3244be0 Framework update. 2021-11-09 19:36:27 -08:00
stephb9959
7e4b515f60 Framework update. 2021-11-09 18:03:49 -08:00
stephb9959
a63f80e497 Fixing ActionLinks 2021-11-09 17:22:00 -08:00
stephb9959
2eae6cc73c Fixing ActionLinks 2021-11-09 17:06:30 -08:00
stephb9959
96f215b3c2 Fixing ActionLinks 2021-11-09 15:03:18 -08:00
stephb9959
9551384358 Fixing ActionLinks 2021-11-09 14:58:04 -08:00
stephb9959
b21c5c5e00 Fixing ActionLinks 2021-11-09 14:43:49 -08:00
stephb9959
031d35256c Fixing ActionLinks 2021-11-09 14:21:30 -08:00
stephb9959
5738fa47bb Fixing ActionLinks 2021-11-09 14:09:09 -08:00
stephb9959
fe17650333 Fixing ActionLinks 2021-11-09 13:54:32 -08:00
stephb9959
7636568fb4 Fixing ActionLinks 2021-11-09 13:41:28 -08:00
stephb9959
c0ef77eb53 Fixing ActionLinks 2021-11-09 13:24:26 -08:00
stephb9959
00742a5d0a Implementing several adjustments for security reasons. 2021-11-09 11:57:38 -08:00
stephb9959
a96f673380 Implementing several adjustments for security reasons. 2021-11-09 11:55:22 -08:00
stephb9959
53ecdb471e Implementing several adjustments for security reasons. 2021-11-09 11:52:08 -08:00
stephb9959
f80a0c5007 Implementing several adjustments for security reasons. 2021-11-09 11:50:39 -08:00
stephb9959
9e7d7ba67d Implementing several adjustments for security reasons. 2021-11-09 11:49:28 -08:00
stephb9959
b508c0d054 Implementing several adjustments for security reasons. 2021-11-09 11:48:20 -08:00
stephb9959
79788dab44 Implementing several adjustments for security reasons. 2021-11-09 11:47:25 -08:00
stephb9959
8dec946c45 Implementing several adjustments for security reasons. 2021-11-09 11:40:40 -08:00
stephb9959
43ea5ac424 Implementing several adjustments for security reasons. 2021-11-09 11:39:51 -08:00
stephb9959
328ff158cb Implementing several adjustments for security reasons. 2021-11-09 11:38:23 -08:00
stephb9959
2b89d843c3 Merge remote-tracking branch 'origin/main' 2021-11-09 11:33:29 -08:00
stephb9959
45a50483be Implementing several adjustments for security reasons. 2021-11-09 11:33:20 -08:00
Max
c8ae94a062 allow to set pod annotations (#24) 2021-11-09 12:39:36 +01:00
stephb9959
7b19143d6f Fixing some HTML templates. 2021-11-07 11:18:37 -08:00
stephb9959
bc0c889098 Fixing an issue with some www asset location. 2021-11-07 10:50:37 -08:00
stephb9959
6f8f81866f Fixing HTML policy files so they don't look like the work of a 3 year old. 2021-11-05 13:43:52 -07:00
stephb9959
f213c99816 Fixing passwordpolicy and policy path non-expansion. 2021-11-02 08:50:59 -07:00
52 changed files with 1861 additions and 719 deletions

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ _deps
*.csr *.csr
/cmake-build/ /cmake-build/
/smake-build-debug/ /smake-build-debug/
test_scripts/curl/result.json

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(owsec VERSION 2.3.0) project(owsec VERSION 2.4.0)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@@ -42,7 +42,7 @@ find_package(Boost REQUIRED system)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(AWSSDK REQUIRED COMPONENTS sns) find_package(AWSSDK REQUIRED COMPONENTS sns)
find_package(nlohmann_json REQUIRED)
find_package(CppKafka REQUIRED) find_package(CppKafka REQUIRED)
find_package(PostgreSQL REQUIRED) find_package(PostgreSQL REQUIRED)
find_package(MySQL REQUIRED) find_package(MySQL REQUIRED)
@@ -86,7 +86,11 @@ add_executable( owsec
src/MFAServer.cpp src/MFAServer.h src/MFAServer.cpp src/MFAServer.h
src/SMS_provider_aws.cpp src/SMS_provider_aws.h src/SMS_provider_aws.cpp src/SMS_provider_aws.h
src/SMS_provider.cpp src/SMS_provider.h src/SMS_provider.cpp src/SMS_provider.h
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h) src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
src/storage/storage_tokens.h
src/ActionLinkManager.cpp src/ActionLinkManager.h
)
if(NOT SMALL_BUILD) if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC target_link_libraries(owsec PUBLIC

View File

@@ -11,6 +11,8 @@ RUN apk add --update --no-cache \
RUN git clone https://github.com/stephb9959/poco /poco RUN git clone https://github.com/stephb9959/poco /poco
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
RUN git clone https://github.com/nlohmann/json /json
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
WORKDIR /aws-sdk-cpp WORKDIR /aws-sdk-cpp
@@ -37,6 +39,20 @@ RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install RUN cmake --build . --target install
WORKDIR /json
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
WORKDIR /json-schema-validator
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
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
@@ -75,6 +91,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

View File

@@ -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.
@@ -217,4 +251,4 @@ mailer.sender = OpenWIFI
mailer.loginmethod = login mailer.loginmethod = login
mailer.port = 587 mailer.port = 587
mailer.templates = $OWSEC_ROOT/templates mailer.templates = $OWSEC_ROOT/templates
``` ```

2
build
View File

@@ -1 +1 @@
14 47

View File

@@ -24,6 +24,9 @@ spec:
metadata: metadata:
annotations: annotations:
checksum/config: {{ include "owsec.config" . | sha256sum }} checksum/config: {{ include "owsec.config" . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels: labels:
app.kubernetes.io/name: {{ include "owsec.name" . }} app.kubernetes.io/name: {{ include "owsec.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/instance: {{ .Release.Name }}

View File

@@ -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: v2.3.0-RC2 tag: main
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # registry: tip-tip-wlan-cloud-ucentral.jfrog.io
@@ -95,6 +95,8 @@ tolerations: []
affinity: {} affinity: {}
podAnnotations: {}
persistence: persistence:
enabled: true enabled: true
# storageClassName: "-" # storageClassName: "-"

View File

@@ -51,6 +51,16 @@ components:
properties: properties:
ErrorCode: ErrorCode:
type: integer type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
ErrorDetails: ErrorDetails:
type: string type: string
ErrorDescription: ErrorDescription:

68
src/ActionLinkManager.cpp Normal file
View File

@@ -0,0 +1,68 @@
//
// Created by stephane bourque on 2021-11-08.
//
#include "ActionLinkManager.h"
#include "StorageService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
int ActionLinkManager::Start() {
if(!Running_)
Thr_.start(*this);
return 0;
}
void ActionLinkManager::Stop() {
if(Running_) {
Running_ = false;
Thr_.wakeUp();
Thr_.join();
}
}
void ActionLinkManager::run() {
Running_ = true ;
while(Running_) {
Poco::Thread::trySleep(2000);
if(!Running_)
break;
std::vector<SecurityObjects::ActionLink> Links;
{
std::lock_guard G(Mutex_);
StorageService()->GetActions(Links);
}
if(Links.empty())
continue;
for(auto &i:Links) {
if(!Running_)
break;
SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(i.userId,UInfo)) {
StorageService()->CancelAction(i.id);
continue;
}
if(i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD) {
if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) {
Logger_.information(Poco::format("Send password reset link to %s",UInfo.email));
}
StorageService()->SentAction(i.id);
} else if (i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) {
if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) {
Logger_.information(Poco::format("Send email verification link to %s",UInfo.email));
}
StorageService()->SentAction(i.id);
} else {
StorageService()->SentAction(i.id);
}
}
}
}
}

41
src/ActionLinkManager.h Normal file
View File

@@ -0,0 +1,41 @@
//
// Created by stephane bourque on 2021-11-08.
//
#ifndef OWSEC_ACTIONLINKMANAGER_H
#define OWSEC_ACTIONLINKMANAGER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
public:
enum Actions {
FORGOT_PASSWORD,
VERIFY_EMAIL
};
static ActionLinkManager * instance() {
static ActionLinkManager instance;
return &instance;
}
int Start() final;
void Stop() final;
void run();
private:
Poco::Thread Thr_;
std::atomic_bool Running_ = false;
ActionLinkManager() noexcept:
SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server")
{
}
};
inline ActionLinkManager * ActionLinkManager() { return ActionLinkManager::instance(); }
}
#endif //OWSEC_ACTIONLINKMANAGER_H

View File

@@ -11,6 +11,7 @@
#include "Poco/Net/OAuth20Credentials.h" #include "Poco/Net/OAuth20Credentials.h"
#include "Poco/JWT/Token.h" #include "Poco/JWT/Token.h"
#include "Poco/JWT/Signer.h" #include "Poco/JWT/Signer.h"
#include "Poco/StringTokenizer.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "StorageService.h" #include "StorageService.h"
@@ -21,7 +22,6 @@
#include "MFAServer.h" #include "MFAServer.h"
namespace OpenWifi { namespace OpenWifi {
class AuthService *AuthService::instance_ = nullptr;
AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) { AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
switch (C) { switch (C) {
@@ -46,10 +46,6 @@ namespace OpenWifi {
Signer_.setRSAKey(MicroService::instance().Key()); Signer_.setRSAKey(MicroService::instance().Key());
Signer_.addAllAlgorithms(); Signer_.addAllAlgorithms();
Logger_.notice("Starting..."); Logger_.notice("Starting...");
Secure_ = MicroService::instance().ConfigGetBool("authentication.enabled",true);
DefaultPassword_ = MicroService::instance().ConfigGetString("authentication.default.password","");
DefaultUserName_ = MicroService::instance().ConfigGetString("authentication.default.username","");
Mechanism_ = MicroService::instance().ConfigGetString("authentication.service.type","internal");
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
@@ -62,39 +58,41 @@ namespace OpenWifi {
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 )
{ {
if(!Secure_) std::lock_guard Guard(Mutex_);
return true;
std::lock_guard Guard(Mutex_);
std::string CallToken;
try { try {
Poco::Net::OAuth20Credentials Auth(Request); std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") { if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken(); CallToken = Auth.getBearerToken();
}
} catch(const Poco::Exception &E) {
}
if(!CallToken.empty()) {
if(StorageService()->IsTokenRevoked(CallToken))
return false;
auto Client = UserCache_.find(CallToken);
if( Client == UserCache_.end() )
return ValidateToken(CallToken, CallToken, UInfo);
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken;
UInfo = Client->second ;
return true;
} }
UserCache_.erase(CallToken);
StorageService()->RevokeToken(CallToken);
return false;
}
if(!CallToken.empty()) {
if(StorageService()->IsTokenRevoked(CallToken))
return false;
auto Client = UserCache_.find(CallToken);
if( Client == UserCache_.end() ) {
if(StorageService()->GetToken(SessionToken,UInfo)) {
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
return false;
}
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken;
UInfo = Client->second ;
return true;
}
UserCache_.erase(Client);
StorageService()->RevokeToken(CallToken);
return false;
}
} catch(const Poco::Exception &E) {
Logger_.log(E);
}
return false; return false;
} }
@@ -168,28 +166,6 @@ namespace OpenWifi {
return JWT; return JWT;
} }
bool AuthService::ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
std::lock_guard Guard(Mutex_);
try {
auto E = UserCache_.find(SessionToken);
if(E == UserCache_.end()) {
if(StorageService()->GetToken(SessionToken,UInfo)) {
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
} else {
UInfo = E->second;
return true;
}
} catch (const Poco::Exception &E ) {
Logger_.log(E);
}
return false;
}
void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
@@ -215,35 +191,80 @@ namespace OpenWifi {
} }
bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword); std::lock_guard G(Mutex_);
for (auto const &i:UInfo.lastPasswords) {
if (i == NewPasswordHash) { Poco::toLowerInPlace(UInfo.email);
return false; for (const auto &i:UInfo.lastPasswords) {
auto Tokens = Poco::StringTokenizer(i,"|");
if(Tokens.count()==2) {
const auto & Salt = Tokens[0];
for(const auto &j:UInfo.lastPasswords) {
auto OldTokens = Poco::StringTokenizer(j,"|");
if(OldTokens.count()==2) {
SHA2_.update(Salt+NewPassword+UInfo.email);
if(OldTokens[1]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
} else {
SHA2_.update(NewPassword+UInfo.email);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return false;
} }
} }
if(UInfo.lastPasswords.size()==HowManyOldPassword_) { if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
} }
UInfo.lastPasswords.push_back(NewPasswordHash);
UInfo.currentPassword = NewPasswordHash; auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
UInfo.lastPasswords.push_back(NewHash);
UInfo.currentPassword = NewHash;
UInfo.changePassword = false; UInfo.changePassword = false;
return true; return true;
} }
AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ) static std::string GetMeSomeSalt() {
auto start = std::chrono::high_resolution_clock::now();
return std::to_string(start.time_since_epoch().count());
}
std::string AuthService::ComputeNewPasswordHash(const std::string &UserName, const std::string &Password) {
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Salt = GetMeSomeSalt();
SHA2_.update(Salt + Password + UName );
return Salt + "|" + Utils::ToHex(SHA2_.digest());
}
bool AuthService::ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
std::lock_guard G(Mutex_);
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Tokens = Poco::StringTokenizer(StoredPassword,"|");
if(Tokens.count()==1) {
SHA2_.update(Password+UName);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return true;
} else if (Tokens.count()==2) {
SHA2_.update(Tokens[0]+Password+UName);
if(Tokens[1]==Utils::ToHex(SHA2_.digest()))
return true;
}
return false;
}
UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
SecurityObjects::AclTemplate ACL;
Poco::toLowerInPlace(UserName); Poco::toLowerInPlace(UserName);
auto PasswordHash = ComputePasswordHash(UserName, Password);
if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) { if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION; return USERNAME_PENDING_VERIFICATION;
} }
if(PasswordHash != UInfo.userinfo.currentPassword) { if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
return INVALID_CREDENTIALS; return INVALID_CREDENTIALS;
} }
@@ -273,51 +294,31 @@ namespace OpenWifi {
return SUCCESS; return SUCCESS;
} }
if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_)
{
ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
UInfo.webtoken.acl_template_ = ACL;
UInfo.userinfo.email = DefaultUserName_;
UInfo.userinfo.currentPassword = DefaultPassword_;
UInfo.userinfo.name = DefaultUserName_;
UInfo.userinfo.userRole = SecurityObjects::ROOT;
CreateToken(UserName, UInfo );
return SUCCESS;
}
return INVALID_CREDENTIALS; return INVALID_CREDENTIALS;
} }
std::string AuthService::ComputePasswordHash(const std::string &UserName, const std::string &Password) { bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
std::string UName = Poco::trim(Poco::toLower(UserName));
SHA2_.update(Password + UName);
return Utils::ToHex(SHA2_.digest());
}
bool AuthService::SendEmailToUser(std::string &Email, EMAIL_REASON Reason) {
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(StorageService()->GetUserByEmail(Email,UInfo)) { if(StorageService()->GetUserByEmail(Email,UInfo)) {
switch (Reason) { switch (Reason) {
case FORGOT_PASSWORD: { case FORGOT_PASSWORD: {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg"; Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "Password reset link"; Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] = Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
} }
break; break;
case EMAIL_VERIFICATION: { case EMAIL_VERIFICATION: {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg"; Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "EMail Address Verification"; Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] = Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true; UInfo.waitingForEmailCheck = true;
} }
@@ -326,19 +327,20 @@ namespace OpenWifi {
default: default:
break; break;
} }
return true;
} }
return false; return false;
} }
bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
MessageAttributes Attrs; SecurityObjects::ActionLink A;
Attrs[RECIPIENT_EMAIL] = UInfo.email; A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
Attrs[LOGO] = "logo.jpg"; A.userId = UInfo.email;
Attrs[SUBJECT] = "EMail Address Verification"; A.id = MicroService::instance().CreateUUID();
Attrs[ACTION_LINK] = A.created = std::time(nullptr);
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ; A.expires = A.created + 24*60*60;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); StorageService()->CreateAction(A);
UInfo.waitingForEmailCheck = true; UInfo.waitingForEmailCheck = true;
return true; return true;
} }

View File

@@ -35,16 +35,6 @@ namespace OpenWifi{
CUSTOM CUSTOM
}; };
enum AUTH_ERROR {
SUCCESS,
PASSWORD_CHANGE_REQUIRED,
INVALID_CREDENTIALS,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR
};
enum EMAIL_REASON { enum EMAIL_REASON {
FORGOT_PASSWORD, FORGOT_PASSWORD,
EMAIL_VERIFICATION EMAIL_VERIFICATION
@@ -54,19 +44,16 @@ namespace OpenWifi{
static int AccessTypeToInt(ACCESS_TYPE T); static int AccessTypeToInt(ACCESS_TYPE T);
static AuthService *instance() { static AuthService *instance() {
if (instance_ == nullptr) { static AuthService instance;
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 );
[[nodiscard]] AUTH_ERROR 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 );
void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo );
[[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_;};
void Logout(const std::string &token, bool EraseFromCache=true); void Logout(const std::string &token, bool EraseFromCache=true);
@@ -77,26 +64,31 @@ namespace OpenWifi{
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request); [[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);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::WebToken & UserInfo );
[[nodiscard]] std::string ComputePasswordHash(const std::string &UserName, const std::string &Password); [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password);
[[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
[[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
[[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
[[nodiscard]] static bool SendEmailToUser(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);
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
}
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
return MicroService::instance().DataDir() + "/wwwassets/the_logo.png";
}
private: private:
static AuthService *instance_;
bool Secure_ = false ;
std::string DefaultUserName_;
std::string DefaultPassword_;
std::string Mechanism_;
Poco::JWT::Signer Signer_; Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_; Poco::SHA2Engine SHA2_;
SecurityObjects::UserInfoCache UserCache_; 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;
uint64_t HowManyOldPassword_=5; uint64_t HowManyOldPassword_=5;

View File

@@ -30,6 +30,7 @@
#include "SMTPMailerService.h" #include "SMTPMailerService.h"
#include "AuthService.h" #include "AuthService.h"
#include "SMSSender.h" #include "SMSSender.h"
#include "ActionLinkManager.h"
namespace OpenWifi { namespace OpenWifi {
class Daemon *Daemon::instance_ = nullptr; class Daemon *Daemon::instance_ = nullptr;
@@ -44,7 +45,9 @@ namespace OpenWifi {
SubSystemVec{ SubSystemVec{
StorageService(), StorageService(),
SMSSender(), SMSSender(),
ActionLinkManager(),
SMTPMailerService(), SMTPMailerService(),
RESTAPI_RateLimiter(),
AuthService() AuthService()
}); });
} }
@@ -53,8 +56,8 @@ namespace OpenWifi {
void Daemon::initialize() { void Daemon::initialize() {
AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html"); AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html");
PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html"); PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html");
} }
void MicroServicePostInitialization() { void MicroServicePostInitialization() {

View File

@@ -6,11 +6,10 @@
#include "SMSSender.h" #include "SMSSender.h"
#include "SMTPMailerService.h" #include "SMTPMailerService.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "AuthService.h"
namespace OpenWifi { namespace OpenWifi {
class MFAServer * MFAServer::instance_ = nullptr;
int MFAServer::Start() { int MFAServer::Start() {
return 0; return 0;
} }
@@ -47,7 +46,7 @@ namespace OpenWifi {
if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
Attrs[LOGO] = "logo.jpg"; Attrs[LOGO] = AuthService::GetLogoAssetURI();
Attrs[SUBJECT] = "Login validation code"; Attrs[SUBJECT] = "Login validation code";
Attrs[CHALLENGE_CODE] = Challenge; Attrs[CHALLENGE_CODE] = Challenge;
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);

View File

@@ -24,24 +24,21 @@ namespace OpenWifi {
int Start() override; int Start() override;
void Stop() override; void Stop() override;
static MFAServer *instance() { static MFAServer *instance() {
if (instance_ == nullptr) { static MFAServer instance;
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);
bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
bool MethodEnabled(const std::string &Method); static bool MethodEnabled(const std::string &Method);
bool ResendCode(const std::string &uuid); bool ResendCode(const std::string &uuid);
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(rand() % 999999);
} }
private: private:
static MFAServer * instance_;
MFAChallengeCache Cache_; MFAChallengeCache Cache_;
MFAServer() noexcept: MFAServer() noexcept:
SubSystemServer("MFServer", "MFA-SVR", "mfa") SubSystemServer("MFServer", "MFA-SVR", "mfa")

View File

@@ -11,46 +11,61 @@
#include "Daemon.h" #include "Daemon.h"
namespace OpenWifi { namespace OpenWifi {
void RESTAPI_action_links::DoGet() { void RESTAPI_action_links::DoGet() {
auto Action = GetParameter("action",""); auto Action = GetParameter("action","");
auto Id = GetParameter("id",""); auto Id = GetParameter("id","");
SecurityObjects::ActionLink Link;
if(!StorageService()->GetActionLink(Id,Link))
return DoReturnA404();
if(Action=="password_reset") if(Action=="password_reset")
return RequestResetPassword(Id); return RequestResetPassword(Link);
else if(Action=="email_verification") else if(Action=="email_verification")
return DoEmailVerification(Id); return DoEmailVerification(Link);
else else
return DoReturnA404(); return DoReturnA404();
} }
void RESTAPI_action_links::DoPost() { void RESTAPI_action_links::DoPost() {
auto Action = GetParameter("action",""); auto Action = GetParameter("action","");
auto Id = GetParameter("id","");
Logger_.information(Poco::format("COMPLETE-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
if(Action=="password_reset") if(Action=="password_reset")
CompleteResetPassword(Id); return CompleteResetPassword();
else else
DoReturnA404(); return DoReturnA404();
} }
void RESTAPI_action_links::RequestResetPassword(std::string &Id) { void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id)); Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId));
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset.html"}; Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
Types::StringPairVec FormVars{ {"UUID", Id}, Types::StringPairVec FormVars{ {"UUID", Link.id},
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
SendHTMLFileBack(FormFile,FormVars); SendHTMLFileBack(FormFile,FormVars);
} }
void RESTAPI_action_links::CompleteResetPassword(std::string &Id) { void RESTAPI_action_links::CompleteResetPassword() {
// form has been posted... // form has been posted...
RESTAPI_PartHandler PartHandler; RESTAPI_PartHandler PartHandler;
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler); Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
if (!Form.empty()) { if (!Form.empty()) {
auto Password1 = Form.get("password1","bla"); auto Password1 = Form.get("password1","bla");
auto Password2 = Form.get("password1","blu"); auto Password2 = Form.get("password1","blu");
Id = Form.get("id",""); auto Id = Form.get("id","");
auto Now = std::time(nullptr);
SecurityObjects::ActionLink Link;
if(!StorageService()->GetActionLink(Id,Link))
return DoReturnA404();
if(Now > Link.expires) {
StorageService()->CancelAction(Id);
return DoReturnA404();
}
if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) { if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id}, Types::StringPairVec FormVars{ {"UUID", Id},
@@ -62,7 +77,7 @@ namespace OpenWifi {
} }
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(Id,UInfo)) { if(!StorageService()->GetUserById(Link.userId,UInfo)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id}, Types::StringPairVec FormVars{ {"UUID", Id},
{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
@@ -82,37 +97,45 @@ namespace OpenWifi {
{"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
return SendHTMLFileBack(FormFile,FormVars); return SendHTMLFileBack(FormFile,FormVars);
} }
StorageService()->UpdateUserInfo(UInfo.email,Id,UInfo); StorageService()->UpdateUserInfo(UInfo.email,Link.userId,UInfo);
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
Types::StringPairVec FormVars{ {"UUID", Id}, Types::StringPairVec FormVars{ {"UUID", Id},
{"USERNAME", UInfo.email}, {"USERNAME", UInfo.email},
{"ACTION_LINK",MicroService::instance().GetUIURI()}}; {"ACTION_LINK",MicroService::instance().GetUIURI()}};
StorageService()->CompleteAction(Id);
SendHTMLFileBack(FormFile,FormVars); SendHTMLFileBack(FormFile,FormVars);
} else { } else {
DoReturnA404(); DoReturnA404();
} }
} }
void RESTAPI_action_links::DoEmailVerification(std::string &Id) { void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
SecurityObjects::UserInfo UInfo; auto Now = std::time(nullptr);
Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), Id)); if(Now > Link.expires) {
if (!StorageService()->GetUserById(Id, UInfo)) { StorageService()->CancelAction(Link.id);
Types::StringPairVec FormVars{{"UUID", Id}, return DoReturnA404();
}
SecurityObjects::UserInfo UInfo;
if (!StorageService()->GetUserById(Link.userId, UInfo)) {
Types::StringPairVec FormVars{{"UUID", Link.id},
{"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
return SendHTMLFileBack(FormFile, FormVars); return SendHTMLFileBack(FormFile, FormVars);
} }
Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email));
UInfo.waitingForEmailCheck = false; UInfo.waitingForEmailCheck = false;
UInfo.validated = true; UInfo.validated = true;
UInfo.lastEmailCheck = std::time(nullptr); UInfo.lastEmailCheck = std::time(nullptr);
UInfo.validationDate = std::time(nullptr); UInfo.validationDate = std::time(nullptr);
StorageService()->UpdateUserInfo(UInfo.email, Id, UInfo); StorageService()->UpdateUserInfo(UInfo.email, Link.userId, UInfo);
Types::StringPairVec FormVars{{"UUID", Id}, Types::StringPairVec FormVars{{"UUID", Link.id},
{"USERNAME", UInfo.email}, {"USERNAME", UInfo.email},
{"ACTION_LINK",MicroService::instance().GetUIURI()}}; {"ACTION_LINK",MicroService::instance().GetUIURI()}};
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
StorageService()->CompleteAction(Link.id);
SendHTMLFileBack(FormFile, FormVars); SendHTMLFileBack(FormFile, FormVars);
} }

View File

@@ -19,11 +19,12 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_OPTIONS}, Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, Server,
Internal, Internal,
false) {} false,
true, RateLimit{.Interval=1000,.MaxCalls=5}) {}
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(std::string &Id); void RequestResetPassword(SecurityObjects::ActionLink &Link);
void CompleteResetPassword(std::string &Id); void CompleteResetPassword();
void DoEmailVerification(std::string &Id); void DoEmailVerification(SecurityObjects::ActionLink &Link);
void DoReturnA404(); void DoReturnA404();
void DoGet() final; void DoGet() final;

View File

@@ -14,11 +14,12 @@
#include "MFAServer.h" #include "MFAServer.h"
#include "framework/RESTAPI_protocol.h" #include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "StorageService.h"
namespace OpenWifi { namespace OpenWifi {
void RESTAPI_oauth2Handler::DoGet() { void RESTAPI_oauth2Handler::DoGet() {
if (!IsAuthorized()) { if (!IsAuthorized()) {
return UnAuthorized("Not authorized."); return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
} }
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
if(GetMe) { if(GetMe) {
@@ -27,7 +28,7 @@ namespace OpenWifi {
UserInfo_.userinfo.to_json(Me); UserInfo_.userinfo.to_json(Me);
return ReturnObject(Me); return ReturnObject(Me);
} }
BadRequest("Ill-formed request. Please consult documentation."); BadRequest(RESTAPI::Errors::UnrecognizedRequest);
} }
void RESTAPI_oauth2Handler::DoDelete() { void RESTAPI_oauth2Handler::DoDelete() {
@@ -63,31 +64,46 @@ namespace OpenWifi {
} }
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
// Send an email to the userId SecurityObjects::UserInfo UInfo1;
Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); auto UserExists = StorageService()->GetUserByEmail(userId,UInfo1);
SecurityObjects::UserInfoAndPolicy UInfo; if(UserExists) {
if(AuthService::SendEmailToUser(userId,AuthService::FORGOT_PASSWORD)) Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
Logger_.information(Poco::format("Send password reset link to %s",userId)); SecurityObjects::ActionLink NewLink;
UInfo.webtoken.userMustChangePassword=true;
Poco::JSON::Object ReturnObj; NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
UInfo.webtoken.to_json(ReturnObj); NewLink.id = MicroService::instance().CreateUUID();
return ReturnObject(ReturnObj); NewLink.userId = UInfo1.Id;
NewLink.created = std::time(nullptr);
NewLink.expires = NewLink.created + (24*60*60);
StorageService()->CreateAction(NewLink);
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
} else {
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
} }
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("uuid")) { if(Obj->has(RESTAPI::Protocol::UUID)) {
auto uuid = Obj->get("uuid").toString(); auto uuid = Obj->get(RESTAPI::Protocol::UUID).toString();
if(MFAServer().ResendCode(uuid)) if(MFAServer().ResendCode(uuid))
return OK(); return OK();
return UnAuthorized("Unrecognized credentials (username/password).");
} }
return UnAuthorized("Unrecognized credentials (username/password)."); return UnAuthorized(RESTAPI::Errors::InvalidCredentials);
} }
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("uuid")) { if(Obj->has(RESTAPI::Protocol::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;
@@ -95,29 +111,36 @@ namespace OpenWifi {
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} }
} }
return UnAuthorized("Unrecognized credentials (username/password)."); return UnAuthorized(RESTAPI::Errors::InvalidCredentials);
} }
SecurityObjects::UserInfoAndPolicy UInfo; SecurityObjects::UserInfoAndPolicy UInfo;
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo); auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
if (Code==AuthService::SUCCESS) { if (Code==SUCCESS) {
Poco::JSON::Object ReturnObj; Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) { if(AuthService()->RequiresMFA(UInfo)) {
if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) { if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} }
Logger_.warning("MFA Seems ot be broken. Please fix. Disabling MFA checking for now."); Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
} }
UInfo.webtoken.to_json(ReturnObj); UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} else { } else {
switch(Code) { switch(Code) {
case AuthService::INVALID_CREDENTIALS: return UnAuthorized("Unrecognized credentials (username/password)."); break; case INVALID_CREDENTIALS:
case AuthService::PASSWORD_INVALID: return UnAuthorized("Invalid password."); break; return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code);
case AuthService::PASSWORD_ALREADY_USED: return UnAuthorized("Password already used previously."); break; case PASSWORD_INVALID:
case AuthService::USERNAME_PENDING_VERIFICATION: return UnAuthorized("User access pending email verification."); break; return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code);
case AuthService::PASSWORD_CHANGE_REQUIRED: return UnAuthorized("Password change expected."); break; case PASSWORD_ALREADY_USED:
default: return UnAuthorized("Unrecognized credentials (username/password)."); break; return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code);
case USERNAME_PENDING_VERIFICATION:
return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code);
case PASSWORD_CHANGE_REQUIRED:
return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code);
default:
return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break;
} }
return; return;
} }

View File

@@ -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) {} Internal, false, true , RateLimit{.Interval=2000,.MaxCalls=5}) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; }; 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;

View File

@@ -25,7 +25,11 @@ namespace OpenWifi {
} else if(!StorageService()->GetUserById(Id,UInfo)) { } else if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound(); return NotFound();
} }
Poco::JSON::Object UserInfoObject; Poco::JSON::Object UserInfoObject;
UInfo.currentPassword.clear();
UInfo.lastPasswords.clear();
UInfo.oauthType.clear();
UInfo.to_json(UserInfoObject); UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject); ReturnObject(UserInfoObject);
} }
@@ -36,17 +40,30 @@ 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) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
return NotFound(); return NotFound();
} }
if(AuthService()->DeleteUserFromCache(UInfo.email)) if(AuthService()->DeleteUserFromCache(UInfo.email)) {
; // nothing to do
}
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));
@@ -66,6 +83,14 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidUserRole); return BadRequest(RESTAPI::Errors::InvalidUserRole);
} }
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && UInfo.userRole == SecurityObjects::ROOT) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
Poco::toLowerInPlace(UInfo.email); Poco::toLowerInPlace(UInfo.email);
if(!Utils::ValidEMailAddress(UInfo.email)) { if(!Utils::ValidEMailAddress(UInfo.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress); return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
@@ -115,6 +140,14 @@ namespace OpenWifi {
return NotFound(); return NotFound();
} }
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole == SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
SecurityObjects::UserInfo NewUser; SecurityObjects::UserInfo NewUser;
auto RawObject = ParseStream(); auto RawObject = ParseStream();
if(!NewUser.from_json(RawObject)) { if(!NewUser.from_json(RawObject)) {
@@ -136,8 +169,19 @@ namespace OpenWifi {
AssignIfPresent(RawObject,"suspended", Existing.suspended); AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed); AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole")) if(RawObject->has("userRole")) {
Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(NewRole!=Existing.userRole) {
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(Id==UserInfo_.userinfo.Id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Existing.userRole = NewRole;
}
}
if(RawObject->has("notes")) { if(RawObject->has("notes")) {
SecurityObjects::NoteInfoVec NIV; SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
@@ -161,26 +205,27 @@ namespace OpenWifi {
} }
if(RawObject->has("userTypeProprietaryInfo")) { if(RawObject->has("userTypeProprietaryInfo")) {
bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled;
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") {
auto PropInfo = RawObject->get("userTypeProprietaryInfo");
auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>();
if(PInfo->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
}
if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method; Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
auto MobileStruct = RawObject->get("userTypeProprietaryInfo");
auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>();
if(Info->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
}
if(!NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
} else if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
} else {
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest(RESTAPI::Errors::BadMFAMethod);
}
} }
} }

View File

@@ -16,11 +16,14 @@ namespace OpenWifi {
Poco::JSON::Array ArrayObj; Poco::JSON::Array ArrayObj;
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) { if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) {
for (const auto &i : Users) { for (auto &i : Users) {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
if (IdOnly) { if (IdOnly) {
ArrayObj.add(i.Id); ArrayObj.add(i.Id);
} else { } else {
i.currentPassword.clear();
i.lastPasswords.clear();
i.oauthType.clear();
i.to_json(Obj); i.to_json(Obj);
ArrayObj.add(Obj); ArrayObj.add(Obj);
} }
@@ -38,6 +41,9 @@ namespace OpenWifi {
if (IdOnly) { if (IdOnly) {
ArrayObj.add(UInfo.Id); ArrayObj.add(UInfo.Id);
} else { } else {
UInfo.currentPassword.clear();
UInfo.lastPasswords.clear();
UInfo.oauthType.clear();
UInfo.to_json(Obj); UInfo.to_json(Obj);
ArrayObj.add(Obj); ArrayObj.add(Obj);
} }

View File

@@ -68,7 +68,7 @@ namespace OpenWifi::GWObjects {
#endif #endif
} }
bool Device::from_json(Poco::JSON::Object::Ptr Obj) { bool Device::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"serialNumber",SerialNumber); field_from_json(Obj,"serialNumber",SerialNumber);
field_from_json(Obj,"deviceType",DeviceType); field_from_json(Obj,"deviceType",DeviceType);
@@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"attachFile", AttachDate); field_to_json(Obj,"attachFile", AttachDate);
} }
bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) { bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"name",Name); field_from_json(Obj,"name",Name);
field_from_json(Obj,"configuration",Configuration); field_from_json(Obj,"configuration",Configuration);
@@ -166,7 +166,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"created", created); field_to_json(Obj,"created", created);
} }
bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr Obj) { bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"serialNumber",serialNumber); field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"author",author); field_from_json(Obj,"author",author);

View File

@@ -59,7 +59,7 @@ namespace OpenWifi::GWObjects {
std::string DevicePassword; std::string DevicePassword;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const; void to_json_with_status(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj); bool from_json(Poco::JSON::Object::Ptr &Obj);
void Print() const; void Print() const;
}; };
@@ -116,7 +116,7 @@ namespace OpenWifi::GWObjects {
uint64_t Created; uint64_t Created;
uint64_t LastModified; uint64_t LastModified;
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 CommandDetails { struct CommandDetails {
@@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects {
std::string author; std::string author;
uint64_t created; uint64_t created;
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 RttySessionDetails { struct RttySessionDetails {

View File

@@ -10,27 +10,30 @@
#include "RESTAPI_ProvObjects.h" #include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::ProvObjects { namespace OpenWifi::ProvObjects {
void ObjectInfo::to_json(Poco::JSON::Object &Obj) const { void ObjectInfo::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj,"id",id); field_to_json(Obj,"id",id);
RESTAPI_utils::field_to_json(Obj,"name",name); field_to_json(Obj,"name",name);
RESTAPI_utils::field_to_json(Obj,"description",description); field_to_json(Obj,"description",description);
RESTAPI_utils::field_to_json(Obj,"created",created); field_to_json(Obj,"created",created);
RESTAPI_utils::field_to_json(Obj,"modified",modified); field_to_json(Obj,"modified",modified);
RESTAPI_utils::field_to_json(Obj,"notes",notes); field_to_json(Obj,"notes",notes);
RESTAPI_utils::field_to_json(Obj,"tags",tags); field_to_json(Obj,"tags",tags);
} }
bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json(Obj,"id",id); field_from_json(Obj,"id",id);
RESTAPI_utils::field_from_json(Obj,"name",name); field_from_json(Obj,"name",name);
RESTAPI_utils::field_from_json(Obj,"description",description); field_from_json(Obj,"description",description);
RESTAPI_utils::field_from_json(Obj,"created",created); field_from_json(Obj,"created",created);
RESTAPI_utils::field_from_json(Obj,"modified",modified); field_from_json(Obj,"modified",modified);
RESTAPI_utils::field_from_json(Obj,"notes",notes); field_from_json(Obj,"notes",notes);
RESTAPI_utils::field_from_json(Obj,"tags",tags); field_from_json(Obj,"tags",tags);
return true; return true;
} catch(...) { } catch(...) {
@@ -39,18 +42,18 @@ namespace OpenWifi::ProvObjects {
} }
void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const { void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"users",users); field_to_json( Obj,"users",users);
RESTAPI_utils::field_to_json( Obj,"resources",resources); field_to_json( Obj,"resources",resources);
RESTAPI_utils::field_to_json( Obj,"access",access); field_to_json( Obj,"access",access);
RESTAPI_utils::field_to_json( Obj,"policy",policy); field_to_json( Obj,"policy",policy);
} }
bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"users",users); field_from_json( Obj,"users",users);
RESTAPI_utils::field_from_json( Obj,"resources",resources); field_from_json( Obj,"resources",resources);
RESTAPI_utils::field_from_json( Obj,"access",access); field_from_json( Obj,"access",access);
RESTAPI_utils::field_from_json( Obj,"policy",policy); field_from_json( Obj,"policy",policy);
return true; return true;
} catch(...) { } catch(...) {
@@ -60,17 +63,17 @@ namespace OpenWifi::ProvObjects {
void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const { void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json(Obj, "entries", entries); field_to_json(Obj, "entries", entries);
RESTAPI_utils::field_to_json(Obj, "inUse", inUse); field_to_json(Obj, "inUse", inUse);
RESTAPI_utils::field_to_json(Obj, "entity", entity); field_to_json(Obj, "entity", entity);
} }
bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json(Obj, "entries", entries); field_from_json(Obj, "entries", entries);
RESTAPI_utils::field_from_json(Obj, "inUse", inUse); field_from_json(Obj, "inUse", inUse);
RESTAPI_utils::field_from_json(Obj, "entity", entity); field_from_json(Obj, "entity", entity);
return true; return true;
} catch(...) { } catch(...) {
@@ -80,31 +83,31 @@ namespace OpenWifi::ProvObjects {
void Entity::to_json(Poco::JSON::Object &Obj) const { void Entity::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"venues",venues); field_to_json( Obj,"venues",venues);
RESTAPI_utils::field_to_json( Obj,"children",children); field_to_json( Obj,"children",children);
RESTAPI_utils::field_to_json( Obj,"contacts",contacts); field_to_json( Obj,"contacts",contacts);
RESTAPI_utils::field_to_json( Obj,"locations",locations); field_to_json( Obj,"locations",locations);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"devices",devices); field_to_json( Obj,"devices",devices);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP); field_to_json( Obj,"sourceIP",sourceIP);
} }
bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"venues",venues); field_from_json( Obj,"venues",venues);
RESTAPI_utils::field_from_json( Obj,"children",children); field_from_json( Obj,"children",children);
RESTAPI_utils::field_from_json( Obj,"contacts",contacts); field_from_json( Obj,"contacts",contacts);
RESTAPI_utils::field_from_json( Obj,"locations",locations); field_from_json( Obj,"locations",locations);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"devices",devices); field_from_json( Obj,"devices",devices);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP); field_from_json( Obj,"sourceIP",sourceIP);
return true; return true;
} catch(...) { } catch(...) {
@@ -113,14 +116,14 @@ namespace OpenWifi::ProvObjects {
} }
void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const { void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"child",child); field_to_json( Obj,"child",child);
} }
bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"child",child); field_from_json( Obj,"child",child);
return true; return true;
} catch (...) { } catch (...) {
@@ -130,37 +133,37 @@ namespace OpenWifi::ProvObjects {
void Venue::to_json(Poco::JSON::Object &Obj) const { void Venue::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"children",children); field_to_json( Obj,"children",children);
RESTAPI_utils::field_to_json( Obj,"devices",devices); field_to_json( Obj,"devices",devices);
RESTAPI_utils::field_to_json( Obj,"topology",topology); field_to_json( Obj,"topology",topology);
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"design",design); field_to_json( Obj,"design",design);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"contact",contact); field_to_json( Obj,"contact",contact);
RESTAPI_utils::field_to_json( Obj,"location",location); field_to_json( Obj,"location",location);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP); field_to_json( Obj,"sourceIP",sourceIP);
} }
bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"children",children); field_from_json( Obj,"children",children);
RESTAPI_utils::field_from_json( Obj,"devices",devices); field_from_json( Obj,"devices",devices);
RESTAPI_utils::field_from_json( Obj,"topology",topology); field_from_json( Obj,"topology",topology);
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"design",design); field_from_json( Obj,"design",design);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"contact",contact); field_from_json( Obj,"contact",contact);
RESTAPI_utils::field_from_json( Obj,"location",location); field_from_json( Obj,"location",location);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP); field_from_json( Obj,"sourceIP",sourceIP);
return true; return true;
} catch (...) { } catch (...) {
@@ -169,16 +172,16 @@ namespace OpenWifi::ProvObjects {
} }
void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"id",id); field_to_json( Obj,"id",id);
RESTAPI_utils::field_to_json( Obj,"entity",loginId); field_to_json( Obj,"entity",loginId);
RESTAPI_utils::field_to_json( Obj,"children",userType); field_to_json( Obj,"children",userType);
} }
bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) { bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"id",id); field_from_json( Obj,"id",id);
RESTAPI_utils::field_from_json( Obj,"entity",loginId); field_from_json( Obj,"entity",loginId);
RESTAPI_utils::field_from_json( Obj,"children",userType); field_from_json( Obj,"children",userType);
return true; return true;
} catch(...) { } catch(...) {
} }
@@ -187,17 +190,17 @@ namespace OpenWifi::ProvObjects {
void ManagementRole::to_json(Poco::JSON::Object &Obj) const { void ManagementRole::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"users",users); field_to_json( Obj,"users",users);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
} }
bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"users",users); field_from_json( Obj,"users",users);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
return true; return true;
} catch(...) { } catch(...) {
} }
@@ -206,39 +209,39 @@ namespace OpenWifi::ProvObjects {
void Location::to_json(Poco::JSON::Object &Obj) const { void Location::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type)); field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
RESTAPI_utils::field_to_json( Obj,"buildingName",buildingName); field_to_json( Obj,"buildingName",buildingName);
RESTAPI_utils::field_to_json( Obj,"addressLines",addressLines); field_to_json( Obj,"addressLines",addressLines);
RESTAPI_utils::field_to_json( Obj,"city",city); field_to_json( Obj,"city",city);
RESTAPI_utils::field_to_json( Obj,"state",state); field_to_json( Obj,"state",state);
RESTAPI_utils::field_to_json( Obj,"postal",postal); field_to_json( Obj,"postal",postal);
RESTAPI_utils::field_to_json( Obj,"country",country); field_to_json( Obj,"country",country);
RESTAPI_utils::field_to_json( Obj,"phones",phones); field_to_json( Obj,"phones",phones);
RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles); field_to_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_to_json( Obj,"geoCode",geoCode); field_to_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
} }
bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
std::string tmp_type; std::string tmp_type;
RESTAPI_utils::field_from_json( Obj,"type", tmp_type); field_from_json( Obj,"type", tmp_type);
type = location_from_string(tmp_type); type = location_from_string(tmp_type);
RESTAPI_utils::field_from_json( Obj,"buildingName",buildingName); field_from_json( Obj,"buildingName",buildingName);
RESTAPI_utils::field_from_json( Obj,"addressLines",addressLines); field_from_json( Obj,"addressLines",addressLines);
RESTAPI_utils::field_from_json( Obj,"city",city); field_from_json( Obj,"city",city);
RESTAPI_utils::field_from_json( Obj,"state",state); field_from_json( Obj,"state",state);
RESTAPI_utils::field_from_json( Obj,"postal",postal); field_from_json( Obj,"postal",postal);
RESTAPI_utils::field_from_json( Obj,"country",country); field_from_json( Obj,"country",country);
RESTAPI_utils::field_from_json( Obj,"phones",phones); field_from_json( Obj,"phones",phones);
RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles); field_from_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode); field_from_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
return true; return true;
} catch (...) { } catch (...) {
@@ -248,43 +251,43 @@ namespace OpenWifi::ProvObjects {
void Contact::to_json(Poco::JSON::Object &Obj) const { void Contact::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"type", to_string(type)); field_to_json( Obj,"type", to_string(type));
RESTAPI_utils::field_to_json( Obj,"title",title); field_to_json( Obj,"title",title);
RESTAPI_utils::field_to_json( Obj,"salutation",salutation); field_to_json( Obj,"salutation",salutation);
RESTAPI_utils::field_to_json( Obj,"firstname",firstname); field_to_json( Obj,"firstname",firstname);
RESTAPI_utils::field_to_json( Obj,"lastname",lastname); field_to_json( Obj,"lastname",lastname);
RESTAPI_utils::field_to_json( Obj,"initials",initials); field_to_json( Obj,"initials",initials);
RESTAPI_utils::field_to_json( Obj,"visual",visual); field_to_json( Obj,"visual",visual);
RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles); field_to_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_to_json( Obj,"phones",phones); field_to_json( Obj,"phones",phones);
RESTAPI_utils::field_to_json( Obj,"primaryEmail",primaryEmail); field_to_json( Obj,"primaryEmail",primaryEmail);
RESTAPI_utils::field_to_json( Obj,"secondaryEmail",secondaryEmail); field_to_json( Obj,"secondaryEmail",secondaryEmail);
RESTAPI_utils::field_to_json( Obj,"accessPIN",accessPIN); field_to_json( Obj,"accessPIN",accessPIN);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
} }
bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
std::string tmp_type; std::string tmp_type;
RESTAPI_utils::field_from_json( Obj,"type", tmp_type); field_from_json( Obj,"type", tmp_type);
type = contact_from_string(tmp_type); type = contact_from_string(tmp_type);
RESTAPI_utils::field_from_json( Obj,"title",title); field_from_json( Obj,"title",title);
RESTAPI_utils::field_from_json( Obj,"salutation",salutation); field_from_json( Obj,"salutation",salutation);
RESTAPI_utils::field_from_json( Obj,"firstname",firstname); field_from_json( Obj,"firstname",firstname);
RESTAPI_utils::field_from_json( Obj,"lastname",lastname); field_from_json( Obj,"lastname",lastname);
RESTAPI_utils::field_from_json( Obj,"initials",initials); field_from_json( Obj,"initials",initials);
RESTAPI_utils::field_from_json( Obj,"visual",visual); field_from_json( Obj,"visual",visual);
RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles); field_from_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_from_json( Obj,"phones",phones); field_from_json( Obj,"phones",phones);
RESTAPI_utils::field_from_json( Obj,"primaryEmail",primaryEmail); field_from_json( Obj,"primaryEmail",primaryEmail);
RESTAPI_utils::field_from_json( Obj,"secondaryEmail",secondaryEmail); field_from_json( Obj,"secondaryEmail",secondaryEmail);
RESTAPI_utils::field_from_json( Obj,"accessPIN",accessPIN); field_from_json( Obj,"accessPIN",accessPIN);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
return true; return true;
} catch (...) { } catch (...) {
@@ -294,35 +297,35 @@ namespace OpenWifi::ProvObjects {
void InventoryTag::to_json(Poco::JSON::Object &Obj) const { void InventoryTag::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json(Obj, "serialNumber", serialNumber); field_to_json(Obj, "serialNumber", serialNumber);
RESTAPI_utils::field_to_json(Obj, "venue", venue); field_to_json(Obj, "venue", venue);
RESTAPI_utils::field_to_json(Obj, "entity", entity); field_to_json(Obj, "entity", entity);
RESTAPI_utils::field_to_json(Obj, "subscriber", subscriber); field_to_json(Obj, "subscriber", subscriber);
RESTAPI_utils::field_to_json(Obj, "deviceType", deviceType); field_to_json(Obj, "deviceType", deviceType);
RESTAPI_utils::field_to_json(Obj, "qrCode", qrCode); field_to_json(Obj, "qrCode", qrCode);
RESTAPI_utils::field_to_json(Obj, "geoCode", geoCode); field_to_json(Obj, "geoCode", geoCode);
RESTAPI_utils::field_to_json(Obj, "location", location); field_to_json(Obj, "location", location);
RESTAPI_utils::field_to_json(Obj, "contact", contact); field_to_json(Obj, "contact", contact);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
} }
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"serialNumber",serialNumber); field_from_json( Obj,"serialNumber",serialNumber);
RESTAPI_utils::field_from_json( Obj,"venue",venue); field_from_json( Obj,"venue",venue);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"subscriber",subscriber); field_from_json( Obj,"subscriber",subscriber);
RESTAPI_utils::field_from_json( Obj,"deviceType",deviceType); field_from_json( Obj,"deviceType",deviceType);
RESTAPI_utils::field_from_json(Obj, "qrCode", qrCode); field_from_json(Obj, "qrCode", qrCode);
RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode); field_from_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_from_json( Obj,"location",location); field_from_json( Obj,"location",location);
RESTAPI_utils::field_from_json( Obj,"contact",contact); field_from_json( Obj,"contact",contact);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
return true; return true;
} catch(...) { } catch(...) {
@@ -331,18 +334,18 @@ namespace OpenWifi::ProvObjects {
} }
void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"name", name); field_to_json( Obj,"name", name);
RESTAPI_utils::field_to_json( Obj,"description", description); field_to_json( Obj,"description", description);
RESTAPI_utils::field_to_json( Obj,"weight", weight); field_to_json( Obj,"weight", weight);
RESTAPI_utils::field_to_json( Obj,"configuration", configuration); field_to_json( Obj,"configuration", configuration);
} }
bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"name",name); field_from_json( Obj,"name",name);
RESTAPI_utils::field_from_json( Obj,"description",description); field_from_json( Obj,"description",description);
RESTAPI_utils::field_from_json( Obj,"weight",weight); field_from_json( Obj,"weight",weight);
RESTAPI_utils::field_from_json( Obj,"configuration",configuration); field_from_json( Obj,"configuration",configuration);
return true; return true;
} catch(...) { } catch(...) {
@@ -352,27 +355,27 @@ namespace OpenWifi::ProvObjects {
void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const { void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceTypes",deviceTypes); field_to_json( Obj,"deviceTypes",deviceTypes);
RESTAPI_utils::field_to_json( Obj,"configuration",configuration); field_to_json( Obj,"configuration",configuration);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"variables",variables); field_to_json( Obj,"variables",variables);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
RESTAPI_utils::field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
} }
bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceTypes",deviceTypes); field_from_json( Obj,"deviceTypes",deviceTypes);
RESTAPI_utils::field_from_json( Obj,"configuration",configuration); field_from_json( Obj,"configuration",configuration);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"variables",variables); field_from_json( Obj,"variables",variables);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
RESTAPI_utils::field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
return true; return true;
} catch(...) { } catch(...) {
@@ -381,8 +384,8 @@ namespace OpenWifi::ProvObjects {
} }
void Report::to_json(Poco::JSON::Object &Obj) const { void Report::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "snapshot", snapShot); field_to_json(Obj, "snapshot", snapShot);
RESTAPI_utils::field_to_json(Obj, "devices", tenants); field_to_json(Obj, "devices", tenants);
}; };
void Report::reset() { void Report::reset() {
@@ -390,16 +393,16 @@ namespace OpenWifi::ProvObjects {
} }
void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const { void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "uuid", uuid); field_to_json(Obj, "uuid", uuid);
RESTAPI_utils::field_to_json(Obj, "name", name); field_to_json(Obj, "name", name);
RESTAPI_utils::field_to_json(Obj, "description", description); field_to_json(Obj, "description", description);
} }
bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"uuid",uuid); field_from_json( Obj,"uuid",uuid);
RESTAPI_utils::field_from_json( Obj,"name",name); field_from_json( Obj,"name",name);
RESTAPI_utils::field_from_json( Obj,"description",description); field_from_json( Obj,"description",description);
return true; return true;
} catch(...) { } catch(...) {
@@ -408,14 +411,14 @@ namespace OpenWifi::ProvObjects {
} }
void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const { void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "type", type); field_to_json(Obj, "type", type);
RESTAPI_utils::field_to_json(Obj, "entries", entries); field_to_json(Obj, "entries", entries);
} }
bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"type",type); field_from_json( Obj,"type",type);
RESTAPI_utils::field_from_json( Obj,"entries",entries); field_from_json( Obj,"entries",entries);
return true; return true;
} catch(...) { } catch(...) {
@@ -424,12 +427,94 @@ namespace OpenWifi::ProvObjects {
} }
void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const { void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "entries", entries); field_to_json(Obj, "entries", entries);
} }
bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"entries",entries); field_from_json( Obj,"entries",entries);
return true;
} catch(...) {
}
return false;
}
void UserList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "list", list);
}
bool UserList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "list", list);
return true;
} catch(...) {
}
return false;
}
void ObjectACL::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "users", users);
field_to_json(Obj, "access", access);
}
bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "users", users);
field_from_json(Obj, "access", access);
return true;
} catch(...) {
}
return false;
}
void ObjectACLList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "list", list);
}
bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "list", list);
return true;
} catch(...) {
}
return false;
}
void Map::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json( Obj,"data",data);
field_to_json( Obj,"entity",entity);
field_to_json( Obj,"creator",creator);
field_to_json( Obj,"visibility",visibility);
field_to_json( Obj,"access",access);
}
bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json( Obj,"data",data);
field_from_json( Obj,"entity",entity);
field_from_json( Obj,"creator",creator);
field_from_json( Obj,"visibility",visibility);
field_from_json( Obj,"access",access);
return true;
} catch(...) {
}
return false;
}
void MapList::to_json(Poco::JSON::Object &Obj) const {
field_to_json( Obj,"list",list);
}
bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json( Obj,"list",list);
return true; return true;
} catch(...) { } catch(...) {
@@ -438,13 +523,47 @@ namespace OpenWifi::ProvObjects {
} }
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = std::time(nullptr);
if(O->has("name")) if(O->has("name"))
I.name = O->get("name").toString(); I.name = O->get("name").toString();
if(O->has("description"))
if(I.name.empty())
return false;
if(O->has("description"))
I.description = O->get("description").toString(); I.description = O->get("description").toString();
SecurityObjects::MergeNotes(O,U,I.notes); SecurityObjects::MergeNotes(O,U,I.notes);
I.modified = std::time(nullptr); SecurityObjects::NoteInfoVec N;
for(auto &i:I.notes) {
if(i.note.empty())
continue;
N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note});
}
I.modified = Now;
return true; return true;
} }
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = std::time(nullptr);
if(O->has("name"))
I.name = O->get("name").toString();
if(I.name.empty())
return false;
if(O->has("description"))
I.description = O->get("description").toString();
SecurityObjects::NoteInfoVec N;
for(auto &i:I.notes) {
if(i.note.empty())
continue;
N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note});
}
I.notes = N;
I.modified = I.created = Now;
I.id = MicroService::instance().CreateUUID();
return true;
}
}; };

View File

@@ -15,6 +15,13 @@
namespace OpenWifi::ProvObjects { namespace OpenWifi::ProvObjects {
enum FIRMWARE_UPGRADE_RULES {
dont_upgrade,
upgrade_inherit,
upgrade_release_only,
upgrade_latest
};
struct ObjectInfo { struct ObjectInfo {
Types::UUID_t id; Types::UUID_t id;
std::string name; std::string name;
@@ -317,7 +324,50 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
struct UserList {
std::vector<std::string> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ObjectACL {
UserList users;
std::string access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ObjectACLList {
std::vector<ObjectACL> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Map {
ObjectInfo info;
std::string data;
std::string entity;
std::string creator;
std::string visibility;
ObjectACLList access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct MapList {
std::vector<Map> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
}; };

View File

@@ -138,7 +138,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"primary", primary); field_to_json(Obj,"primary", primary);
} }
bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) { bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"number",number); field_from_json(Obj,"number",number);
field_from_json(Obj,"verified",verified); field_from_json(Obj,"verified",verified);
@@ -155,7 +155,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"method", method); field_to_json(Obj,"method", method);
} }
bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) { bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"enabled",enabled); field_from_json(Obj,"enabled",enabled);
field_from_json(Obj,"method",method); field_from_json(Obj,"method",method);
@@ -171,7 +171,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "mfa", mfa); field_to_json(Obj, "mfa", mfa);
} }
bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr Obj) { bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"mobiles",mobiles); field_from_json(Obj,"mobiles",mobiles);
field_from_json(Obj,"mfa",mfa); field_from_json(Obj,"mfa",mfa);
@@ -189,7 +189,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "method", method); field_to_json(Obj, "method", method);
} }
bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) { bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"question",question); field_from_json(Obj,"question",question);
@@ -208,7 +208,7 @@ namespace OpenWifi::SecurityObjects {
} }
bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr Obj) { bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"answer",answer); field_from_json(Obj,"answer",answer);
@@ -387,11 +387,12 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"note", note); field_to_json(Obj,"note", note);
} }
bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) { bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"created",created); field_from_json(Obj,"created",created);
field_from_json(Obj,"createdBy",createdBy); field_from_json(Obj,"createdBy",createdBy);
field_from_json(Obj,"note",note); field_from_json(Obj,"note",note);
return true;
} catch(...) { } catch(...) {
} }
@@ -428,10 +429,11 @@ namespace OpenWifi::SecurityObjects {
field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
} }
bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) { bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"resource",resource); field_from_json(Obj,"resource",resource);
field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
return true;
} catch(...) { } catch(...) {
} }
@@ -447,7 +449,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"notes", notes); field_to_json(Obj,"notes", notes);
} }
bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) { bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"id",id); field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name); field_from_json(Obj,"name",name);
@@ -455,6 +457,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"policy",policy); field_from_json(Obj,"policy",policy);
field_from_json(Obj,"role",role); field_from_json(Obj,"role",role);
field_from_json(Obj,"notes",notes); field_from_json(Obj,"notes",notes);
return true;
} catch(...) { } catch(...) {
} }
@@ -465,13 +468,51 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "profiles", profiles); field_to_json(Obj, "profiles", profiles);
} }
bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) { bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"profiles",profiles); field_from_json(Obj,"profiles",profiles);
return true;
} catch(...) { } catch(...) {
} }
return false; return false;
} }
void ActionLink::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"action",action);
field_to_json(Obj,"userId",userId);
field_to_json(Obj,"actionTemplate",actionTemplate);
field_to_json(Obj,"variables",variables);
field_to_json(Obj,"locale",locale);
field_to_json(Obj,"message",message);
field_to_json(Obj,"sent",sent);
field_to_json(Obj,"created",created);
field_to_json(Obj,"expires",expires);
field_to_json(Obj,"completed",completed);
field_to_json(Obj,"canceled",canceled);
}
bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"action",action);
field_from_json(Obj,"userId",userId);
field_from_json(Obj,"actionTemplate",actionTemplate);
field_from_json(Obj,"variables",variables);
field_from_json(Obj,"locale",locale);
field_from_json(Obj,"message",message);
field_from_json(Obj,"sent",sent);
field_from_json(Obj,"created",created);
field_from_json(Obj,"expires",expires);
field_from_json(Obj,"completed",completed);
field_from_json(Obj,"canceled",canceled);
return true;
} catch(...) {
}
return false;
}
} }

View File

@@ -10,7 +10,7 @@
#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H #define UCENTRAL_RESTAPI_SECURITYOBJECTS_H
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include "../framework/OpenWifiTypes.h" #include "framework/OpenWifiTypes.h"
namespace OpenWifi::SecurityObjects { namespace OpenWifi::SecurityObjects {
@@ -53,7 +53,7 @@ namespace OpenWifi::SecurityObjects {
std::string createdBy; std::string createdBy;
std::string note; std::string note;
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);
}; };
typedef std::vector<NoteInfo> NoteInfoVec; typedef std::vector<NoteInfo> NoteInfoVec;
@@ -63,7 +63,7 @@ namespace OpenWifi::SecurityObjects {
bool primary; bool primary;
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 {
@@ -71,7 +71,7 @@ namespace OpenWifi::SecurityObjects {
std::string method; std::string method;
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 UserLoginLoginExtensions { struct UserLoginLoginExtensions {
@@ -79,7 +79,7 @@ namespace OpenWifi::SecurityObjects {
struct MfaAuthInfo mfa; struct MfaAuthInfo mfa;
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 MFAChallengeRequest { struct MFAChallengeRequest {
@@ -89,7 +89,7 @@ namespace OpenWifi::SecurityObjects {
uint64_t created; uint64_t created;
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 MFAChallengeResponse { struct MFAChallengeResponse {
@@ -97,7 +97,7 @@ namespace OpenWifi::SecurityObjects {
std::string answer; std::string answer;
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 UserInfo { struct UserInfo {
@@ -200,7 +200,7 @@ namespace OpenWifi::SecurityObjects {
std::string resource; std::string resource;
ResourceAccessType access; ResourceAccessType access;
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);
}; };
typedef std::vector<ProfileAction> ProfileActionVec; typedef std::vector<ProfileAction> ProfileActionVec;
@@ -212,14 +212,37 @@ namespace OpenWifi::SecurityObjects {
std::string role; std::string role;
NoteInfoVec notes; NoteInfoVec notes;
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);
}; };
typedef std::vector<SecurityProfile> SecurityProfileVec; typedef std::vector<SecurityProfile> SecurityProfileVec;
struct SecurityProfileList { struct SecurityProfileList {
SecurityProfileVec profiles; SecurityProfileVec profiles;
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);
};
enum LinkActions {
FORGOT_PASSWORD=1,
VERIFY_EMAIL
};
struct ActionLink {
std::string id;
uint64_t action;
std::string userId;
std::string actionTemplate;
Types::StringPairVec variables;
std::string locale;
std::string message;
uint64_t sent=0;
uint64_t created=std::time(nullptr);
uint64_t expires=0;
uint64_t completed=0;
uint64_t canceled=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
}; };
} }

View File

@@ -14,7 +14,6 @@
#include "framework/MicroService.h" #include "framework/MicroService.h"
namespace OpenWifi { namespace OpenWifi {
class SMSSender * SMSSender::instance_ = nullptr;
int SMSSender::Start() { int SMSSender::Start() {
Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws"); Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws");

View File

@@ -25,10 +25,8 @@ namespace OpenWifi {
class SMSSender : public SubSystemServer { class SMSSender : public SubSystemServer {
public: public:
static SMSSender *instance() { static SMSSender *instance() {
if (instance_ == nullptr) { static SMSSender instance;
instance_ = new SMSSender; return &instance;
}
return instance_;
} }
int Start() final; int Start() final;
@@ -39,7 +37,6 @@ namespace OpenWifi {
bool IsNumberValid(const std::string &Number, const std::string &UserName); bool IsNumberValid(const std::string &Number, const std::string &UserName);
[[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message); [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
private: private:
static SMSSender * instance_;
std::string Provider_; std::string Provider_;
bool Enabled_=false; bool Enabled_=false;
std::vector<SMSValidationCacheEntry> Cache_; std::vector<SMSValidationCacheEntry> Cache_;

View File

@@ -18,11 +18,10 @@
#include "SMTPMailerService.h" #include "SMTPMailerService.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "AuthService.h"
namespace OpenWifi { namespace OpenWifi {
class SMTPMailerService * SMTPMailerService::instance_ = nullptr;
void SMTPMailerService::LoadMyConfig() { void SMTPMailerService::LoadMyConfig() {
MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname"); MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username"); SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
@@ -147,7 +146,7 @@ namespace OpenWifi {
auto Logo = Msg.Attrs.find(LOGO); auto Logo = Msg.Attrs.find(LOGO);
if(Logo!=Msg.Attrs.end()) { if(Logo!=Msg.Attrs.end()) {
Poco::File LogoFile(TemplateDir_ + "/" + Logo->second); 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);

View File

@@ -59,10 +59,8 @@ namespace OpenWifi {
class SMTPMailerService : public SubSystemServer, Poco::Runnable { class SMTPMailerService : public SubSystemServer, Poco::Runnable {
public: public:
static SMTPMailerService *instance() { static SMTPMailerService *instance() {
if (instance_ == nullptr) { static SMTPMailerService instance;
instance_ = new SMTPMailerService; return & instance;
}
return instance_;
} }
struct MessageEvent { struct MessageEvent {
@@ -88,7 +86,6 @@ namespace OpenWifi {
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:
static SMTPMailerService * instance_;
std::string MailHost_; std::string MailHost_;
std::string Sender_; std::string Sender_;
int MailHostPort_=25; int MailHostPort_=25;

View File

@@ -10,13 +10,12 @@
namespace OpenWifi { namespace OpenWifi {
class Storage *Storage::instance_ = nullptr;
int Storage::Start() { int Storage::Start() {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
StorageClass::Start(); StorageClass::Start();
Create_Tables(); Create_Tables();
InitializeDefaultUser();
return 0; return 0;
} }

View File

@@ -15,34 +15,6 @@
namespace OpenWifi { namespace OpenWifi {
static const std::string AllActionLinksFieldsForSelect {
"Id, "
"Action,"
"UserId,"
"template,"
"locale,"
"message,"
"sent,"
"created,"
"expires,"
"completed,"
"canceled"
};
static const std::string AllActionLinksFieldsForUpdate {
"Id=?, "
"Action=?,"
"UserId=?,"
"template=?,"
"locale=?,"
"message=?,"
"sent=?,"
"created=?,"
"expires=?,"
"completed=?,"
"canceled=?"
};
static const std::string AllEmailTemplatesFieldsForCreation { static const std::string AllEmailTemplatesFieldsForCreation {
}; };
@@ -90,7 +62,7 @@ namespace OpenWifi {
return UNKNOWN; return UNKNOWN;
} }
static const std::string from_userType(USER_TYPE U) { static std::string from_userType(USER_TYPE U) {
switch(U) { switch(U) {
case ROOT: return "root"; case ROOT: return "root";
case ADMIN: return "admin"; case ADMIN: return "admin";
@@ -104,10 +76,8 @@ namespace OpenWifi {
} }
static Storage *instance() { static Storage *instance() {
if (instance_ == nullptr) { static Storage instance;
instance_ = new Storage; return &instance;
}
return instance_;
} }
int Start() override; int Start() override;
@@ -116,7 +86,8 @@ namespace OpenWifi {
/* /*
* All user management functions * All user management functions
*/ */
bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser); bool InitializeDefaultUser();
bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false);
bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id);
@@ -143,18 +114,20 @@ namespace OpenWifi {
/* /*
* All ActionLinks functions * All ActionLinks functions
*/ */
bool CreateAction(std::string &ActionId, std::string &Action, USER_ID_TYPE & Id, Types::StringPairVec & Elements ); bool CreateAction( SecurityObjects::ActionLink & A);
bool DeleteAction(std::string &ActionId); bool DeleteAction(std::string &ActionId);
bool CompleteAction(std::string &ActionId); bool CompleteAction(std::string &ActionId);
bool CancelAction(std::string &ActionId); bool CancelAction(std::string &ActionId);
bool SentAction(std::string &ActionId);
bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A);
bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200);
private: private:
static Storage *instance_;
int Create_Tables(); int Create_Tables();
int Create_UserTable(); int Create_UserTable();
int Create_AvatarTable(); int Create_AvatarTable();
int Create_TokensTable(); int Create_TokensTable();
int Create_ActionLinkTable();
}; };
inline Storage * StorageService() { return Storage::instance(); }; inline Storage * StorageService() { return Storage::instance(); };

View File

@@ -57,6 +57,7 @@ using namespace std::chrono_literals;
#include "Poco/URI.h" #include "Poco/URI.h"
#include "Poco/Net/HTTPSClientSession.h" #include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/NetworkInterface.h" #include "Poco/Net/NetworkInterface.h"
#include "Poco/ExpireLRUCache.h"
#include "cppkafka/cppkafka.h" #include "cppkafka/cppkafka.h"
@@ -66,6 +67,86 @@ using namespace std::chrono_literals;
#include "framework/RESTAPI_errors.h" #include "framework/RESTAPI_errors.h"
#include "framework/uCentral_Protocol.h" #include "framework/uCentral_Protocol.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "nlohmann/json.hpp"
namespace OpenWifi {
enum UNAUTHORIZED_REASON {
SUCCESS=0,
PASSWORD_CHANGE_REQUIRED,
INVALID_CREDENTIALS,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR,
ACCESS_DENIED,
INVALID_TOKEN
};
class AppServiceRegistry {
public:
inline AppServiceRegistry();
static AppServiceRegistry & instance() {
static AppServiceRegistry instance;
return instance;
}
inline ~AppServiceRegistry() {
Save();
}
inline void Save() {
std::istringstream IS( to_string(Registry_));
std::ofstream OF;
OF.open(FileName,std::ios::binary | std::ios::trunc);
Poco::StreamCopier::copyStream(IS, OF);
}
inline void Set(const char *Key, uint64_t Value ) {
Registry_[Key] = Value;
Save();
}
inline void Set(const char *Key, const std::string &Value ) {
Registry_[Key] = Value;
Save();
}
inline void Set(const char *Key, bool Value ) {
Registry_[Key] = Value;
Save();
}
inline bool Get(const char *Key, bool & Value ) {
if(Registry_[Key].is_boolean()) {
Value = Registry_[Key].get<bool>();
return true;
}
return false;
}
inline bool Get(const char *Key, uint64_t & Value ) {
if(Registry_[Key].is_number_unsigned()) {
Value = Registry_[Key].get<uint64_t>();
return true;
}
return false;
}
inline bool Get(const char *Key, std::string & Value ) {
if(Registry_[Key].is_string()) {
Value = Registry_[Key].get<std::string>();
return true;
}
return false;
}
private:
std::string FileName;
nlohmann::json Registry_;
};
}
namespace OpenWifi::RESTAPI_utils { namespace OpenWifi::RESTAPI_utils {
@@ -263,6 +344,21 @@ namespace OpenWifi::RESTAPI_utils {
return OS.str(); return OS.str();
} }
inline std::string to_string(const Types::StringPairVec & ObjectArray) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
return "[]";
for(auto const &i:ObjectArray) {
Poco::JSON::Array InnerArray;
InnerArray.add(i.first);
InnerArray.add(i.second);
OutputArr.add(InnerArray);
}
std::ostringstream OS;
Poco::JSON::Stringifier::condense(OutputArr,OS);
return OS.str();
}
template<class T> std::string to_string(const std::vector<T> & ObjectArray) { template<class T> std::string to_string(const std::vector<T> & ObjectArray) {
Poco::JSON::Array OutputArr; Poco::JSON::Array OutputArr;
if(ObjectArray.empty()) if(ObjectArray.empty())
@@ -345,6 +441,27 @@ namespace OpenWifi::RESTAPI_utils {
return Result; return Result;
} }
inline Types::StringPairVec to_stringpair_array(const std::string &S) {
Types::StringPairVec R;
if(S.empty())
return R;
try {
Poco::JSON::Parser P;
auto Object = P.parse(S).template extract<Poco::JSON::Array::Ptr>();
for (auto const &i : *Object) {
auto InnerObject = i.template extract<Poco::JSON::Array::Ptr>();
if(InnerObject->size()==2) {
Types::StringPair P{InnerObject->get(0).toString(), InnerObject->get(1).toString()};
R.push_back(P);
}
}
} catch (...) {
}
return R;
}
template<class T> std::vector<T> to_object_array(const std::string & ObjectString) { template<class T> std::vector<T> to_object_array(const std::string & ObjectString) {
std::vector<T> Result; std::vector<T> Result;
if(ObjectString.empty()) if(ObjectString.empty())
@@ -729,16 +846,13 @@ namespace OpenWifi::Utils {
return Result; return Result;
} }
inline void SaveSystemId(uint64_t Id);
[[nodiscard]] inline uint64_t InitializeSystemId() { [[nodiscard]] inline uint64_t InitializeSystemId() {
std::random_device RDev; std::random_device RDev;
std::srand(RDev()); std::srand(RDev());
std::chrono::high_resolution_clock Clock; std::chrono::high_resolution_clock Clock;
auto Now = Clock.now().time_since_epoch().count(); auto Now = Clock.now().time_since_epoch().count();
auto S = (GetDefaultMacAsInt64() + std::rand() + Now) ; auto S = (GetDefaultMacAsInt64() + std::rand() + Now) ;
SaveSystemId(S); OpenWifi::AppServiceRegistry().Set("systemid",S);
std::cout << "ID: " << S << std::endl;
return S; return S;
} }
@@ -887,6 +1001,7 @@ namespace OpenWifi {
static const std::string uSERVICE_SUBCRIBER{ "owsub"}; static const std::string uSERVICE_SUBCRIBER{ "owsub"};
static const std::string uSERVICE_INSTALLER{ "owinst"}; static const std::string uSERVICE_INSTALLER{ "owinst"};
class MyErrorHandler : public Poco::ErrorHandler { class MyErrorHandler : public Poco::ErrorHandler {
public: public:
explicit MyErrorHandler(Poco::Util::Application &App) : App_(App) {} explicit MyErrorHandler(Poco::Util::Application &App) : App_(App) {}
@@ -1309,6 +1424,63 @@ namespace OpenWifi {
std::string _fileName; std::string _fileName;
}; };
class RESTAPI_RateLimiter : public SubSystemServer {
public:
struct ClientCacheEntry {
int64_t Start=0;
int Count=0;
};
static RESTAPI_RateLimiter *instance() {
static RESTAPI_RateLimiter instance;
return &instance;
}
inline int Start() final { return 0;};
inline void Stop() final { };
inline bool IsRateLimited(const Poco::Net::HTTPServerRequest &R, int64_t Period, int64_t MaxCalls) {
Poco::URI uri(R.getURI());
auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
auto E = Cache_.get(H);
const auto p1 = std::chrono::system_clock::now();
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(p1.time_since_epoch()).count();
if(E.isNull()) {
Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString()));
return false;
}
if((Now-E->Start)<Period) {
E->Count++;
Cache_.update(H,E);
if(E->Count > MaxCalls)
return true;
return false;
}
E->Start = Now;
E->Count = 1;
Cache_.update(H,E);
return false;
}
inline void Clear() {
Cache_.clear();
}
private:
Poco::ExpireLRUCache<uint64_t,ClientCacheEntry> Cache_{2048};
std::hash<std::string> str_hash;
RESTAPI_RateLimiter() noexcept:
SubSystemServer("RateLimiter", "RATE-LIMITER", "rate.limiter")
{
}
};
inline RESTAPI_RateLimiter * RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); }
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler { class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
public: public:
struct QueryBlock { struct QueryBlock {
@@ -1318,8 +1490,28 @@ namespace OpenWifi {
}; };
typedef std::map<std::string, std::string> BindingMap; typedef std::map<std::string, std::string> BindingMap;
RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector<std::string> Methods, RESTAPI_GenericServer & Server, bool Internal=false, bool AlwaysAuthorize=true) struct RateLimit {
: Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), Server_(Server), Internal_(Internal), AlwaysAuthorize_(AlwaysAuthorize) {} int64_t Interval=1000;
int64_t MaxCalls=10;
};
RESTAPIHandler( BindingMap map,
Poco::Logger &l,
std::vector<std::string> Methods,
RESTAPI_GenericServer & Server,
bool Internal=false,
bool AlwaysAuthorize=true,
bool RateLimited=false,
const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100})
: Bindings_(std::move(map)),
Logger_(l),
Methods_(std::move(Methods)),
Server_(Server),
Internal_(Internal),
AlwaysAuthorize_(AlwaysAuthorize),
RateLimited_(RateLimited),
MyRates_(Profile){
}
inline bool RoleIsAuthorized(const std::string & Path, const std::string & Method, std::string & Reason) { inline bool RoleIsAuthorized(const std::string & Path, const std::string & Method, std::string & Reason) {
return true; return true;
@@ -1331,6 +1523,9 @@ namespace OpenWifi {
Request = &RequestIn; Request = &RequestIn;
Response = &ResponseIn; Response = &ResponseIn;
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls))
return;
if (!ContinueProcessing()) if (!ContinueProcessing())
return; return;
@@ -1340,7 +1535,7 @@ namespace OpenWifi {
std::string Reason; std::string Reason;
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) { if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
UnAuthorized(Reason); UnAuthorized(Reason, ACCESS_DENIED);
return; return;
} }
@@ -1561,10 +1756,10 @@ namespace OpenWifi {
Poco::JSON::Stringifier::stringify(ErrorObject, Answer); Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
} }
inline void UnAuthorized(const std::string & Reason = "") { inline void UnAuthorized(const std::string & Reason = "", int Code = INVALID_CREDENTIALS ) {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN); PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
Poco::JSON::Object ErrorObject; Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",403); ErrorObject.set("ErrorCode",Code);
ErrorObject.set("ErrorDetails",Request->getMethod()); ErrorObject.set("ErrorDetails",Request->getMethod());
ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ; ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ;
std::ostream &Answer = Response->send(); std::ostream &Answer = Response->send();
@@ -1609,7 +1804,7 @@ namespace OpenWifi {
Response->set("Cache-Control", "private"); Response->set("Cache-Control", "private");
Response->set("Pragma", "private"); Response->set("Pragma", "private");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->set("Content-Length", std::to_string(File.getSize())); Response->setContentLength(File.getSize());
AddCORS(); AddCORS();
Response->sendFile(File.path(),"application/octet-stream"); Response->sendFile(File.path(),"application/octet-stream");
} }
@@ -1647,10 +1842,10 @@ namespace OpenWifi {
const Types::StringPairVec & FormVars) { const Types::StringPairVec & FormVars) {
Response->set("Pragma", "private"); Response->set("Pragma", "private");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->set("Content-Length", std::to_string(File.getSize())); std::string FormContent = Utils::LoadFile(File.path());
AddCORS();
auto FormContent = Utils::LoadFile(File.path());
Utils::ReplaceVariables(FormContent, FormVars); Utils::ReplaceVariables(FormContent, FormVars);
Response->setContentLength(FormContent.size());
AddCORS();
Response->setChunkedTransferEncoding(true); Response->setChunkedTransferEncoding(true);
Response->setContentType("text/html"); Response->setContentType("text/html");
std::ostream& ostr = Response->send(); std::ostream& ostr = Response->send();
@@ -1760,12 +1955,14 @@ namespace OpenWifi {
std::vector<std::string> Methods_; std::vector<std::string> Methods_;
QueryBlock QB_; QueryBlock QB_;
bool Internal_=false; bool Internal_=false;
bool RateLimited_=false;
bool QueryBlockInitialized_=false; bool QueryBlockInitialized_=false;
Poco::Net::HTTPServerRequest *Request= nullptr; Poco::Net::HTTPServerRequest *Request= nullptr;
Poco::Net::HTTPServerResponse *Response= nullptr; Poco::Net::HTTPServerResponse *Response= nullptr;
bool AlwaysAuthorize_=true; bool AlwaysAuthorize_=true;
Poco::JSON::Parser IncomingParser_; Poco::JSON::Parser IncomingParser_;
RESTAPI_GenericServer & Server_; RESTAPI_GenericServer & Server_;
RateLimit MyRates_;
}; };
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler { class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
@@ -1890,9 +2087,8 @@ namespace OpenWifi {
inline void initialize(Poco::Util::Application & self) override; inline void initialize(Poco::Util::Application & self) override;
static KafkaManager *instance() { static KafkaManager *instance() {
if(instance_== nullptr) static KafkaManager instance;
instance_ = new KafkaManager; return &instance;
return instance_;
} }
inline int Start() override { inline int Start() override {
@@ -1967,7 +2163,6 @@ namespace OpenWifi {
// void WakeUp(); // void WakeUp();
private: private:
static KafkaManager *instance_;
std::mutex ProducerMutex_; std::mutex ProducerMutex_;
std::mutex ConsumerMutex_; std::mutex ConsumerMutex_;
bool KafkaEnabled_ = false; bool KafkaEnabled_ = false;
@@ -1995,7 +2190,6 @@ namespace OpenWifi {
}; };
inline KafkaManager * KafkaManager() { return KafkaManager::instance(); } inline KafkaManager * KafkaManager() { return KafkaManager::instance(); }
inline class KafkaManager *KafkaManager::instance_ = nullptr;
class AuthClient : public SubSystemServer { class AuthClient : public SubSystemServer {
public: public:
@@ -2005,10 +2199,8 @@ namespace OpenWifi {
} }
static AuthClient *instance() { static AuthClient *instance() {
if (instance_ == nullptr) { static AuthClient instance;
instance_ = new AuthClient; return &instance;
}
return instance_;
} }
inline int Start() override { inline int Start() override {
@@ -2086,12 +2278,10 @@ namespace OpenWifi {
} }
private: private:
static AuthClient *instance_;
OpenWifi::SecurityObjects::UserInfoCache UserCache_; OpenWifi::SecurityObjects::UserInfoCache UserCache_;
}; };
inline AuthClient * AuthClient() { return AuthClient::instance(); } inline AuthClient * AuthClient() { return AuthClient::instance(); }
inline class AuthClient * AuthClient::instance_ = nullptr;
class ALBRequestHandler: public Poco::Net::HTTPRequestHandler class ALBRequestHandler: public Poco::Net::HTTPRequestHandler
/// Return a HTML document with the current date and time. /// Return a HTML document with the current date and time.
@@ -2148,10 +2338,8 @@ namespace OpenWifi {
} }
static ALBHealthCheckServer *instance() { static ALBHealthCheckServer *instance() {
if (instance_ == nullptr) { static ALBHealthCheckServer instance;
instance_ = new ALBHealthCheckServer; return &instance;
}
return instance_;
} }
inline int Start() override; inline int Start() override;
@@ -2162,14 +2350,12 @@ namespace OpenWifi {
} }
private: private:
static ALBHealthCheckServer *instance_;
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;
}; };
inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
inline class ALBHealthCheckServer * ALBHealthCheckServer::instance_ = nullptr;
Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S); Poco::Logger & L, RESTAPI_GenericServer & S);
@@ -2181,10 +2367,8 @@ namespace OpenWifi {
class RESTAPI_server : public SubSystemServer { class RESTAPI_server : public SubSystemServer {
public: public:
static RESTAPI_server *instance() { static RESTAPI_server *instance() {
if (instance_ == nullptr) { static RESTAPI_server instance;
instance_ = new RESTAPI_server; return &instance;
}
return instance_;
} }
int Start() override; int Start() override;
inline void Stop() override { inline void Stop() override {
@@ -2202,7 +2386,6 @@ namespace OpenWifi {
} }
private: private:
static RESTAPI_server *instance_;
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_; std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_; Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_; RESTAPI_GenericServer Server_;
@@ -2235,9 +2418,6 @@ namespace OpenWifi {
RESTAPI_GenericServer &Server_; RESTAPI_GenericServer &Server_;
}; };
inline class RESTAPI_server *RESTAPI_server::instance_ = nullptr;
inline int RESTAPI_server::Start() { inline int RESTAPI_server::Start() {
Logger_.information("Starting."); Logger_.information("Starting.");
Server_.InitLogging(); Server_.InitLogging();
@@ -2269,10 +2449,8 @@ namespace OpenWifi {
public: public:
static RESTAPI_InternalServer *instance() { static RESTAPI_InternalServer *instance() {
if (instance_ == nullptr) { static RESTAPI_InternalServer instance;
instance_ = new RESTAPI_InternalServer; return &instance;
}
return instance_;
} }
inline int Start() override; inline int Start() override;
@@ -2290,7 +2468,6 @@ namespace OpenWifi {
return RESTAPI_internal_server(Path, Bindings, Logger_, Server_); return RESTAPI_internal_server(Path, Bindings, Logger_, Server_);
} }
private: private:
static RESTAPI_InternalServer *instance_;
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_; std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_; Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_; RESTAPI_GenericServer Server_;
@@ -2301,8 +2478,6 @@ namespace OpenWifi {
}; };
inline class RESTAPI_InternalServer* RESTAPI_InternalServer::instance_ = nullptr;
inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); }; inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); };
class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
@@ -2357,6 +2532,8 @@ namespace OpenWifi {
uint64_t LastUpdate=0; uint64_t LastUpdate=0;
}; };
class SubSystemServer; class SubSystemServer;
typedef std::map<uint64_t, MicroServiceMeta> MicroServiceMetaMap; typedef std::map<uint64_t, MicroServiceMeta> MicroServiceMetaMap;
typedef std::vector<MicroServiceMeta> MicroServiceMetaVec; typedef std::vector<MicroServiceMeta> MicroServiceMetaVec;
@@ -2918,6 +3095,22 @@ namespace OpenWifi {
return Application::EXIT_OK; return Application::EXIT_OK;
} }
AppServiceRegistry::AppServiceRegistry() {
FileName = MicroService::instance().DataDir() + "/registry.json";
Poco::File F(FileName);
try {
if(F.exists()) {
std::ostringstream OS;
std::ifstream IF(FileName);
Poco::StreamCopier::copyStream(IF, OS);
Registry_ = nlohmann::json::parse(OS.str());
}
} catch (...) {
Registry_ = nlohmann::json::parse("{}");
}
}
inline void SubSystemServer::initialize(Poco::Util::Application &self) { inline void SubSystemServer::initialize(Poco::Util::Application &self) {
Logger_.notice("Initializing..."); Logger_.notice("Initializing...");
auto i = 0; auto i = 0;
@@ -3178,7 +3371,8 @@ namespace OpenWifi {
auto InsertResult = CertNames.insert(CertFileName); auto InsertResult = CertNames.insert(CertFileName);
if(InsertResult.second) { if(InsertResult.second) {
Poco::JSON::Object Inner; Poco::JSON::Object Inner;
Inner.set("filename", CertFileName); Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName); Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn(); auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn",ExpiresOn.timestamp().epochTime()); Inner.set("expiresOn",ExpiresOn.timestamp().epochTime());
@@ -3477,7 +3671,7 @@ namespace OpenWifi {
Utils::FormatIPv6(Request->clientAddress().toString()), Utils::FormatIPv6(Request->clientAddress().toString()),
Request->getMethod(), Request->getURI())); Request->getMethod(), Request->getURI()));
} }
UnAuthorized(); UnAuthorized("Invalid token", INVALID_TOKEN);
} }
return false; return false;
} }
@@ -3487,40 +3681,14 @@ namespace OpenWifi {
} }
namespace OpenWifi::Utils { namespace OpenWifi::Utils {
inline void SaveSystemId(uint64_t Id) { [[nodiscard]] inline uint64_t GetSystemId() {
try { uint64_t ID=0;
std::ofstream O; if(!AppServiceRegistry().Get("systemid",ID)) {
O.open(MicroService::instance().DataDir() + "/system.id",std::ios::binary | std::ios::trunc); return InitializeSystemId();
O << Id; }
O.close(); return ID;
} catch (...) }
{ }
std::cout << "Could not save system ID" << std::endl;
}
}
[[nodiscard]] inline uint64_t GetSystemId() {
uint64_t ID=0;
// if the system ID file exists, open and read it.
Poco::File SID( MicroService::instance().DataDir() + "/system.id");
try {
if (SID.exists()) {
std::ifstream I;
I.open(SID.path());
I >> ID;
I.close();
if (ID == 0)
return InitializeSystemId();
return ID;
} else {
return InitializeSystemId();
}
} catch (...) {
return InitializeSystemId();
}
}
}
namespace OpenWifi::CIDR { namespace OpenWifi::CIDR {

View File

@@ -47,13 +47,18 @@ namespace OpenWifi::RESTAPI::Errors {
static const std::string IdMustBe0{"To create a user, you must set the ID to 0"}; static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
static const std::string InvalidUserRole{"Invalid userRole."}; static const std::string InvalidUserRole{"Invalid userRole."};
static const std::string InvalidEmailAddress{"Invalid email address."}; static const std::string InvalidEmailAddress{"Invalid email address."};
static const std::string InvalidPassword{"Invalid password."};
static const std::string PasswordRejected{"Password was rejected. This maybe an old password."}; static const std::string PasswordRejected{"Password was rejected. This maybe an old password."};
static const std::string InvalidIPRanges{"Invalid IP range specifications."}; static const std::string InvalidIPRanges{"Invalid IP range specifications."};
static const std::string InvalidLOrderBy{"Invalid orderBy specification."}; static const std::string InvalidLOrderBy{"Invalid orderBy specification."};
static const std::string NeedMobileNumber{"You must provide at least one validated phone number."}; static const std::string NeedMobileNumber{"You must provide at least one validated phone number."};
static const std::string BadMFAMethod{"MFA only supports sms or email."}; static const std::string BadMFAMethod{"MFA only supports sms or email."};
static const std::string InvalidCredentials{"Invalid credentials (username/password)."};
static const std::string InvalidPassword{"Password does not conform to basic password rules."};
static const std::string UserPendingVerification{"User access denied pending email verification."};
static const std::string PasswordMustBeChanged{"Password must be changed."};
static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
static const std::string MissingAuthenticationInformation{"Missing authentication information."};
static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
} }
#endif //OWPROV_RESTAPI_ERRORS_H #endif //OWPROV_RESTAPI_ERRORS_H

View File

@@ -103,8 +103,6 @@ namespace OpenWifi {
DBType dbType_ = sqlite; DBType dbType_ = sqlite;
}; };
// inline StorageClass * Storage() { return StorageClass::instance(); }
#ifdef SMALL_BUILD #ifdef SMALL_BUILD
int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }

View File

@@ -0,0 +1,186 @@
//
// Created by stephane bourque on 2021-11-08.
//
#include "storage_actionLinks.h"
#include <string>
#include "StorageService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "framework/MicroService.h"
namespace OpenWifi {
bool Convert(const ActionLinkRecord &T, SecurityObjects::ActionLink &U) {
U.id = T.get<0>();
U.action = T.get<1>();
U.userId = T.get<2>();
U.actionTemplate = T.get<3>();
U.variables = RESTAPI_utils::to_stringpair_array(T.get<4>());
U.locale = T.get<5>();
U.message = T.get<6>();
U.sent = T.get<7>();
U.created = T.get<8>();
U.expires = T.get<9>();
U.completed = T.get<10>();
U.canceled = T.get<11>();
return true;
}
bool Convert(const SecurityObjects::ActionLink &U, ActionLinkRecord &T) {
T.set<0>(U.id);
T.set<1>(U.action);
T.set<2>(U.userId);
T.set<3>(U.actionTemplate);
T.set<4>(RESTAPI_utils::to_string(U.variables));
T.set<5>(U.locale);
T.set<6>(U.message);
T.set<7>(U.sent);
T.set<8>(U.created);
T.set<9>(U.expires);
T.set<10>(U.completed);
T.set<11>(U.canceled);
return true;
}
bool Storage::CreateAction( SecurityObjects::ActionLink & A) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Insert(Sess);
std::string St2{
"INSERT INTO ActionLinks (" + AllActionLinksFieldsForSelect + ") VALUES(" + AllActionLinksValuesForSelect + ")"};
ActionLinkRecord AR;
Convert(A, AR);
Insert << ConvertParams(St2),
Poco::Data::Keywords::use(AR);
Insert.execute();
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
bool Storage::GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
ActionLinkRecordList ARL;
std::string S{
"SELECT " + AllActionLinksFieldsForSelect + " From ActionLinks where sent=0 and canceled=0 and completed=0"};
Select << ConvertParams(S),
Poco::Data::Keywords::into(ARL);
Select.execute();
for(const auto &i:ARL) {
SecurityObjects::ActionLink L;
Convert(i,L);
Links.emplace_back(L);
}
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
bool Storage::GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
ActionLinkRecord AR;
std::string St2{
"SELECT " + AllActionLinksFieldsForSelect + " From ActionLinks where id=?"};
Select << ConvertParams(St2),
Poco::Data::Keywords::into(AR),
Poco::Data::Keywords::use(ActionId);
Select.execute();
if(Select.rowsExtracted()==1) {
Convert(AR, A);
return true;
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
bool Storage::SentAction(std::string &ActionId) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Update(Sess);
uint64_t Sent = std::time(nullptr);
std::string St{"UPDATE ActionLinks set Sent=? where id=?"};
Update << ConvertParams(St),
Poco::Data::Keywords::use(Sent),
Poco::Data::Keywords::use(ActionId);
Update.execute();
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
bool Storage::DeleteAction(std::string &ActionId) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
uint64_t Sent = std::time(nullptr);
std::string St{"DELETE FROM ActionLinks where id=?"};
Delete << ConvertParams(St),
Poco::Data::Keywords::use(ActionId);
Delete.execute();
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
bool Storage::CompleteAction(std::string &ActionId) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Update(Sess);
uint64_t completed = std::time(nullptr);
std::string St{"UPDATE ActionLinks set completed=? where id=?"};
Update << ConvertParams(St),
Poco::Data::Keywords::use(completed),
Poco::Data::Keywords::use(ActionId);
Update.execute();
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
bool Storage::CancelAction(std::string &ActionId) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Update(Sess);
uint64_t canceled = std::time(nullptr);
std::string St{"UPDATE ActionLinks set canceled=? where id=?"};
Update << ConvertParams(St),
Poco::Data::Keywords::use(canceled),
Poco::Data::Keywords::use(ActionId);
Update.execute();
return true;
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return false;
}
}

View File

@@ -0,0 +1,79 @@
//
// Created by stephane bourque on 2021-11-08.
//
#ifndef OWSEC_STORAGE_ACTIONLINKS_H
#define OWSEC_STORAGE_ACTIONLINKS_H
#include <string>
#include <vector>
#include "Poco/Tuple.h"
namespace OpenWifi {
static const std::string AllActionLinksFieldsForCreation{
"Id varchar(36),"
"Action bigint,"
"UserId text,"
"template text,"
"variables text,"
"locale varchar,"
"message text,"
"sent bigint,"
"created bigint,"
"expires bigint,"
"completed bigint,"
"canceled bigint"
};
static const std::string AllActionLinksFieldsForSelect {
"Id, "
"Action,"
"UserId,"
"template,"
"variables,"
"locale,"
"message,"
"sent,"
"created,"
"expires,"
"completed,"
"canceled"
};
static const std::string AllActionLinksValuesForSelect{ "?,?,?,?,?,?,?,?,?,?,?,?" };
static const std::string AllActionLinksFieldsForUpdate {
"Id=?, "
"Action=?,"
"UserId=?,"
"template=?,"
"variables=?,"
"locale=?,"
"message=?,"
"sent=?,"
"created=?,"
"expires=?,"
"completed=?,"
"canceled=?"
};
typedef Poco::Tuple <
std::string, // id
uint64_t, // action
std::string, // userId
std::string, // actionTemplate
std::string, // variables
std::string, // locale
std::string, // message
uint64_t, // sent
uint64_t, // created
uint64_t, // expires
uint64_t, // completed
uint64_t // canceled
> ActionLinkRecord;
typedef std::vector <ActionLinkRecord> ActionLinkRecordList;
}
#endif //OWSEC_STORAGE_ACTIONLINKS_H

View File

@@ -35,8 +35,7 @@ namespace OpenWifi {
uint64_t Now = std::time(nullptr); uint64_t Now = std::time(nullptr);
std::string St2{ std::string St2{"INSERT INTO Avatars (" + AllAvatarFieldsForSelect + ") VALUES( " + AllAvatarValuesForSelect + " )"};
"INSERT INTO Avatars (Id,Type,Created,Name,Avatar) VALUES(?,?,?,?,?)"};
Insert << ConvertParams(St2), Insert << ConvertParams(St2),
Poco::Data::Keywords::use(Id), Poco::Data::Keywords::use(Id),
@@ -58,13 +57,19 @@ namespace OpenWifi {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess); Poco::Data::Statement Select(Sess);
std::string St2{"SELECT Avatar, Type, Name FROM Avatars WHERE Id=?"}; std::string St2{"SELECT " + AllAvatarFieldsForSelect + " FROM Avatars WHERE Id=?"};
Poco::Data::Statement Select2(Sess); Poco::Data::Statement Select2(Sess);
std::string TId;
uint64_t Created;
Select2 << ConvertParams(St2), Select2 << ConvertParams(St2),
Poco::Data::Keywords::into(L), Poco::Data::Keywords::into(TId),
Poco::Data::Keywords::into(Type), Poco::Data::Keywords::into(Type),
Poco::Data::Keywords::into(Created),
Poco::Data::Keywords::into(Name), Poco::Data::Keywords::into(Name),
Poco::Data::Keywords::into(L),
Poco::Data::Keywords::use(Id); Poco::Data::Keywords::use(Id);
Select2.execute(); Select2.execute();

View File

@@ -7,6 +7,33 @@
namespace OpenWifi { namespace OpenWifi {
static const std::string AllAvatarFieldsForCreation_sqlite{
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar BLOB"
};
static const std::string AllAvatarFieldsForCreation_mysql{
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar LONGBLOB"
};
static const std::string AllAvatarFieldsForCreation_pgsql{
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar BYTEA"
};
static const std::string AllAvatarFieldsForSelect{ " Id,Type,Created,Name,Avatar " };
static const std::string AllAvatarValuesForSelect{ "?,?,?,?,?" };
} }

View File

@@ -5,6 +5,8 @@
#include "StorageService.h" #include "StorageService.h"
#include "storage_users.h" #include "storage_users.h"
#include "storage_avatar.h" #include "storage_avatar.h"
#include "storage_actionLinks.h"
#include "storage_tokens.h"
namespace OpenWifi { namespace OpenWifi {
@@ -12,6 +14,7 @@ namespace OpenWifi {
Create_UserTable(); Create_UserTable();
Create_AvatarTable(); Create_AvatarTable();
Create_TokensTable(); Create_TokensTable();
Create_ActionLinkTable();
return 0; return 0;
} }
@@ -40,83 +43,51 @@ namespace OpenWifi {
return 1; return 1;
} }
int Storage::Create_ActionLinkTable() {
try {
Poco::Data::Session Sess = Pool_->get();
Sess << "CREATE TABLE IF NOT EXISTS ActionLinks ( "
+ AllActionLinksFieldsForCreation + " ) ",
Poco::Data::Keywords::now;
return 0;
} catch(const Poco::Exception &E) {
Logger_.log(E);
}
return 1;
}
int Storage::Create_AvatarTable() { int Storage::Create_AvatarTable() {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
if(dbType_==sqlite) { if(dbType_==sqlite) {
Sess << "CREATE TABLE IF NOT EXISTS Avatars (" Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_sqlite +
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar BLOB"
") ", Poco::Data::Keywords::now; ") ", Poco::Data::Keywords::now;
} else if(dbType_==mysql) { } else if(dbType_==mysql) {
Sess << "CREATE TABLE IF NOT EXISTS Avatars (" Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_mysql +
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar LONGBLOB"
") ", Poco::Data::Keywords::now; ") ", Poco::Data::Keywords::now;
} else if(dbType_==pgsql) { } else if(dbType_==pgsql) {
Sess << "CREATE TABLE IF NOT EXISTS Avatars (" Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_pgsql +
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar BYTEA"
") ", Poco::Data::Keywords::now; ") ", Poco::Data::Keywords::now;
} }
return 0; return 0;
} catch(const Poco::Exception &E) { } catch(const Poco::Exception &E) {
Logger_.log(E); Logger_.log(E);
} }
return 0; return 1;
} }
int Storage::Create_TokensTable() { int Storage::Create_TokensTable() {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
if(dbType_==sqlite) { Sess << "CREATE TABLE IF NOT EXISTS Tokens (" +
Sess << "CREATE TABLE IF NOT EXISTS Tokens (" AllTokensFieldsForCreation +
"Token TEXT PRIMARY KEY, "
"RefreshToken TEXT, "
"TokenType TEXT, "
"UserName TEXT, "
"Created BIGINT, "
"Expires BIGINT, "
"IdleTimeOut BIGINT, "
"RevocationDate BIGINT "
") ", Poco::Data::Keywords::now; ") ", Poco::Data::Keywords::now;
} else if(dbType_==mysql) {
Sess << "CREATE TABLE IF NOT EXISTS Tokens ("
"Token TEXT PRIMARY KEY, "
"RefreshToken TEXT, "
"TokenType TEXT, "
"UserName TEXT, "
"Created BIGINT, "
"Expires BIGINT, "
"IdleTimeOut BIGINT, "
"RevocationDate BIGINT "
") ", Poco::Data::Keywords::now;
} else if(dbType_==pgsql) {
Sess << "CREATE TABLE IF NOT EXISTS Tokens ("
"Token TEXT PRIMARY KEY, "
"RefreshToken TEXT, "
"TokenType TEXT, "
"UserName TEXT, "
"Created BIGINT, "
"Expires BIGINT, "
"IdleTimeOut BIGINT, "
"RevocationDate BIGINT "
") ", Poco::Data::Keywords::now;
}
return 0; return 0;
} catch(const Poco::Exception &E) { } catch(const Poco::Exception &E) {
Logger_.log(E); Logger_.log(E);
} }
return 0; return 1;
} }
} }

View File

@@ -1,5 +1,6 @@
#include "../StorageService.h" #include "StorageService.h"
#include "storage/storage_tokens.h"
namespace OpenWifi { namespace OpenWifi {
@@ -22,7 +23,7 @@ namespace OpenWifi {
uint64_t Z = 0; uint64_t Z = 0;
std::string St2{ std::string St2{
"INSERT INTO Tokens (Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate) VALUES(?,?,?,?,?,?,?,?)"}; "INSERT INTO Tokens (" + AllTokensFieldsForSelect + ") VALUES(" + AllTokensValuesForSelect + ")"};
Insert << ConvertParams(St2), Insert << ConvertParams(St2),
Poco::Data::Keywords::use(Token), Poco::Data::Keywords::use(Token),
@@ -49,7 +50,7 @@ namespace OpenWifi {
uint32_t RevocationDate = 0 ; uint32_t RevocationDate = 0 ;
std::string St2{"SELECT Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate 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_),

View File

@@ -0,0 +1,30 @@
//
// Created by stephane bourque on 2021-11-08.
//
#ifndef OWSEC_STORAGE_TOKENS_H
#define OWSEC_STORAGE_TOKENS_H
#include <string>
#include <vector>
#include "Poco/Tuple.h"
namespace OpenWifi {
static std::string AllTokensFieldsForCreation{ "Token TEXT PRIMARY KEY, "
"RefreshToken TEXT, "
"TokenType TEXT, "
"UserName TEXT, "
"Created BIGINT, "
"Expires BIGINT, "
"IdleTimeOut BIGINT, "
"RevocationDate BIGINT "
};
static std::string AllTokensFieldsForSelect {"Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate"};
static std::string AllTokensValuesForSelect{"?,?,?,?,?,?,?,?"};
}
#endif //OWSEC_STORAGE_TOKENS_H

View File

@@ -80,7 +80,35 @@ namespace OpenWifi {
return true; return true;
} }
bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser) { std::string DefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"};
// if we do not find a default user, then we need to create one based on the
// property file. We must set its flag to "must change password", this user has root privilege.
// if the "DEFAULT-USER-UUID", we keep the UUID of that user. We want to hide the UUID of the default root user
bool Storage::InitializeDefaultUser() {
SecurityObjects::UserInfo U;
bool DefaultUserCreated = false;
AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated);
if(!GetUserById(DefaultUseridStockUUID,U) && !DefaultUserCreated) {
U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password","");
U.lastPasswords.push_back(U.currentPassword);
U.email = MicroService::instance().ConfigGetString("authentication.default.username","");
U.Id = DefaultUseridStockUUID;
U.userRole = SecurityObjects::ROOT;
U.creationDate = std::time(nullptr);
U.validated = true;
U.name = "Default User";
U.description = "Default user should be deleted.";
U.changePassword = true;
CreateUser("SYSTEM",U, true);
AppServiceRegistry().Set("defaultusercreated",true);
return true;
}
return false;
}
bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready ) {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
@@ -103,19 +131,23 @@ namespace OpenWifi {
if(!Records.empty()) if(!Records.empty())
return false; return false;
NewUser.Id = MicroService::instance().CreateUUID(); if(!PasswordHashedAlready) {
NewUser.creationDate = std::time(nullptr); NewUser.Id = MicroService::instance().CreateUUID();
NewUser.creationDate = std::time(nullptr);
}
// if there is a password, we assume that we do not want email verification, // if there is a password, we assume that we do not want email verification,
// if there is no password, we will do email verification // if there is no password, we will do email verification
if(NewUser.currentPassword.empty()) { if(NewUser.currentPassword.empty()) {
} else { } else {
NewUser.currentPassword = AuthService()->ComputePasswordHash(NewUser.email,NewUser.currentPassword); if(!PasswordHashedAlready) {
NewUser.lastPasswords.clear(); NewUser.currentPassword = AuthService()->ComputeNewPasswordHash(NewUser.email,NewUser.currentPassword);
NewUser.lastPasswords.push_back(NewUser.currentPassword); NewUser.lastPasswords.clear();
NewUser.lastPasswordChange = std::time(nullptr); NewUser.lastPasswords.push_back(NewUser.currentPassword);
NewUser.validated = true; NewUser.lastPasswordChange = std::time(nullptr);
NewUser.validated = true;
}
} }
auto Notes = RESTAPI_utils::to_string(NewUser.notes); auto Notes = RESTAPI_utils::to_string(NewUser.notes);

View File

@@ -105,20 +105,6 @@ namespace OpenWifi {
"oauthType=?, " "oauthType=?, "
"oauthUserInfo=? "}; "oauthUserInfo=? "};
static const std::string AllActionLinksFieldsForCreation{
"Id varchar(36),"
"Action varchar,"
"UserId varchar,"
"template varchar,"
"locale varchar,"
"message text,"
"sent bigint,"
"created bigint,"
"expires bigint,"
"completed bigint,"
"canceled bigint"
};
typedef Poco::Tuple < typedef Poco::Tuple <
std::string, // Id = 0; std::string, // Id = 0;
std::string, // name; std::string, // name;

View File

@@ -58,8 +58,8 @@ testlogin() {
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$payload" > ${result_file} -d "$payload" > ${result_file}
userMustChangePassword=$(cat ${result_file} | jq -r '.userMustChangePassword') userMustChangePassword=$(cat ${result_file} | jq -r '.ErrorCode')
if [[ ${userMustChangePassword} == "true" ]] if [[ ${userMustChangePassword} == "1" ]]
then then
echo "User must change password to login..." echo "User must change password to login..."
if [[ "$3" == "" ]] if [[ "$3" == "" ]]
@@ -78,7 +78,10 @@ testlogin() {
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$payload" > ${result_file} -d "$payload" > ${result_file}
jq < ${result_file} token=$(cat ${result_file} | jq -r '.access_token')
else
payload="{ \"userId\" : \"$1\" , \"password\" : \"$2\" }"
token=$(curl ${FLAGS} -X POST -H "Content-Type: application/json" -d "$payload" "https://${OWSEC}/api/v1/oauth2" | jq -r '.access_token')
fi fi
jq < ${result_file} jq < ${result_file}
} }
@@ -372,6 +375,7 @@ case "$1" in
"getsubsystemnames") login; getsubsystemnames; logout ;; "getsubsystemnames") login; getsubsystemnames; logout ;;
"reloadsubsystem") login; reloadsubsystem "$2"; logout ;; "reloadsubsystem") login; reloadsubsystem "$2"; logout ;;
"systeminfo") login; systeminfo ; logout;; "systeminfo") login; systeminfo ; logout;;
"testburst") login; login; login; login; login; login; login; login; login; login; login; login; login; login; login; login;;
"help") login; help ; logout ;; "help") login; help ; logout ;;
*) help ;; *) help ;;
esac esac

View File

@@ -29,9 +29,38 @@
opacity: 0.8; opacity: 0.8;
} }
.imgcontainer { .img-container {
width: 100%;
margin-top: 5%;
text-align: center; text-align: center;
margin: 24px 0 12px 0; display: block;
}
.info-card {
padding: 30px;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
display: block;
width: 50%;
border: 1em;
background-color: white;
width: 40%;
height: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
margin-top: 50px;
position: relative;
}
.info-list {
width: 80%;
margin: auto;
}
.info-title {
padding-bottom: 20px;
width: 80%;
margin: auto;
} }
img.avatar { img.avatar {
@@ -48,6 +77,10 @@
padding-top: 16px; padding-top: 16px;
} }
body {
background-color: #ebedef;
}
/* Change styles for span and cancel button on extra small screens */ /* Change styles for span and cancel button on extra small screens */
@media screen and (max-width: 300px) { @media screen and (max-width: 300px) {
span.password1 { span.password1 {
@@ -62,17 +95,17 @@
</head> </head>
<body> <body>
<div class="imgcontainer"> <div class="img-container">
<img src="open-wifi.svg" alt="OpenWifi"> <img src="/wwwassets/the_logo.png" alt="OpenWifi">
</div> </div>
<div> <div class="info-card">
<p>Site access rules:</p> <h2 class="info-title">Site Access rules</h2>
<ul> <ul class="info-list">
<li>Must be a TIP Member.</li> <li>Must be a TIP Member.</li>
</ul> </ul>
</div> </div>
</body> </body>
</html> </html>

View File

@@ -30,8 +30,10 @@
} }
.imgcontainer { .imgcontainer {
width: 100%;
margin-top: 5%;
text-align: center; text-align: center;
margin: 24px 0 12px 0; display: block;
} }
img.avatar { img.avatar {
@@ -43,6 +45,37 @@
padding: 16px; padding: 16px;
} }
.info-card {
padding: 30px;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
display: block;
width: 50%;
border: 1em;
background-color: white;
width: 40%;
height: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
margin-top: 50px;
position: relative;
}
.info-list {
width: 80%;
margin: auto;
}
.info-title {
padding-bottom: 20px;
width: 80%;
margin: auto;
}
.body {
background-color: #ebedef;
}
span.password1 { span.password1 {
float: right; float: right;
padding-top: 16px; padding-top: 16px;
@@ -60,16 +93,17 @@
} }
</style> </style>
</head> </head>
<body> <body class="body">
<div class="imgcontainer"> <div class="imgcontainer">
<img src="open-wifi.svg" alt="OpenWifi"> <img src="/wwwassets/the_logo.png" alt="OpenWifi">
</div> </div>
<div>
<p>Password rules:</p> <div class="info-card">
<ul> <h2 class="info-title">Password rules</h2>
<li>Must be at least 8 characters long.</li> <ul class="info-list">
<li>Must be at least 8 characters long</li>
<li>Must contain 1 uppercase letter</li> <li>Must contain 1 uppercase letter</li>
<li>Must contain 1 lowercase letter</li> <li>Must contain 1 lowercase letter</li>
<li>Must contain 1 digit</li> <li>Must contain 1 digit</li>
@@ -78,5 +112,6 @@
</div> </div>
</body> </body>
</html> </html>

View File

@@ -3,8 +3,15 @@
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<style> <style>
body {font-family: Arial, Helvetica, sans-serif;} body {
form {border: 3px solid #f1f1f1;} font-family: Arial,
Helvetica, sans-serif;
background-color: #ebedef;
}
.body {
background-color: #ebedef;
}
input[type=text], input[type=password] { input[type=text], input[type=password] {
width: 90%; width: 90%;
@@ -31,15 +38,10 @@
} }
.imgcontainer { .imgcontainer {
width: 100%;
margin-top: 5%;
text-align: center; text-align: center;
margin: 5px 0 5px 0; display: block;
grid-column-start: 2;
grid-column-end: 2;
}
.passwordlabel {
grid-column-start: 2;
grid-column-end: 2;
} }
img.avatar { img.avatar {
@@ -50,16 +52,22 @@
.grid-container { .grid-container {
display: grid; display: grid;
grid-template-columns: 15% 70% 15%; grid-template-columns: 15% 70% 15%;
background-color: #f3db21;
grid-column-gap: 5px; grid-column-gap: 5px;
padding: 10px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.8);
text-align: center; text-align: center;
padding: 20px 0; padding: 30px;
font-size: 30px; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
display: block;
width: 50%;
border: 1em;
background-color: white;
width: 40%;
height: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
margin-top: 50px;
position: relative;
} }
.passwordtext { .passwordtext {
@@ -67,7 +75,13 @@
margin-left: 5%; margin-left: 5%;
} }
.password-input {
margin-top: 0px;
}
.rulestext { .rulestext {
width: 95%;
margin: auto;
display: inline-block; display: inline-block;
text-align: left; text-align: left;
text-justify: none; text-justify: none;
@@ -101,17 +115,18 @@
</head> </head>
<body> <body>
<div class="imgcontainer">
<img src="/wwwassets/the_logo.png" alt="OpenWifi">
</div>
<form action="/api/v1/actionLink?action=password_reset" method="post" onsubmit="return validatePassword()"> <form action="/api/v1/actionLink?action=password_reset" method="post" onsubmit="return validatePassword()">
<input type="hidden" id="custId" name="id" value="${UUID}"> <input type="hidden" id="custId" name="id" value="${UUID}">
<div class="grid-container"> <div class="grid-container">
<h2>Reset Password</h2>
<div class="imgcontainer">
<img src="/wwwassets/open-wifi.svg" alt="Logo" class="logo">
</div>
<div class="passwordlabel"> <div class="passwordlabel">
<label class="passwordtext" for="password1" ><b>New Password</b></label> <label class="passwordtext" for="password1" ><b>New Password</b></label>
<input id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required> <input className="password-input" id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required>
</div> </div>
<div class="passwordlabel"> <div class="passwordlabel">
<label class="passwordtext" for="password2"><b>Retype Password</b></label> <label class="passwordtext" for="password2"><b>Retype Password</b></label>

View File

@@ -1,11 +1,107 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Reset Password Failed</title> <style>
body {font-family: Arial, Helvetica, sans-serif;}
form {border: 3px solid #f1f1f1;}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
button {
background-color: #04AA6D;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 100%;
}
button:hover {
opacity: 0.8;
}
.imgcontainer {
width: 100%;
margin-top: 5%;
text-align: center;
display: block;
}
img.avatar {
width: 40%;
border-radius: 50%;
}
.container {
padding: 16px;
}
.info-card {
padding: 30px;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
display: block;
width: 50%;
border: 1em;
background-color: white;
width: 40%;
height: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
margin-top: 50px;
position: relative;
}
.info-list {
width: 80%;
margin: auto;
}
.info-title {
padding-bottom: 20px;
width: 80%;
margin: auto;
}
.body {
background-color: #ebedef;
}
span.password1 {
float: right;
padding-top: 16px;
}
/* Change styles for span and cancel button on extra small screens */
@media screen and (max-width: 300px) {
span.password1 {
display: block;
float: none;
}
.cancelbtn {
width: 100%;
}
}
</style>
</head> </head>
<body> <body class="body">
<h1>Password reset failed...</h1>
<div class="imgcontainer">
<img src="/wwwassets/the_logo.png" alt="OpenWifi">
</div>
<div class="info-card">
<h1 class="info-title">Reset Password Failed</h1>
<div> <div>
<h3>ID</h3> <h3>ID</h3>
<b>${UUID}</b> <b>${UUID}</b>
@@ -14,5 +110,7 @@
<h3>Error</h3> <h3>Error</h3>
<b>${ERROR_TEXT}</b> <b>${ERROR_TEXT}</b>
</div> </div>
</div>
</body> </body>
</html> </html>

View File

@@ -62,8 +62,9 @@
</head> </head>
<body> <body>
<div class="imgcontainer"> <div class="imgcontainer">
<img src="/wwwassets/avatar.jpg" alt="Avatar" class="avatar"> <img src="/wwwassets/the_logo.png" alt="Avatar" class="avatar">
</div> </div>
<h1>Password was successfully reset</h1> <h1>Password was successfully reset</h1>
<div> <div>
<h3>Thank you ${USERNAME} for resetting your password.</h3> <h3>Thank you ${USERNAME} for resetting your password.</h3>

BIN
wwwassets/the_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB