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 1860 additions and 718 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owsec VERSION 2.3.0)
project(owsec VERSION 2.4.0)
set(CMAKE_CXX_STANDARD 17)
@@ -42,7 +42,7 @@ find_package(Boost REQUIRED system)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(AWSSDK REQUIRED COMPONENTS sns)
find_package(nlohmann_json REQUIRED)
find_package(CppKafka REQUIRED)
find_package(PostgreSQL REQUIRED)
find_package(MySQL REQUIRED)
@@ -86,7 +86,11 @@ add_executable( owsec
src/MFAServer.cpp src/MFAServer.h
src/SMS_provider_aws.cpp src/SMS_provider_aws.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)
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/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
WORKDIR /aws-sdk-cpp
@@ -37,6 +39,20 @@ RUN cmake ..
RUN cmake --build . --config Release -j8
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 cmake /owsec/cmake
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
COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
EXPOSE 16001 17001 16101

View File

@@ -98,6 +98,40 @@ to get a sample. The default is
### `authentication.oldpasswords`
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
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.
@@ -217,4 +251,4 @@ mailer.sender = OpenWIFI
mailer.loginmethod = login
mailer.port = 587
mailer.templates = $OWSEC_ROOT/templates
```
```

2
build
View File

@@ -1 +1 @@
14
47

View File

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

View File

@@ -95,6 +95,8 @@ tolerations: []
affinity: {}
podAnnotations: {}
persistence:
enabled: true
# storageClassName: "-"

View File

@@ -51,6 +51,16 @@ components:
properties:
ErrorCode:
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:
type: string
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/JWT/Token.h"
#include "Poco/JWT/Signer.h"
#include "Poco/StringTokenizer.h"
#include "framework/MicroService.h"
#include "StorageService.h"
@@ -21,7 +22,6 @@
#include "MFAServer.h"
namespace OpenWifi {
class AuthService *AuthService::instance_ = nullptr;
AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
switch (C) {
@@ -46,10 +46,6 @@ namespace OpenWifi {
Signer_.setRSAKey(MicroService::instance().Key());
Signer_.addAllAlgorithms();
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,}$");
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
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 )
{
if(!Secure_)
return true;
std::lock_guard Guard(Mutex_);
std::string CallToken;
std::lock_guard Guard(Mutex_);
try {
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") {
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;
std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken();
}
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;
}
@@ -168,28 +166,6 @@ namespace OpenWifi {
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)
{
std::lock_guard Guard(Mutex_);
@@ -215,35 +191,80 @@ namespace OpenWifi {
}
bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword);
for (auto const &i:UInfo.lastPasswords) {
if (i == NewPasswordHash) {
return false;
std::lock_guard G(Mutex_);
Poco::toLowerInPlace(UInfo.email);
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_) {
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;
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_);
SecurityObjects::AclTemplate ACL;
Poco::toLowerInPlace(UserName);
auto PasswordHash = ComputePasswordHash(UserName, Password);
if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION;
}
if(PasswordHash != UInfo.userinfo.currentPassword) {
if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
return INVALID_CREDENTIALS;
}
@@ -273,51 +294,31 @@ namespace OpenWifi {
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;
}
std::string AuthService::ComputePasswordHash(const std::string &UserName, const std::string &Password) {
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) {
bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
SecurityObjects::UserInfo UInfo;
if(StorageService()->GetUserByEmail(Email,UInfo)) {
switch (Reason) {
case FORGOT_PASSWORD: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg";
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
}
break;
case EMAIL_VERIFICATION: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg";
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true;
}
@@ -326,19 +327,20 @@ namespace OpenWifi {
default:
break;
}
return true;
}
return false;
}
bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
MessageAttributes Attrs;
SecurityObjects::ActionLink A;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
A.userId = UInfo.email;
A.id = MicroService::instance().CreateUUID();
A.created = std::time(nullptr);
A.expires = A.created + 24*60*60;
StorageService()->CreateAction(A);
UInfo.waitingForEmailCheck = true;
return true;
}

View File

@@ -35,16 +35,6 @@ namespace OpenWifi{
CUSTOM
};
enum AUTH_ERROR {
SUCCESS,
PASSWORD_CHANGE_REQUIRED,
INVALID_CREDENTIALS,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR
};
enum EMAIL_REASON {
FORGOT_PASSWORD,
EMAIL_VERIFICATION
@@ -54,19 +44,16 @@ namespace OpenWifi{
static int AccessTypeToInt(ACCESS_TYPE T);
static AuthService *instance() {
if (instance_ == nullptr) {
instance_ = new AuthService;
}
return instance_;
static AuthService instance;
return &instance;
}
int Start() override;
void Stop() override;
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
[[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);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo );
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
void Logout(const std::string &token, bool EraseFromCache=true);
@@ -77,26 +64,31 @@ namespace OpenWifi{
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
[[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
[[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]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
[[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 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:
static AuthService *instance_;
bool Secure_ = false ;
std::string DefaultUserName_;
std::string DefaultPassword_;
std::string Mechanism_;
Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_;
SecurityObjects::UserInfoCache UserCache_;
std::string PasswordValidationStr_;
std::string PasswordValidationStr_;
std::regex PasswordValidation_;
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
uint64_t HowManyOldPassword_=5;

View File

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

View File

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

View File

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

View File

@@ -11,46 +11,61 @@
#include "Daemon.h"
namespace OpenWifi {
void RESTAPI_action_links::DoGet() {
auto Action = GetParameter("action","");
auto Id = GetParameter("id","");
SecurityObjects::ActionLink Link;
if(!StorageService()->GetActionLink(Id,Link))
return DoReturnA404();
if(Action=="password_reset")
return RequestResetPassword(Id);
return RequestResetPassword(Link);
else if(Action=="email_verification")
return DoEmailVerification(Id);
return DoEmailVerification(Link);
else
return DoReturnA404();
}
void RESTAPI_action_links::DoPost() {
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")
CompleteResetPassword(Id);
return CompleteResetPassword();
else
DoReturnA404();
return DoReturnA404();
}
void RESTAPI_action_links::RequestResetPassword(std::string &Id) {
Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId));
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
Types::StringPairVec FormVars{ {"UUID", Link.id},
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
SendHTMLFileBack(FormFile,FormVars);
}
void RESTAPI_action_links::CompleteResetPassword(std::string &Id) {
void RESTAPI_action_links::CompleteResetPassword() {
// form has been posted...
RESTAPI_PartHandler PartHandler;
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
if (!Form.empty()) {
auto Password1 = Form.get("password1","bla");
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)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
@@ -62,7 +77,7 @@ namespace OpenWifi {
}
SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(Id,UInfo)) {
if(!StorageService()->GetUserById(Link.userId,UInfo)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"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."}};
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"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"USERNAME", UInfo.email},
{"ACTION_LINK",MicroService::instance().GetUIURI()}};
StorageService()->CompleteAction(Id);
SendHTMLFileBack(FormFile,FormVars);
} else {
DoReturnA404();
}
}
void RESTAPI_action_links::DoEmailVerification(std::string &Id) {
SecurityObjects::UserInfo UInfo;
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
auto Now = std::time(nullptr);
Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), Id));
if (!StorageService()->GetUserById(Id, UInfo)) {
Types::StringPairVec FormVars{{"UUID", Id},
if(Now > Link.expires) {
StorageService()->CancelAction(Link.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.."}};
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
return SendHTMLFileBack(FormFile, FormVars);
}
Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email));
UInfo.waitingForEmailCheck = false;
UInfo.validated = true;
UInfo.lastEmailCheck = std::time(nullptr);
UInfo.validationDate = std::time(nullptr);
StorageService()->UpdateUserInfo(UInfo.email, Id, UInfo);
Types::StringPairVec FormVars{{"UUID", Id},
StorageService()->UpdateUserInfo(UInfo.email, Link.userId, UInfo);
Types::StringPairVec FormVars{{"UUID", Link.id},
{"USERNAME", UInfo.email},
{"ACTION_LINK",MicroService::instance().GetUIURI()}};
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
StorageService()->CompleteAction(Link.id);
SendHTMLFileBack(FormFile, FormVars);
}

View File

@@ -19,11 +19,12 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
Internal,
false) {}
false,
true, RateLimit{.Interval=1000,.MaxCalls=5}) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
void RequestResetPassword(std::string &Id);
void CompleteResetPassword(std::string &Id);
void DoEmailVerification(std::string &Id);
void RequestResetPassword(SecurityObjects::ActionLink &Link);
void CompleteResetPassword();
void DoEmailVerification(SecurityObjects::ActionLink &Link);
void DoReturnA404();
void DoGet() final;

View File

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

View File

@@ -21,7 +21,7 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
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"}; };
void DoGet() final;
void DoPost() final;

View File

@@ -25,7 +25,11 @@ namespace OpenWifi {
} else if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound();
}
Poco::JSON::Object UserInfoObject;
UInfo.currentPassword.clear();
UInfo.lastPasswords.clear();
UInfo.oauthType.clear();
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
}
@@ -36,17 +40,30 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
if(UserInfo_.userinfo.userRole!= SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(UserInfo_.userinfo.Id == Id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound();
}
if(UInfo.userRole==SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
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));
StorageService()->RevokeAllTokens(UInfo.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);
}
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);
if(!Utils::ValidEMailAddress(UInfo.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
@@ -115,6 +140,14 @@ namespace OpenWifi {
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;
auto RawObject = ParseStream();
if(!NewUser.from_json(RawObject)) {
@@ -136,8 +169,19 @@ namespace OpenWifi {
AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole"))
Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(RawObject->has("userRole")) {
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")) {
SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
@@ -161,26 +205,27 @@ namespace OpenWifi {
}
if(RawObject->has("userTypeProprietaryInfo")) {
bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.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;
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::Object Answer;
if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) {
for (const auto &i : Users) {
for (auto &i : Users) {
Poco::JSON::Object Obj;
if (IdOnly) {
ArrayObj.add(i.Id);
} else {
i.currentPassword.clear();
i.lastPasswords.clear();
i.oauthType.clear();
i.to_json(Obj);
ArrayObj.add(Obj);
}
@@ -38,6 +41,9 @@ namespace OpenWifi {
if (IdOnly) {
ArrayObj.add(UInfo.Id);
} else {
UInfo.currentPassword.clear();
UInfo.lastPasswords.clear();
UInfo.oauthType.clear();
UInfo.to_json(Obj);
ArrayObj.add(Obj);
}

View File

@@ -68,7 +68,7 @@ namespace OpenWifi::GWObjects {
#endif
}
bool Device::from_json(Poco::JSON::Object::Ptr Obj) {
bool Device::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",SerialNumber);
field_from_json(Obj,"deviceType",DeviceType);
@@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects {
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 {
field_from_json(Obj,"name",Name);
field_from_json(Obj,"configuration",Configuration);
@@ -166,7 +166,7 @@ namespace OpenWifi::GWObjects {
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 {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"author",author);

View File

@@ -59,7 +59,7 @@ namespace OpenWifi::GWObjects {
std::string DevicePassword;
void to_json(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;
};
@@ -116,7 +116,7 @@ namespace OpenWifi::GWObjects {
uint64_t Created;
uint64_t LastModified;
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 {
@@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects {
std::string author;
uint64_t created;
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 {

View File

@@ -10,27 +10,30 @@
#include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::ProvObjects {
void ObjectInfo::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj,"id",id);
RESTAPI_utils::field_to_json(Obj,"name",name);
RESTAPI_utils::field_to_json(Obj,"description",description);
RESTAPI_utils::field_to_json(Obj,"created",created);
RESTAPI_utils::field_to_json(Obj,"modified",modified);
RESTAPI_utils::field_to_json(Obj,"notes",notes);
RESTAPI_utils::field_to_json(Obj,"tags",tags);
field_to_json(Obj,"id",id);
field_to_json(Obj,"name",name);
field_to_json(Obj,"description",description);
field_to_json(Obj,"created",created);
field_to_json(Obj,"modified",modified);
field_to_json(Obj,"notes",notes);
field_to_json(Obj,"tags",tags);
}
bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json(Obj,"id",id);
RESTAPI_utils::field_from_json(Obj,"name",name);
RESTAPI_utils::field_from_json(Obj,"description",description);
RESTAPI_utils::field_from_json(Obj,"created",created);
RESTAPI_utils::field_from_json(Obj,"modified",modified);
RESTAPI_utils::field_from_json(Obj,"notes",notes);
RESTAPI_utils::field_from_json(Obj,"tags",tags);
field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name);
field_from_json(Obj,"description",description);
field_from_json(Obj,"created",created);
field_from_json(Obj,"modified",modified);
field_from_json(Obj,"notes",notes);
field_from_json(Obj,"tags",tags);
return true;
} catch(...) {
@@ -39,18 +42,18 @@ namespace OpenWifi::ProvObjects {
}
void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"users",users);
RESTAPI_utils::field_to_json( Obj,"resources",resources);
RESTAPI_utils::field_to_json( Obj,"access",access);
RESTAPI_utils::field_to_json( Obj,"policy",policy);
field_to_json( Obj,"users",users);
field_to_json( Obj,"resources",resources);
field_to_json( Obj,"access",access);
field_to_json( Obj,"policy",policy);
}
bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"users",users);
RESTAPI_utils::field_from_json( Obj,"resources",resources);
RESTAPI_utils::field_from_json( Obj,"access",access);
RESTAPI_utils::field_from_json( Obj,"policy",policy);
field_from_json( Obj,"users",users);
field_from_json( Obj,"resources",resources);
field_from_json( Obj,"access",access);
field_from_json( Obj,"policy",policy);
return true;
} catch(...) {
@@ -60,17 +63,17 @@ namespace OpenWifi::ProvObjects {
void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json(Obj, "entries", entries);
RESTAPI_utils::field_to_json(Obj, "inUse", inUse);
RESTAPI_utils::field_to_json(Obj, "entity", entity);
field_to_json(Obj, "entries", entries);
field_to_json(Obj, "inUse", inUse);
field_to_json(Obj, "entity", entity);
}
bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json(Obj, "entries", entries);
RESTAPI_utils::field_from_json(Obj, "inUse", inUse);
RESTAPI_utils::field_from_json(Obj, "entity", entity);
field_from_json(Obj, "entries", entries);
field_from_json(Obj, "inUse", inUse);
field_from_json(Obj, "entity", entity);
return true;
} catch(...) {
@@ -80,31 +83,31 @@ namespace OpenWifi::ProvObjects {
void Entity::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"venues",venues);
RESTAPI_utils::field_to_json( Obj,"children",children);
RESTAPI_utils::field_to_json( Obj,"contacts",contacts);
RESTAPI_utils::field_to_json( Obj,"locations",locations);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"devices",devices);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP);
field_to_json( Obj,"parent",parent);
field_to_json( Obj,"venues",venues);
field_to_json( Obj,"children",children);
field_to_json( Obj,"contacts",contacts);
field_to_json( Obj,"locations",locations);
field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
field_to_json( Obj,"devices",devices);
field_to_json( Obj,"rrm",rrm);
field_to_json( Obj,"sourceIP",sourceIP);
}
bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"venues",venues);
RESTAPI_utils::field_from_json( Obj,"children",children);
RESTAPI_utils::field_from_json( Obj,"contacts",contacts);
RESTAPI_utils::field_from_json( Obj,"locations",locations);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"devices",devices);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP);
field_from_json( Obj,"parent",parent);
field_from_json( Obj,"venues",venues);
field_from_json( Obj,"children",children);
field_from_json( Obj,"contacts",contacts);
field_from_json( Obj,"locations",locations);
field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
field_from_json( Obj,"devices",devices);
field_from_json( Obj,"rrm",rrm);
field_from_json( Obj,"sourceIP",sourceIP);
return true;
} catch(...) {
@@ -113,14 +116,14 @@ namespace OpenWifi::ProvObjects {
}
void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"child",child);
field_to_json( Obj,"parent",parent);
field_to_json( Obj,"child",child);
}
bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"child",child);
field_from_json( Obj,"parent",parent);
field_from_json( Obj,"child",child);
return true;
} catch (...) {
@@ -130,37 +133,37 @@ namespace OpenWifi::ProvObjects {
void Venue::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"children",children);
RESTAPI_utils::field_to_json( Obj,"devices",devices);
RESTAPI_utils::field_to_json( Obj,"topology",topology);
RESTAPI_utils::field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"design",design);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"contact",contact);
RESTAPI_utils::field_to_json( Obj,"location",location);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP);
field_to_json( Obj,"parent",parent);
field_to_json( Obj,"entity",entity);
field_to_json( Obj,"children",children);
field_to_json( Obj,"devices",devices);
field_to_json( Obj,"topology",topology);
field_to_json( Obj,"parent",parent);
field_to_json( Obj,"design",design);
field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
field_to_json( Obj,"contact",contact);
field_to_json( Obj,"location",location);
field_to_json( Obj,"rrm",rrm);
field_to_json( Obj,"sourceIP",sourceIP);
}
bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"children",children);
RESTAPI_utils::field_from_json( Obj,"devices",devices);
RESTAPI_utils::field_from_json( Obj,"topology",topology);
RESTAPI_utils::field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"design",design);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"contact",contact);
RESTAPI_utils::field_from_json( Obj,"location",location);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP);
field_from_json( Obj,"parent",parent);
field_from_json( Obj,"entity",entity);
field_from_json( Obj,"children",children);
field_from_json( Obj,"devices",devices);
field_from_json( Obj,"topology",topology);
field_from_json( Obj,"parent",parent);
field_from_json( Obj,"design",design);
field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
field_from_json( Obj,"contact",contact);
field_from_json( Obj,"location",location);
field_from_json( Obj,"rrm",rrm);
field_from_json( Obj,"sourceIP",sourceIP);
return true;
} catch (...) {
@@ -169,16 +172,16 @@ namespace OpenWifi::ProvObjects {
}
void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"id",id);
RESTAPI_utils::field_to_json( Obj,"entity",loginId);
RESTAPI_utils::field_to_json( Obj,"children",userType);
field_to_json( Obj,"id",id);
field_to_json( Obj,"entity",loginId);
field_to_json( Obj,"children",userType);
}
bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"id",id);
RESTAPI_utils::field_from_json( Obj,"entity",loginId);
RESTAPI_utils::field_from_json( Obj,"children",userType);
field_from_json( Obj,"id",id);
field_from_json( Obj,"entity",loginId);
field_from_json( Obj,"children",userType);
return true;
} catch(...) {
}
@@ -187,17 +190,17 @@ namespace OpenWifi::ProvObjects {
void ManagementRole::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"users",users);
RESTAPI_utils::field_to_json( Obj,"entity",entity);
field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"users",users);
field_to_json( Obj,"entity",entity);
}
bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"users",users);
RESTAPI_utils::field_from_json( Obj,"entity",entity);
field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"users",users);
field_from_json( Obj,"entity",entity);
return true;
} catch(...) {
}
@@ -206,39 +209,39 @@ namespace OpenWifi::ProvObjects {
void Location::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
RESTAPI_utils::field_to_json( Obj,"buildingName",buildingName);
RESTAPI_utils::field_to_json( Obj,"addressLines",addressLines);
RESTAPI_utils::field_to_json( Obj,"city",city);
RESTAPI_utils::field_to_json( Obj,"state",state);
RESTAPI_utils::field_to_json( Obj,"postal",postal);
RESTAPI_utils::field_to_json( Obj,"country",country);
RESTAPI_utils::field_to_json( Obj,"phones",phones);
RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_to_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
field_to_json( Obj,"buildingName",buildingName);
field_to_json( Obj,"addressLines",addressLines);
field_to_json( Obj,"city",city);
field_to_json( Obj,"state",state);
field_to_json( Obj,"postal",postal);
field_to_json( Obj,"country",country);
field_to_json( Obj,"phones",phones);
field_to_json( Obj,"mobiles",mobiles);
field_to_json( Obj,"geoCode",geoCode);
field_to_json( Obj,"inUse",inUse);
field_to_json( Obj,"entity",entity);
field_to_json( Obj,"managementPolicy",managementPolicy);
}
bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
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);
RESTAPI_utils::field_from_json( Obj,"buildingName",buildingName);
RESTAPI_utils::field_from_json( Obj,"addressLines",addressLines);
RESTAPI_utils::field_from_json( Obj,"city",city);
RESTAPI_utils::field_from_json( Obj,"state",state);
RESTAPI_utils::field_from_json( Obj,"postal",postal);
RESTAPI_utils::field_from_json( Obj,"country",country);
RESTAPI_utils::field_from_json( Obj,"phones",phones);
RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"buildingName",buildingName);
field_from_json( Obj,"addressLines",addressLines);
field_from_json( Obj,"city",city);
field_from_json( Obj,"state",state);
field_from_json( Obj,"postal",postal);
field_from_json( Obj,"country",country);
field_from_json( Obj,"phones",phones);
field_from_json( Obj,"mobiles",mobiles);
field_from_json( Obj,"geoCode",geoCode);
field_from_json( Obj,"inUse",inUse);
field_from_json( Obj,"entity",entity);
field_from_json( Obj,"managementPolicy",managementPolicy);
return true;
} catch (...) {
@@ -248,43 +251,43 @@ namespace OpenWifi::ProvObjects {
void Contact::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"type", to_string(type));
RESTAPI_utils::field_to_json( Obj,"title",title);
RESTAPI_utils::field_to_json( Obj,"salutation",salutation);
RESTAPI_utils::field_to_json( Obj,"firstname",firstname);
RESTAPI_utils::field_to_json( Obj,"lastname",lastname);
RESTAPI_utils::field_to_json( Obj,"initials",initials);
RESTAPI_utils::field_to_json( Obj,"visual",visual);
RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_to_json( Obj,"phones",phones);
RESTAPI_utils::field_to_json( Obj,"primaryEmail",primaryEmail);
RESTAPI_utils::field_to_json( Obj,"secondaryEmail",secondaryEmail);
RESTAPI_utils::field_to_json( Obj,"accessPIN",accessPIN);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"type", to_string(type));
field_to_json( Obj,"title",title);
field_to_json( Obj,"salutation",salutation);
field_to_json( Obj,"firstname",firstname);
field_to_json( Obj,"lastname",lastname);
field_to_json( Obj,"initials",initials);
field_to_json( Obj,"visual",visual);
field_to_json( Obj,"mobiles",mobiles);
field_to_json( Obj,"phones",phones);
field_to_json( Obj,"primaryEmail",primaryEmail);
field_to_json( Obj,"secondaryEmail",secondaryEmail);
field_to_json( Obj,"accessPIN",accessPIN);
field_to_json( Obj,"inUse",inUse);
field_to_json( Obj,"entity",entity);
field_to_json( Obj,"managementPolicy",managementPolicy);
}
bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
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);
RESTAPI_utils::field_from_json( Obj,"title",title);
RESTAPI_utils::field_from_json( Obj,"salutation",salutation);
RESTAPI_utils::field_from_json( Obj,"firstname",firstname);
RESTAPI_utils::field_from_json( Obj,"lastname",lastname);
RESTAPI_utils::field_from_json( Obj,"initials",initials);
RESTAPI_utils::field_from_json( Obj,"visual",visual);
RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_from_json( Obj,"phones",phones);
RESTAPI_utils::field_from_json( Obj,"primaryEmail",primaryEmail);
RESTAPI_utils::field_from_json( Obj,"secondaryEmail",secondaryEmail);
RESTAPI_utils::field_from_json( Obj,"accessPIN",accessPIN);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"title",title);
field_from_json( Obj,"salutation",salutation);
field_from_json( Obj,"firstname",firstname);
field_from_json( Obj,"lastname",lastname);
field_from_json( Obj,"initials",initials);
field_from_json( Obj,"visual",visual);
field_from_json( Obj,"mobiles",mobiles);
field_from_json( Obj,"phones",phones);
field_from_json( Obj,"primaryEmail",primaryEmail);
field_from_json( Obj,"secondaryEmail",secondaryEmail);
field_from_json( Obj,"accessPIN",accessPIN);
field_from_json( Obj,"inUse",inUse);
field_from_json( Obj,"entity",entity);
field_from_json( Obj,"managementPolicy",managementPolicy);
return true;
} catch (...) {
@@ -294,35 +297,35 @@ namespace OpenWifi::ProvObjects {
void InventoryTag::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json(Obj, "serialNumber", serialNumber);
RESTAPI_utils::field_to_json(Obj, "venue", venue);
RESTAPI_utils::field_to_json(Obj, "entity", entity);
RESTAPI_utils::field_to_json(Obj, "subscriber", subscriber);
RESTAPI_utils::field_to_json(Obj, "deviceType", deviceType);
RESTAPI_utils::field_to_json(Obj, "qrCode", qrCode);
RESTAPI_utils::field_to_json(Obj, "geoCode", geoCode);
RESTAPI_utils::field_to_json(Obj, "location", location);
RESTAPI_utils::field_to_json(Obj, "contact", contact);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json(Obj, "serialNumber", serialNumber);
field_to_json(Obj, "venue", venue);
field_to_json(Obj, "entity", entity);
field_to_json(Obj, "subscriber", subscriber);
field_to_json(Obj, "deviceType", deviceType);
field_to_json(Obj, "qrCode", qrCode);
field_to_json(Obj, "geoCode", geoCode);
field_to_json(Obj, "location", location);
field_to_json(Obj, "contact", contact);
field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
field_to_json( Obj,"rrm",rrm);
field_to_json( Obj,"managementPolicy",managementPolicy);
}
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"serialNumber",serialNumber);
RESTAPI_utils::field_from_json( Obj,"venue",venue);
RESTAPI_utils::field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"subscriber",subscriber);
RESTAPI_utils::field_from_json( Obj,"deviceType",deviceType);
RESTAPI_utils::field_from_json(Obj, "qrCode", qrCode);
RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_from_json( Obj,"location",location);
RESTAPI_utils::field_from_json( Obj,"contact",contact);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"serialNumber",serialNumber);
field_from_json( Obj,"venue",venue);
field_from_json( Obj,"entity",entity);
field_from_json( Obj,"subscriber",subscriber);
field_from_json( Obj,"deviceType",deviceType);
field_from_json(Obj, "qrCode", qrCode);
field_from_json( Obj,"geoCode",geoCode);
field_from_json( Obj,"location",location);
field_from_json( Obj,"contact",contact);
field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
field_from_json( Obj,"rrm",rrm);
field_from_json( Obj,"managementPolicy",managementPolicy);
return true;
} catch(...) {
@@ -331,18 +334,18 @@ namespace OpenWifi::ProvObjects {
}
void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"name", name);
RESTAPI_utils::field_to_json( Obj,"description", description);
RESTAPI_utils::field_to_json( Obj,"weight", weight);
RESTAPI_utils::field_to_json( Obj,"configuration", configuration);
field_to_json( Obj,"name", name);
field_to_json( Obj,"description", description);
field_to_json( Obj,"weight", weight);
field_to_json( Obj,"configuration", configuration);
}
bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"name",name);
RESTAPI_utils::field_from_json( Obj,"description",description);
RESTAPI_utils::field_from_json( Obj,"weight",weight);
RESTAPI_utils::field_from_json( Obj,"configuration",configuration);
field_from_json( Obj,"name",name);
field_from_json( Obj,"description",description);
field_from_json( Obj,"weight",weight);
field_from_json( Obj,"configuration",configuration);
return true;
} catch(...) {
@@ -352,27 +355,27 @@ namespace OpenWifi::ProvObjects {
void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceTypes",deviceTypes);
RESTAPI_utils::field_to_json( Obj,"configuration",configuration);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"variables",variables);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
RESTAPI_utils::field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"deviceTypes",deviceTypes);
field_to_json( Obj,"configuration",configuration);
field_to_json( Obj,"inUse",inUse);
field_to_json( Obj,"variables",variables);
field_to_json( Obj,"rrm",rrm);
field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
}
bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceTypes",deviceTypes);
RESTAPI_utils::field_from_json( Obj,"configuration",configuration);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"variables",variables);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
RESTAPI_utils::field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"deviceTypes",deviceTypes);
field_from_json( Obj,"configuration",configuration);
field_from_json( Obj,"inUse",inUse);
field_from_json( Obj,"variables",variables);
field_from_json( Obj,"rrm",rrm);
field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
return true;
} catch(...) {
@@ -381,8 +384,8 @@ namespace OpenWifi::ProvObjects {
}
void Report::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "snapshot", snapShot);
RESTAPI_utils::field_to_json(Obj, "devices", tenants);
field_to_json(Obj, "snapshot", snapShot);
field_to_json(Obj, "devices", tenants);
};
void Report::reset() {
@@ -390,16 +393,16 @@ namespace OpenWifi::ProvObjects {
}
void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "uuid", uuid);
RESTAPI_utils::field_to_json(Obj, "name", name);
RESTAPI_utils::field_to_json(Obj, "description", description);
field_to_json(Obj, "uuid", uuid);
field_to_json(Obj, "name", name);
field_to_json(Obj, "description", description);
}
bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"uuid",uuid);
RESTAPI_utils::field_from_json( Obj,"name",name);
RESTAPI_utils::field_from_json( Obj,"description",description);
field_from_json( Obj,"uuid",uuid);
field_from_json( Obj,"name",name);
field_from_json( Obj,"description",description);
return true;
} catch(...) {
@@ -408,14 +411,14 @@ namespace OpenWifi::ProvObjects {
}
void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "type", type);
RESTAPI_utils::field_to_json(Obj, "entries", entries);
field_to_json(Obj, "type", type);
field_to_json(Obj, "entries", entries);
}
bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"type",type);
RESTAPI_utils::field_from_json( Obj,"entries",entries);
field_from_json( Obj,"type",type);
field_from_json( Obj,"entries",entries);
return true;
} catch(...) {
@@ -424,12 +427,94 @@ namespace OpenWifi::ProvObjects {
}
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) {
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;
} catch(...) {
@@ -438,13 +523,47 @@ namespace OpenWifi::ProvObjects {
}
bool UpdateObjectInfo(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(O->has("description"))
if(I.name.empty())
return false;
if(O->has("description"))
I.description = O->get("description").toString();
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;
}
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 {
enum FIRMWARE_UPGRADE_RULES {
dont_upgrade,
upgrade_inherit,
upgrade_release_only,
upgrade_latest
};
struct ObjectInfo {
Types::UUID_t id;
std::string name;
@@ -317,7 +324,50 @@ namespace OpenWifi::ProvObjects {
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 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);
}
bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) {
bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"number",number);
field_from_json(Obj,"verified",verified);
@@ -155,7 +155,7 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"enabled",enabled);
field_from_json(Obj,"method",method);
@@ -171,7 +171,7 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"mobiles",mobiles);
field_from_json(Obj,"mfa",mfa);
@@ -189,7 +189,7 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"uuid",uuid);
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 {
field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"answer",answer);
@@ -387,11 +387,12 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"created",created);
field_from_json(Obj,"createdBy",createdBy);
field_from_json(Obj,"note",note);
return true;
} catch(...) {
}
@@ -428,10 +429,11 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"resource",resource);
field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
return true;
} catch(...) {
}
@@ -447,7 +449,7 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name);
@@ -455,6 +457,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"policy",policy);
field_from_json(Obj,"role",role);
field_from_json(Obj,"notes",notes);
return true;
} catch(...) {
}
@@ -465,13 +468,51 @@ namespace OpenWifi::SecurityObjects {
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 {
field_from_json(Obj,"profiles",profiles);
return true;
} catch(...) {
}
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
#include "Poco/JSON/Object.h"
#include "../framework/OpenWifiTypes.h"
#include "framework/OpenWifiTypes.h"
namespace OpenWifi::SecurityObjects {
@@ -53,7 +53,7 @@ namespace OpenWifi::SecurityObjects {
std::string createdBy;
std::string note;
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;
@@ -63,7 +63,7 @@ namespace OpenWifi::SecurityObjects {
bool primary;
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 {
@@ -71,7 +71,7 @@ namespace OpenWifi::SecurityObjects {
std::string method;
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 {
@@ -79,7 +79,7 @@ namespace OpenWifi::SecurityObjects {
struct MfaAuthInfo mfa;
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 {
@@ -89,7 +89,7 @@ namespace OpenWifi::SecurityObjects {
uint64_t created;
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 {
@@ -97,7 +97,7 @@ namespace OpenWifi::SecurityObjects {
std::string answer;
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 {
@@ -200,7 +200,7 @@ namespace OpenWifi::SecurityObjects {
std::string resource;
ResourceAccessType access;
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;
@@ -212,14 +212,37 @@ namespace OpenWifi::SecurityObjects {
std::string role;
NoteInfoVec notes;
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;
struct SecurityProfileList {
SecurityProfileVec profiles;
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"
namespace OpenWifi {
class SMSSender * SMSSender::instance_ = nullptr;
int SMSSender::Start() {
Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws");

View File

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

View File

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

View File

@@ -59,10 +59,8 @@ namespace OpenWifi {
class SMTPMailerService : public SubSystemServer, Poco::Runnable {
public:
static SMTPMailerService *instance() {
if (instance_ == nullptr) {
instance_ = new SMTPMailerService;
}
return instance_;
static SMTPMailerService instance;
return & instance;
}
struct MessageEvent {
@@ -88,7 +86,6 @@ namespace OpenWifi {
void reinitialize(Poco::Util::Application &self) override;
bool Enabled() const { return Enabled_; }
private:
static SMTPMailerService * instance_;
std::string MailHost_;
std::string Sender_;
int MailHostPort_=25;

View File

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

View File

@@ -15,34 +15,6 @@
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 {
};
@@ -90,7 +62,7 @@ namespace OpenWifi {
return UNKNOWN;
}
static const std::string from_userType(USER_TYPE U) {
static std::string from_userType(USER_TYPE U) {
switch(U) {
case ROOT: return "root";
case ADMIN: return "admin";
@@ -104,10 +76,8 @@ namespace OpenWifi {
}
static Storage *instance() {
if (instance_ == nullptr) {
instance_ = new Storage;
}
return instance_;
static Storage instance;
return &instance;
}
int Start() override;
@@ -116,7 +86,8 @@ namespace OpenWifi {
/*
* 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 GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id);
@@ -143,18 +114,20 @@ namespace OpenWifi {
/*
* 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 CompleteAction(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:
static Storage *instance_;
int Create_Tables();
int Create_UserTable();
int Create_AvatarTable();
int Create_TokensTable();
int Create_ActionLinkTable();
};
inline Storage * StorageService() { return Storage::instance(); };

View File

@@ -57,6 +57,7 @@ using namespace std::chrono_literals;
#include "Poco/URI.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/NetworkInterface.h"
#include "Poco/ExpireLRUCache.h"
#include "cppkafka/cppkafka.h"
@@ -66,6 +67,86 @@ using namespace std::chrono_literals;
#include "framework/RESTAPI_errors.h"
#include "framework/uCentral_Protocol.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 {
@@ -263,6 +344,21 @@ namespace OpenWifi::RESTAPI_utils {
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) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
@@ -345,6 +441,27 @@ namespace OpenWifi::RESTAPI_utils {
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) {
std::vector<T> Result;
if(ObjectString.empty())
@@ -729,16 +846,13 @@ namespace OpenWifi::Utils {
return Result;
}
inline void SaveSystemId(uint64_t Id);
[[nodiscard]] inline uint64_t InitializeSystemId() {
std::random_device RDev;
std::srand(RDev());
std::chrono::high_resolution_clock Clock;
auto Now = Clock.now().time_since_epoch().count();
auto S = (GetDefaultMacAsInt64() + std::rand() + Now) ;
SaveSystemId(S);
std::cout << "ID: " << S << std::endl;
OpenWifi::AppServiceRegistry().Set("systemid",S);
return S;
}
@@ -887,6 +1001,7 @@ namespace OpenWifi {
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
static const std::string uSERVICE_INSTALLER{ "owinst"};
class MyErrorHandler : public Poco::ErrorHandler {
public:
explicit MyErrorHandler(Poco::Util::Application &App) : App_(App) {}
@@ -1309,6 +1424,63 @@ namespace OpenWifi {
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 {
public:
struct QueryBlock {
@@ -1318,8 +1490,28 @@ namespace OpenWifi {
};
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)
: Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), Server_(Server), Internal_(Internal), AlwaysAuthorize_(AlwaysAuthorize) {}
struct RateLimit {
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) {
return true;
@@ -1331,6 +1523,9 @@ namespace OpenWifi {
Request = &RequestIn;
Response = &ResponseIn;
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls))
return;
if (!ContinueProcessing())
return;
@@ -1340,7 +1535,7 @@ namespace OpenWifi {
std::string Reason;
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
UnAuthorized(Reason);
UnAuthorized(Reason, ACCESS_DENIED);
return;
}
@@ -1561,10 +1756,10 @@ namespace OpenWifi {
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);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",403);
ErrorObject.set("ErrorCode",Code);
ErrorObject.set("ErrorDetails",Request->getMethod());
ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ;
std::ostream &Answer = Response->send();
@@ -1609,7 +1804,7 @@ namespace OpenWifi {
Response->set("Cache-Control", "private");
Response->set("Pragma", "private");
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();
Response->sendFile(File.path(),"application/octet-stream");
}
@@ -1647,10 +1842,10 @@ namespace OpenWifi {
const Types::StringPairVec & FormVars) {
Response->set("Pragma", "private");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->set("Content-Length", std::to_string(File.getSize()));
AddCORS();
auto FormContent = Utils::LoadFile(File.path());
std::string FormContent = Utils::LoadFile(File.path());
Utils::ReplaceVariables(FormContent, FormVars);
Response->setContentLength(FormContent.size());
AddCORS();
Response->setChunkedTransferEncoding(true);
Response->setContentType("text/html");
std::ostream& ostr = Response->send();
@@ -1760,12 +1955,14 @@ namespace OpenWifi {
std::vector<std::string> Methods_;
QueryBlock QB_;
bool Internal_=false;
bool RateLimited_=false;
bool QueryBlockInitialized_=false;
Poco::Net::HTTPServerRequest *Request= nullptr;
Poco::Net::HTTPServerResponse *Response= nullptr;
bool AlwaysAuthorize_=true;
Poco::JSON::Parser IncomingParser_;
RESTAPI_GenericServer & Server_;
RateLimit MyRates_;
};
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
@@ -1890,9 +2087,8 @@ namespace OpenWifi {
inline void initialize(Poco::Util::Application & self) override;
static KafkaManager *instance() {
if(instance_== nullptr)
instance_ = new KafkaManager;
return instance_;
static KafkaManager instance;
return &instance;
}
inline int Start() override {
@@ -1967,7 +2163,6 @@ namespace OpenWifi {
// void WakeUp();
private:
static KafkaManager *instance_;
std::mutex ProducerMutex_;
std::mutex ConsumerMutex_;
bool KafkaEnabled_ = false;
@@ -1995,7 +2190,6 @@ namespace OpenWifi {
};
inline KafkaManager * KafkaManager() { return KafkaManager::instance(); }
inline class KafkaManager *KafkaManager::instance_ = nullptr;
class AuthClient : public SubSystemServer {
public:
@@ -2005,10 +2199,8 @@ namespace OpenWifi {
}
static AuthClient *instance() {
if (instance_ == nullptr) {
instance_ = new AuthClient;
}
return instance_;
static AuthClient instance;
return &instance;
}
inline int Start() override {
@@ -2086,12 +2278,10 @@ namespace OpenWifi {
}
private:
static AuthClient *instance_;
OpenWifi::SecurityObjects::UserInfoCache UserCache_;
};
inline AuthClient * AuthClient() { return AuthClient::instance(); }
inline class AuthClient * AuthClient::instance_ = nullptr;
class ALBRequestHandler: public Poco::Net::HTTPRequestHandler
/// Return a HTML document with the current date and time.
@@ -2148,10 +2338,8 @@ namespace OpenWifi {
}
static ALBHealthCheckServer *instance() {
if (instance_ == nullptr) {
instance_ = new ALBHealthCheckServer;
}
return instance_;
static ALBHealthCheckServer instance;
return &instance;
}
inline int Start() override;
@@ -2162,14 +2350,12 @@ namespace OpenWifi {
}
private:
static ALBHealthCheckServer *instance_;
std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
int Port_ = 0;
};
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::Logger & L, RESTAPI_GenericServer & S);
@@ -2181,10 +2367,8 @@ namespace OpenWifi {
class RESTAPI_server : public SubSystemServer {
public:
static RESTAPI_server *instance() {
if (instance_ == nullptr) {
instance_ = new RESTAPI_server;
}
return instance_;
static RESTAPI_server instance;
return &instance;
}
int Start() override;
inline void Stop() override {
@@ -2202,7 +2386,6 @@ namespace OpenWifi {
}
private:
static RESTAPI_server *instance_;
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_;
@@ -2235,9 +2418,6 @@ namespace OpenWifi {
RESTAPI_GenericServer &Server_;
};
inline class RESTAPI_server *RESTAPI_server::instance_ = nullptr;
inline int RESTAPI_server::Start() {
Logger_.information("Starting.");
Server_.InitLogging();
@@ -2269,10 +2449,8 @@ namespace OpenWifi {
public:
static RESTAPI_InternalServer *instance() {
if (instance_ == nullptr) {
instance_ = new RESTAPI_InternalServer;
}
return instance_;
static RESTAPI_InternalServer instance;
return &instance;
}
inline int Start() override;
@@ -2290,7 +2468,6 @@ namespace OpenWifi {
return RESTAPI_internal_server(Path, Bindings, Logger_, Server_);
}
private:
static RESTAPI_InternalServer *instance_;
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_;
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(); };
class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
@@ -2357,6 +2532,8 @@ namespace OpenWifi {
uint64_t LastUpdate=0;
};
class SubSystemServer;
typedef std::map<uint64_t, MicroServiceMeta> MicroServiceMetaMap;
typedef std::vector<MicroServiceMeta> MicroServiceMetaVec;
@@ -2918,6 +3095,22 @@ namespace OpenWifi {
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) {
Logger_.notice("Initializing...");
auto i = 0;
@@ -3178,7 +3371,8 @@ namespace OpenWifi {
auto InsertResult = CertNames.insert(CertFileName);
if(InsertResult.second) {
Poco::JSON::Object Inner;
Inner.set("filename", CertFileName);
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn",ExpiresOn.timestamp().epochTime());
@@ -3477,7 +3671,7 @@ namespace OpenWifi {
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->getMethod(), Request->getURI()));
}
UnAuthorized();
UnAuthorized("Invalid token", INVALID_TOKEN);
}
return false;
}
@@ -3487,40 +3681,14 @@ namespace OpenWifi {
}
namespace OpenWifi::Utils {
inline void SaveSystemId(uint64_t Id) {
try {
std::ofstream O;
O.open(MicroService::instance().DataDir() + "/system.id",std::ios::binary | std::ios::trunc);
O << Id;
O.close();
} 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();
}
}
}
[[nodiscard]] inline uint64_t GetSystemId() {
uint64_t ID=0;
if(!AppServiceRegistry().Get("systemid",ID)) {
return InitializeSystemId();
}
return ID;
}
}
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 InvalidUserRole{"Invalid userRole."};
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 InvalidIPRanges{"Invalid IP range specifications."};
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 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

View File

@@ -103,8 +103,6 @@ namespace OpenWifi {
DBType dbType_ = sqlite;
};
// inline StorageClass * Storage() { return StorageClass::instance(); }
#ifdef SMALL_BUILD
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; }

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);
std::string St2{
"INSERT INTO Avatars (Id,Type,Created,Name,Avatar) VALUES(?,?,?,?,?)"};
std::string St2{"INSERT INTO Avatars (" + AllAvatarFieldsForSelect + ") VALUES( " + AllAvatarValuesForSelect + " )"};
Insert << ConvertParams(St2),
Poco::Data::Keywords::use(Id),
@@ -58,13 +57,19 @@ namespace OpenWifi {
Poco::Data::Session Sess = Pool_->get();
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);
std::string TId;
uint64_t Created;
Select2 << ConvertParams(St2),
Poco::Data::Keywords::into(L),
Poco::Data::Keywords::into(TId),
Poco::Data::Keywords::into(Type),
Poco::Data::Keywords::into(Created),
Poco::Data::Keywords::into(Name),
Poco::Data::Keywords::into(L),
Poco::Data::Keywords::use(Id);
Select2.execute();

View File

@@ -7,6 +7,33 @@
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 "storage_users.h"
#include "storage_avatar.h"
#include "storage_actionLinks.h"
#include "storage_tokens.h"
namespace OpenWifi {
@@ -12,6 +14,7 @@ namespace OpenWifi {
Create_UserTable();
Create_AvatarTable();
Create_TokensTable();
Create_ActionLinkTable();
return 0;
}
@@ -40,83 +43,51 @@ namespace OpenWifi {
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() {
try {
Poco::Data::Session Sess = Pool_->get();
if(dbType_==sqlite) {
Sess << "CREATE TABLE IF NOT EXISTS Avatars ("
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar BLOB"
Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_sqlite +
") ", Poco::Data::Keywords::now;
} else if(dbType_==mysql) {
Sess << "CREATE TABLE IF NOT EXISTS Avatars ("
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar LONGBLOB"
Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_mysql +
") ", Poco::Data::Keywords::now;
} else if(dbType_==pgsql) {
Sess << "CREATE TABLE IF NOT EXISTS Avatars ("
"Id VARCHAR(36) PRIMARY KEY, "
"Type VARCHAR, "
"Created BIGINT, "
"Name VARCHAR, "
"Avatar BYTEA"
Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_pgsql +
") ", Poco::Data::Keywords::now;
}
return 0;
} catch(const Poco::Exception &E) {
Logger_.log(E);
}
return 0;
return 1;
}
int Storage::Create_TokensTable() {
try {
Poco::Data::Session Sess = Pool_->get();
if(dbType_==sqlite) {
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 "
Sess << "CREATE TABLE IF NOT EXISTS Tokens (" +
AllTokensFieldsForCreation +
") ", 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;
} catch(const Poco::Exception &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 {
@@ -22,7 +23,7 @@ namespace OpenWifi {
uint64_t Z = 0;
std::string St2{
"INSERT INTO Tokens (Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate) VALUES(?,?,?,?,?,?,?,?)"};
"INSERT INTO Tokens (" + AllTokensFieldsForSelect + ") VALUES(" + AllTokensValuesForSelect + ")"};
Insert << ConvertParams(St2),
Poco::Data::Keywords::use(Token),
@@ -49,7 +50,7 @@ namespace OpenWifi {
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),
Poco::Data::Keywords::into(UInfo.webtoken.access_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;
}
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 {
Poco::Data::Session Sess = Pool_->get();
@@ -103,19 +131,23 @@ namespace OpenWifi {
if(!Records.empty())
return false;
NewUser.Id = MicroService::instance().CreateUUID();
NewUser.creationDate = std::time(nullptr);
if(!PasswordHashedAlready) {
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 no password, we will do email verification
if(NewUser.currentPassword.empty()) {
} else {
NewUser.currentPassword = AuthService()->ComputePasswordHash(NewUser.email,NewUser.currentPassword);
NewUser.lastPasswords.clear();
NewUser.lastPasswords.push_back(NewUser.currentPassword);
NewUser.lastPasswordChange = std::time(nullptr);
NewUser.validated = true;
if(!PasswordHashedAlready) {
NewUser.currentPassword = AuthService()->ComputeNewPasswordHash(NewUser.email,NewUser.currentPassword);
NewUser.lastPasswords.clear();
NewUser.lastPasswords.push_back(NewUser.currentPassword);
NewUser.lastPasswordChange = std::time(nullptr);
NewUser.validated = true;
}
}
auto Notes = RESTAPI_utils::to_string(NewUser.notes);

View File

@@ -105,20 +105,6 @@ namespace OpenWifi {
"oauthType=?, "
"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 <
std::string, // Id = 0;
std::string, // name;

View File

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

View File

@@ -29,9 +29,38 @@
opacity: 0.8;
}
.imgcontainer {
.img-container {
width: 100%;
margin-top: 5%;
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 {
@@ -48,6 +77,10 @@
padding-top: 16px;
}
body {
background-color: #ebedef;
}
/* Change styles for span and cancel button on extra small screens */
@media screen and (max-width: 300px) {
span.password1 {
@@ -62,17 +95,17 @@
</head>
<body>
<div class="imgcontainer">
<img src="open-wifi.svg" alt="OpenWifi">
<div class="img-container">
<img src="/wwwassets/the_logo.png" alt="OpenWifi">
</div>
<div>
<p>Site access rules:</p>
<ul>
<div class="info-card">
<h2 class="info-title">Site Access rules</h2>
<ul class="info-list">
<li>Must be a TIP Member.</li>
</ul>
</div>
</body>
</html>
</html>

View File

@@ -30,8 +30,10 @@
}
.imgcontainer {
width: 100%;
margin-top: 5%;
text-align: center;
margin: 24px 0 12px 0;
display: block;
}
img.avatar {
@@ -43,6 +45,37 @@
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;
@@ -60,16 +93,17 @@
}
</style>
</head>
<body>
<body class="body">
<div class="imgcontainer">
<img src="open-wifi.svg" alt="OpenWifi">
<img src="/wwwassets/the_logo.png" alt="OpenWifi">
</div>
<div>
<p>Password rules:</p>
<ul>
<li>Must be at least 8 characters long.</li>
<div class="info-card">
<h2 class="info-title">Password rules</h2>
<ul class="info-list">
<li>Must be at least 8 characters long</li>
<li>Must contain 1 uppercase letter</li>
<li>Must contain 1 lowercase letter</li>
<li>Must contain 1 digit</li>
@@ -78,5 +112,6 @@
</div>
</body>
</html>
</html>

View File

@@ -3,8 +3,15 @@
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {font-family: Arial, Helvetica, sans-serif;}
form {border: 3px solid #f1f1f1;}
body {
font-family: Arial,
Helvetica, sans-serif;
background-color: #ebedef;
}
.body {
background-color: #ebedef;
}
input[type=text], input[type=password] {
width: 90%;
@@ -31,15 +38,10 @@
}
.imgcontainer {
width: 100%;
margin-top: 5%;
text-align: center;
margin: 5px 0 5px 0;
grid-column-start: 2;
grid-column-end: 2;
}
.passwordlabel {
grid-column-start: 2;
grid-column-end: 2;
display: block;
}
img.avatar {
@@ -50,16 +52,22 @@
.grid-container {
display: grid;
grid-template-columns: 15% 70% 15%;
background-color: #f3db21;
grid-column-gap: 5px;
padding: 10px;
}
.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
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;
}
.passwordtext {
@@ -67,7 +75,13 @@
margin-left: 5%;
}
.password-input {
margin-top: 0px;
}
.rulestext {
width: 95%;
margin: auto;
display: inline-block;
text-align: left;
text-justify: none;
@@ -101,17 +115,18 @@
</head>
<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()">
<input type="hidden" id="custId" name="id" value="${UUID}">
<div class="grid-container">
<div class="imgcontainer">
<img src="/wwwassets/open-wifi.svg" alt="Logo" class="logo">
</div>
<h2>Reset Password</h2>
<div class="passwordlabel">
<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 class="passwordlabel">
<label class="passwordtext" for="password2"><b>Retype Password</b></label>

View File

@@ -1,11 +1,107 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Reset Password Failed</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
<body>
<h1>Password reset failed...</h1>
<body class="body">
<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>
<h3>ID</h3>
<b>${UUID}</b>
@@ -14,5 +110,7 @@
<h3>Error</h3>
<b>${ERROR_TEXT}</b>
</div>
</div>
</body>
</html>
</html>

View File

@@ -62,8 +62,9 @@
</head>
<body>
<div class="imgcontainer">
<img src="/wwwassets/avatar.jpg" alt="Avatar" class="avatar">
<img src="/wwwassets/the_logo.png" alt="Avatar" class="avatar">
</div>
<h1>Password was successfully reset</h1>
<div>
<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