Compare commits

..

3 Commits

Author SHA1 Message Date
Dmitry Dunaev
6a9b0f143e Chg: version of image to v2.3.0-RC2 2021-11-02 13:17:28 +03:00
Stephane Bourque
736d981853 Merge pull request #23 from Telecominfraproject/main
Fixing token generation.
2021-10-30 13:49:15 -07:00
Johann Hoffmann
9a27996d44 Update Helm values to v2.3.0-RC1
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2021-10-29 12:54:01 +03:00
64 changed files with 1055 additions and 5029 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(owsec VERSION 2.4.0) project(owsec VERSION 2.3.0)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@@ -30,20 +30,9 @@ else()
file(WRITE build ${BUILD_NUM}) file(WRITE build ${BUILD_NUM})
endif() endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
set(BUILD_SHARED_LIBS 1) set(BUILD_SHARED_LIBS 1)
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}")
add_definitions(-DTIP_SECURITY_SERVICE="1") add_definitions(-DTIP_SECURITY_SERVICE="1")
set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_STATIC_LIBS OFF)
@@ -53,7 +42,7 @@ find_package(Boost REQUIRED system)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(AWSSDK REQUIRED COMPONENTS sns) find_package(AWSSDK REQUIRED COMPONENTS sns)
find_package(nlohmann_json REQUIRED)
find_package(CppKafka REQUIRED) find_package(CppKafka REQUIRED)
find_package(PostgreSQL REQUIRED) find_package(PostgreSQL REQUIRED)
find_package(MySQL REQUIRED) find_package(MySQL REQUIRED)
@@ -61,11 +50,8 @@ find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataS
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include) include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_executable( owsec add_executable( owsec
build build
src/ow_version.h.in
src/framework/CountryCodes.h src/framework/CountryCodes.h
src/framework/KafkaTopics.h src/framework/KafkaTopics.h
src/framework/MicroService.h src/framework/MicroService.h
@@ -100,11 +86,7 @@ add_executable( owsec
src/MFAServer.cpp src/MFAServer.h src/MFAServer.cpp src/MFAServer.h
src/SMS_provider_aws.cpp src/SMS_provider_aws.h src/SMS_provider_aws.cpp src/SMS_provider_aws.h
src/SMS_provider.cpp src/SMS_provider.h src/SMS_provider.cpp src/SMS_provider.h
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h)
src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
src/storage/storage_tokens.h
src/ActionLinkManager.cpp src/ActionLinkManager.h
src/ACLProcessor.h)
if(NOT SMALL_BUILD) if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC target_link_libraries(owsec PUBLIC

View File

@@ -11,8 +11,6 @@ RUN apk add --update --no-cache \
RUN git clone https://github.com/stephb9959/poco /poco RUN git clone https://github.com/stephb9959/poco /poco
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
RUN git clone https://github.com/nlohmann/json /json
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
WORKDIR /aws-sdk-cpp WORKDIR /aws-sdk-cpp
@@ -39,26 +37,9 @@ RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install RUN cmake --build . --target install
WORKDIR /json
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
WORKDIR /json-schema-validator
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
ADD CMakeLists.txt build /owsec/ ADD CMakeLists.txt build /owsec/
ADD cmake /owsec/cmake ADD cmake /owsec/cmake
ADD src /owsec/src ADD src /owsec/src
ADD .git /owsec/.git
WORKDIR /owsec WORKDIR /owsec
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -78,7 +59,7 @@ RUN addgroup -S "$OWSEC_USER" && \
RUN mkdir /openwifi RUN mkdir /openwifi
RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl postgresql-client RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl
COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec
COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/ COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/
COPY --from=builder /poco/cmake-build/lib/* /lib/ COPY --from=builder /poco/cmake-build/lib/* /lib/
@@ -90,12 +71,10 @@ COPY owsec.properties.tmpl /
COPY wwwassets /dist/wwwassets COPY wwwassets /dist/wwwassets
COPY templates /dist/templates COPY templates /dist/templates
COPY docker-entrypoint.sh / COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh /
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
COPY readiness_check /readiness_check COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
EXPOSE 16001 17001 16101 EXPOSE 16001 17001 16101

View File

@@ -98,40 +98,6 @@ to get a sample. The default is
### `authentication.oldpasswords` ### `authentication.oldpasswords`
The number of older passwords to keep. Default is 5. The number of older passwords to keep. Default is 5.
### Changing default password
On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
```
export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
export OWSEC_DEFAULT_PASSWORD=weLoveWifi # default password __in cleartext__ from property 'authentication.default.password'
export OWSEC_NEW_PASSWORD=NewPass123% # new password that must be set for the user (must comply with 'authentication.validation.expression')
test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
```
CLI is also included in Docker image if you want to run it this way:
```
export OWSEC=openwifi.wlan.local:16001
#export FLAGS="-k"
export OWSEC_DEFAULT_USERNAME=root@system.com
export OWSEC_DEFAULT_PASSWORD=weLoveWifi
export OWSEC_NEW_PASSWORD=NewPass123%
docker run --rm -ti \
--network=host \
--env OWSEC \
--env FLAGS \
--env OWSEC_DEFAULT_USERNAME \
--env OWSEC_DEFAULT_PASSWORD \
--env OWSEC_NEW_PASSWORD \
tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:main \
/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
```
### Kafka integration ### Kafka integration
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure. in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.

2
build
View File

@@ -1 +1 @@
109 14

1
helm/.gitignore vendored
View File

@@ -1,2 +1 @@
*.swp *.swp
charts

View File

@@ -5,14 +5,14 @@ name: owsec
version: 0.1.0 version: 0.1.0
dependencies: dependencies:
- name: postgresql - name: postgresql
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ repository: https://charts.bitnami.com/bitnami
version: 10.9.2 version: 10.9.2
condition: postgresql.enabled condition: postgresql.enabled
- name: mysql - name: mysql
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ repository: https://charts.bitnami.com/bitnami
version: 8.8.3 version: 8.8.3
condition: mysql.enabled condition: mysql.enabled
- name: mariadb - name: mariadb
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ repository: https://charts.bitnami.com/bitnami
version: 9.4.2 version: 9.4.2
condition: mariadb.enabled condition: mariadb.enabled

View File

@@ -30,13 +30,3 @@ Create chart name and version as used by the chart label.
{{- define "owsec.chart" -}} {{- define "owsec.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}} {{- end -}}
{{- define "owsec.ingress.apiVersion" -}}
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}}
{{- print "networking.k8s.io/v1" -}}
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
{{- print "networking.k8s.io/v1beta1" -}}
{{- else -}}
{{- print "extensions/v1beta1" -}}
{{- end -}}
{{- end -}}

View File

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

View File

@@ -2,7 +2,7 @@
{{- range $ingress, $ingressValue := .Values.ingresses }} {{- range $ingress, $ingressValue := .Values.ingresses }}
{{- if $ingressValue.enabled }} {{- if $ingressValue.enabled }}
--- ---
apiVersion: {{ include "owsec.ingress.apiVersion" $root }} apiVersion: extensions/v1beta1
kind: Ingress kind: Ingress
metadata: metadata:
name: {{ include "owsec.fullname" $root }}-{{ $ingress }} name: {{ include "owsec.fullname" $root }}-{{ $ingress }}
@@ -36,25 +36,11 @@ spec:
paths: paths:
{{- range $ingressValue.paths }} {{- range $ingressValue.paths }}
- path: {{ .path }} - path: {{ .path }}
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
pathType: {{ .pathType | default "ImplementationSpecific" }}
{{- end }}
backend: backend:
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
service:
name: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
port:
{{- if kindIs "string" .servicePort }}
name: {{ .servicePort }}
{{- else }}
number: {{ .servicePort }}
{{- end }}
{{- else }}
serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }} serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
servicePort: {{ .servicePort }} servicePort: {{ .servicePort }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- end }}
{{- end }} {{- end }}

View File

@@ -8,7 +8,7 @@ fullnameOverride: ""
images: images:
owsec: owsec:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
tag: v2.4.0 tag: v2.3.0-RC2
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # registry: tip-tip-wlan-cloud-ucentral.jfrog.io
@@ -50,7 +50,6 @@ ingresses:
- restapi.chart-example.local - restapi.chart-example.local
paths: paths:
- path: / - path: /
pathType: ImplementationSpecific
serviceName: owsec serviceName: owsec
servicePort: restapi servicePort: restapi
@@ -96,8 +95,6 @@ tolerations: []
affinity: {} affinity: {}
podAnnotations: {}
persistence: persistence:
enabled: true enabled: true
# storageClassName: "-" # storageClassName: "-"

View File

@@ -51,18 +51,6 @@ components:
properties: properties:
ErrorCode: ErrorCode:
type: integer type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # expired token
- 10 # rate limit exceeded
ErrorDetails: ErrorDetails:
type: string type: string
ErrorDescription: ErrorDescription:

View File

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

View File

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

View File

@@ -1,68 +0,0 @@
//
// 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);
}
}
}
}
}

View File

@@ -1,41 +0,0 @@
//
// 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 auto * instance_ = new ActionLinkManager;
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,7 +11,6 @@
#include "Poco/Net/OAuth20Credentials.h" #include "Poco/Net/OAuth20Credentials.h"
#include "Poco/JWT/Token.h" #include "Poco/JWT/Token.h"
#include "Poco/JWT/Signer.h" #include "Poco/JWT/Signer.h"
#include "Poco/StringTokenizer.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "StorageService.h" #include "StorageService.h"
@@ -22,6 +21,7 @@
#include "MFAServer.h" #include "MFAServer.h"
namespace OpenWifi { namespace OpenWifi {
class AuthService *AuthService::instance_ = nullptr;
AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) { AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
switch (C) { switch (C) {
@@ -46,6 +46,10 @@ namespace OpenWifi {
Signer_.setRSAKey(MicroService::instance().Key()); Signer_.setRSAKey(MicroService::instance().Key());
Signer_.addAllAlgorithms(); Signer_.addAllAlgorithms();
Logger_.notice("Starting..."); Logger_.notice("Starting...");
Secure_ = MicroService::instance().ConfigGetBool("authentication.enabled",true);
DefaultPassword_ = MicroService::instance().ConfigGetString("authentication.default.password","");
DefaultUserName_ = MicroService::instance().ConfigGetString("authentication.default.username","");
Mechanism_ = MicroService::instance().ConfigGetString("authentication.service.type","internal");
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
@@ -56,67 +60,54 @@ namespace OpenWifi {
Logger_.notice("Stopping..."); Logger_.notice("Stopping...");
} }
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ) bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo )
{ {
if(!Secure_)
return true;
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
Expired = false;
try {
std::string CallToken; std::string CallToken;
try {
Poco::Net::OAuth20Credentials Auth(Request); Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") { if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken(); CallToken = Auth.getBearerToken();
} }
} catch(const Poco::Exception &E) {
}
if(!CallToken.empty()) { if(!CallToken.empty()) {
auto Client = UserCache_.get(CallToken); if(StorageService()->IsTokenRevoked(CallToken))
if( Client.isNull() ) {
SecurityObjects::UserInfoAndPolicy UInfo2;
uint64_t RevocationDate=0;
if(StorageService()->GetToken(CallToken,UInfo2,RevocationDate)) {
if(RevocationDate!=0)
return false; return false;
Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr); auto Client = UserCache_.find(CallToken);
if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) { if( Client == UserCache_.end() )
UInfo.webtoken = UInfo2.webtoken; return ValidateToken(CallToken, CallToken, UInfo);
UserCache_.update(CallToken, UInfo);
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken; SessionToken = CallToken;
UInfo = Client->second ;
return true; return true;
} }
} UserCache_.erase(CallToken);
return false; StorageService()->RevokeToken(CallToken);
}
if(!Expired) {
SessionToken = CallToken;
UInfo = *Client ;
return true;
}
RevokeToken(CallToken);
return false;
}
} catch(const Poco::Exception &E) {
Logger_.log(E);
}
return false; return false;
} }
void AuthService::RevokeToken(std::string & Token) { return false;
UserCache_.remove(Token);
StorageService()->RevokeToken(Token);
} }
bool AuthService::DeleteUserFromCache(const std::string &UserName) { bool AuthService::DeleteUserFromCache(const std::string &UserName) {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
std::vector<std::string> OldTokens; for(auto i=UserCache_.begin();i!=UserCache_.end();) {
if (i->second.userinfo.email==UserName) {
UserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void Logout(i->first, false);
{ if(O.userinfo.email==UserName) i = UserCache_.erase(i);
OldTokens.push_back(token); } else {
}); ++i;
}
for(const auto &i:OldTokens) {
Logout(i,false);
UserCache_.remove(i);
} }
return true; return true;
} }
@@ -132,6 +123,9 @@ namespace OpenWifi {
void AuthService::Logout(const std::string &token, bool EraseFromCache) { void AuthService::Logout(const std::string &token, bool EraseFromCache) {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
if(EraseFromCache)
UserCache_.erase(token);
try { try {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
Obj.set("event", "remove-token"); Obj.set("event", "remove-token");
@@ -140,7 +134,7 @@ namespace OpenWifi {
std::stringstream ResultText; std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText); Poco::JSON::Stringifier::stringify(Obj, ResultText);
std::string Tmp{token}; std::string Tmp{token};
RevokeToken(Tmp); StorageService()->RevokeToken(Tmp);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(), KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(),
false); false);
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
@@ -174,6 +168,28 @@ namespace OpenWifi {
return JWT; return JWT;
} }
bool AuthService::ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
std::lock_guard Guard(Mutex_);
try {
auto E = UserCache_.find(SessionToken);
if(E == UserCache_.end()) {
if(StorageService()->GetToken(SessionToken,UInfo)) {
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
} else {
UInfo = E->second;
return true;
}
} catch (const Poco::Exception &E ) {
Logger_.log(E);
}
return false;
}
void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
@@ -191,88 +207,43 @@ namespace OpenWifi {
UInfo.webtoken.username_ = UserName; UInfo.webtoken.username_ = UserName;
UInfo.webtoken.errorCode = 0; UInfo.webtoken.errorCode = 0;
UInfo.webtoken.userMustChangePassword = false; UInfo.webtoken.userMustChangePassword = false;
UserCache_.update(UInfo.webtoken.access_token_,UInfo); UserCache_[UInfo.webtoken.access_token_] = UInfo;
StorageService()->SetLastLogin(UInfo.userinfo.Id); StorageService()->SetLastLogin(UInfo.userinfo.Id);
StorageService()->AddToken(UInfo.userinfo.Id, UInfo.webtoken.access_token_, StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_,
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
} }
bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
std::lock_guard G(Mutex_); auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword);
for (auto const &i:UInfo.lastPasswords) {
Poco::toLowerInPlace(UInfo.email); if (i == NewPasswordHash) {
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; return false;
} }
} }
} else {
SHA2_.update(NewPassword+UInfo.email);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
if(UInfo.lastPasswords.size()==HowManyOldPassword_) { if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
} }
UInfo.lastPasswords.push_back(NewPasswordHash);
auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword); UInfo.currentPassword = NewPasswordHash;
UInfo.lastPasswords.push_back(NewHash);
UInfo.currentPassword = NewHash;
UInfo.changePassword = false; UInfo.changePassword = false;
return true; return true;
} }
static std::string GetMeSomeSalt() { AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
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 , bool & Expired )
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
SecurityObjects::AclTemplate ACL;
Poco::toLowerInPlace(UserName); Poco::toLowerInPlace(UserName);
auto PasswordHash = ComputePasswordHash(UserName, Password);
if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) { if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION; return USERNAME_PENDING_VERIFICATION;
} }
if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) { if(PasswordHash != UInfo.userinfo.currentPassword) {
return INVALID_CREDENTIALS; return INVALID_CREDENTIALS;
} }
@@ -299,35 +270,54 @@ namespace OpenWifi {
UInfo.userinfo.lastLogin=std::time(nullptr); UInfo.userinfo.lastLogin=std::time(nullptr);
StorageService()->SetLastLogin(UInfo.userinfo.Id); StorageService()->SetLastLogin(UInfo.userinfo.Id);
CreateToken(UserName, UInfo ); CreateToken(UserName, UInfo );
return SUCCESS; return SUCCESS;
} }
if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_)
{
ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
UInfo.webtoken.acl_template_ = ACL;
UInfo.userinfo.email = DefaultUserName_;
UInfo.userinfo.currentPassword = DefaultPassword_;
UInfo.userinfo.name = DefaultUserName_;
UInfo.userinfo.userRole = SecurityObjects::ROOT;
CreateToken(UserName, UInfo );
return SUCCESS;
}
return INVALID_CREDENTIALS; return INVALID_CREDENTIALS;
} }
bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { 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) {
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(StorageService()->GetUserByEmail(Email,UInfo)) { if(StorageService()->GetUserByEmail(Email,UInfo)) {
switch (Reason) { switch (Reason) {
case FORGOT_PASSWORD: { case FORGOT_PASSWORD: {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI(); Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "Password reset link"; Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
} }
break; break;
case EMAIL_VERIFICATION: { case EMAIL_VERIFICATION: {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI(); Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "EMail Address Verification"; Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true; UInfo.waitingForEmailCheck = true;
} }
@@ -336,57 +326,33 @@ namespace OpenWifi {
default: default:
break; break;
} }
return true;
} }
return false; return false;
} }
bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
SecurityObjects::ActionLink A; MessageAttributes Attrs;
A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; Attrs[RECIPIENT_EMAIL] = UInfo.email;
A.userId = UInfo.email; Attrs[LOGO] = "logo.jpg";
A.id = MicroService::CreateUUID(); Attrs[SUBJECT] = "EMail Address Verification";
A.created = std::time(nullptr); Attrs[ACTION_LINK] =
A.expires = A.created + 24*60*60; MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
StorageService()->CreateAction(A); SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true; UInfo.waitingForEmailCheck = true;
return true; return true;
} }
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) { bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
auto It = UserCache_.find(Token);
Expired = false; if(It==UserCache_.end())
return false;
auto Client = UserCache_.get(Token); WebToken = It->second.webtoken;
if(!Client.isNull()) { UserInfo = It->second.userinfo;
Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr);
WebToken = Client->webtoken;
UserInfo = Client->userinfo;
return true; return true;
} }
std::string TToken{Token};
if(StorageService()->IsTokenRevoked(TToken)) {
return false;
}
// get the token from disk...
SecurityObjects::UserInfoAndPolicy UInfo;
uint64_t RevocationDate=0;
if(StorageService()->GetToken(TToken, UInfo, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (UInfo.webtoken.created_ + UInfo.webtoken.expires_in_) < std::time(nullptr);
if(StorageService()->GetUserById(UInfo.userinfo.Id,UInfo.userinfo)) {
WebToken = UInfo.webtoken;
UserCache_.update(UInfo.webtoken.access_token_, UInfo);
return true;
}
}
return false;
}
} // end of namespace } // end of namespace

View File

@@ -18,7 +18,6 @@
#include "Poco/SHA2Engine.h" #include "Poco/SHA2Engine.h"
#include "Poco/Crypto/DigestEngine.h" #include "Poco/Crypto/DigestEngine.h"
#include "Poco/HMACEngine.h" #include "Poco/HMACEngine.h"
#include "Poco/ExpireLRUCache.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
@@ -36,6 +35,16 @@ namespace OpenWifi{
CUSTOM CUSTOM
}; };
enum AUTH_ERROR {
SUCCESS,
PASSWORD_CHANGE_REQUIRED,
INVALID_CREDENTIALS,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR
};
enum EMAIL_REASON { enum EMAIL_REASON {
FORGOT_PASSWORD, FORGOT_PASSWORD,
EMAIL_VERIFICATION EMAIL_VERIFICATION
@@ -45,51 +54,48 @@ namespace OpenWifi{
static int AccessTypeToInt(ACCESS_TYPE T); static int AccessTypeToInt(ACCESS_TYPE T);
static AuthService *instance() { static AuthService *instance() {
static auto * instance_ = new AuthService; if (instance_ == nullptr) {
instance_ = new AuthService;
}
return instance_; return instance_;
} }
int Start() override; int Start() override;
void Stop() override; void Stop() override;
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired); [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
[[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); [[nodiscard]] AUTH_ERROR Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo );
void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo );
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
void Logout(const std::string &token, bool EraseFromCache=true); void Logout(const std::string &token, bool EraseFromCache=true);
bool ValidatePassword(const std::string &pwd); bool ValidatePassword(const std::string &pwd);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired); [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo);
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
[[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::WebToken & UserInfo );
[[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password); [[nodiscard]] std::string ComputePasswordHash(const std::string &UserName, const std::string &Password);
[[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
[[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
[[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); [[nodiscard]] static bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason);
[[nodiscard]] bool DeleteUserFromCache(const std::string &UserName); [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
void RevokeToken(std::string & Token);
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
}
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
}
private: private:
static AuthService *instance_;
bool Secure_ = false ;
std::string DefaultUserName_;
std::string DefaultPassword_;
std::string Mechanism_;
Poco::JWT::Signer Signer_; Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_; Poco::SHA2Engine SHA2_;
Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy> UserCache_{2048,1200000}; SecurityObjects::UserInfoCache UserCache_;
// SecurityObjects::UserInfoCache UserCache_;
std::string PasswordValidationStr_; std::string PasswordValidationStr_;
std::regex PasswordValidation_; std::regex PasswordValidation_;
uint64_t TokenAging_ = 30 * 24 * 60 * 60; uint64_t TokenAging_ = 30 * 24 * 60 * 60;
@@ -121,8 +127,8 @@ namespace OpenWifi{
inline AuthService * AuthService() { return AuthService::instance(); } inline AuthService * AuthService() { return AuthService::instance(); }
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired) { [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired ); return AuthService()->IsAuthorized(Request, SessionToken, UInfo );
} }
} // end of namespace } // end of namespace

View File

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

View File

@@ -6,10 +6,11 @@
#include "SMSSender.h" #include "SMSSender.h"
#include "SMTPMailerService.h" #include "SMTPMailerService.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "AuthService.h"
namespace OpenWifi { namespace OpenWifi {
class MFAServer * MFAServer::instance_ = nullptr;
int MFAServer::Start() { int MFAServer::Start() {
return 0; return 0;
} }
@@ -26,7 +27,7 @@ namespace OpenWifi {
return false; return false;
std::string Challenge = MakeChallenge(); std::string Challenge = MakeChallenge();
std::string uuid = MicroService::CreateUUID(); std::string uuid = MicroService::instance().CreateUUID();
uint64_t Created = std::time(nullptr); uint64_t Created = std::time(nullptr);
ChallengeStart.set("uuid",uuid); ChallengeStart.set("uuid",uuid);
@@ -46,7 +47,7 @@ namespace OpenWifi {
if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
Attrs[LOGO] = AuthService::GetLogoAssetURI(); Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "Login validation code"; Attrs[SUBJECT] = "Login validation code";
Attrs[CHALLENGE_CODE] = Challenge; Attrs[CHALLENGE_CODE] = Challenge;
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
@@ -71,9 +72,8 @@ namespace OpenWifi {
auto uuid = ChallengeResponse->get("uuid").toString(); auto uuid = ChallengeResponse->get("uuid").toString();
auto Hint = Cache_.find(uuid); auto Hint = Cache_.find(uuid);
if(Hint == end(Cache_)) { if(Hint == end(Cache_))
return false; return false;
}
auto answer = ChallengeResponse->get("answer").toString(); auto answer = ChallengeResponse->get("answer").toString();
if(Hint->second.Answer!=answer) { if(Hint->second.Answer!=answer) {

View File

@@ -24,21 +24,24 @@ namespace OpenWifi {
int Start() override; int Start() override;
void Stop() override; void Stop() override;
static MFAServer *instance() { static MFAServer *instance() {
static auto * instance_ = new MFAServer; if (instance_ == nullptr) {
instance_ = new MFAServer;
}
return instance_; return instance_;
} }
bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
static bool MethodEnabled(const std::string &Method); bool MethodEnabled(const std::string &Method);
bool ResendCode(const std::string &uuid); bool ResendCode(const std::string &uuid);
static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
static inline std::string MakeChallenge() { static inline std::string MakeChallenge() {
return std::to_string(MicroService::instance().Random(1,999999)); return std::to_string(rand() % 999999);
} }
private: private:
static MFAServer * instance_;
MFAChallengeCache Cache_; MFAChallengeCache Cache_;
MFAServer() noexcept: MFAServer() noexcept:
SubSystemServer("MFServer", "MFA-SVR", "mfa") SubSystemServer("MFServer", "MFA-SVR", "mfa")

View File

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

View File

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

View File

@@ -14,41 +14,25 @@
#include "MFAServer.h" #include "MFAServer.h"
#include "framework/RESTAPI_protocol.h" #include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "StorageService.h"
namespace OpenWifi { namespace OpenWifi {
static void FilterCredentials(SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
void RESTAPI_oauth2Handler::DoGet() { void RESTAPI_oauth2Handler::DoGet() {
bool Expired = false; if (!IsAuthorized()) {
if (!IsAuthorized(Expired)) { return UnAuthorized("Not authorized.");
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
} }
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
if(GetMe) { if(GetMe) {
Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
Poco::JSON::Object Me; Poco::JSON::Object Me;
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo; UserInfo_.userinfo.to_json(Me);
FilterCredentials(ReturnedUser);
ReturnedUser.to_json(Me);
return ReturnObject(Me); return ReturnObject(Me);
} }
BadRequest(RESTAPI::Errors::UnrecognizedRequest); BadRequest("Ill-formed request. Please consult documentation.");
} }
void RESTAPI_oauth2Handler::DoDelete() { void RESTAPI_oauth2Handler::DoDelete() {
bool Expired = false; if (!IsAuthorized()) {
if (!IsAuthorized(Expired)) { return UnAuthorized("Not authorized.");
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
} }
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
@@ -79,31 +63,15 @@ namespace OpenWifi {
} }
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
SecurityObjects::UserInfo UInfo1; // Send an email to the userId
auto UserExists = StorageService()->GetUserByEmail(userId,UInfo1);
if(UserExists) {
Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); 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::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; 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; UInfo.webtoken.userMustChangePassword=true;
Poco::JSON::Object ReturnObj;
UInfo.webtoken.to_json(ReturnObj); UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} else {
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
} }
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) {
@@ -112,8 +80,9 @@ namespace OpenWifi {
auto uuid = Obj->get("uuid").toString(); auto uuid = Obj->get("uuid").toString();
if(MFAServer().ResendCode(uuid)) if(MFAServer().ResendCode(uuid))
return OK(); return OK();
return UnAuthorized("Unrecognized credentials (username/password).");
} }
return UnAuthorized(RESTAPI::Errors::InvalidCredentials); return UnAuthorized("Unrecognized credentials (username/password).");
} }
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
@@ -126,37 +95,29 @@ namespace OpenWifi {
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} }
} }
return UnAuthorized(RESTAPI::Errors::InvalidCredentials); return UnAuthorized("Unrecognized credentials (username/password).");
} }
SecurityObjects::UserInfoAndPolicy UInfo; SecurityObjects::UserInfoAndPolicy UInfo;
bool Expired=false; auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired); if (Code==AuthService::SUCCESS) {
if (Code==SUCCESS) {
Poco::JSON::Object ReturnObj; Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) { if(AuthService()->RequiresMFA(UInfo)) {
if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) { if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} }
Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); Logger_.warning("MFA Seems ot be broken. Please fix. Disabling MFA checking for now.");
} }
UInfo.webtoken.to_json(ReturnObj); UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj); return ReturnObject(ReturnObj);
} else { } else {
switch(Code) { switch(Code) {
case INVALID_CREDENTIALS: case AuthService::INVALID_CREDENTIALS: return UnAuthorized("Unrecognized credentials (username/password)."); break;
return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); case AuthService::PASSWORD_INVALID: return UnAuthorized("Invalid password."); break;
case PASSWORD_INVALID: case AuthService::PASSWORD_ALREADY_USED: return UnAuthorized("Password already used previously."); break;
return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); case AuthService::USERNAME_PENDING_VERIFICATION: return UnAuthorized("User access pending email verification."); break;
case PASSWORD_ALREADY_USED: case AuthService::PASSWORD_CHANGE_REQUIRED: return UnAuthorized("Password change expected."); break;
return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); default: return UnAuthorized("Unrecognized credentials (username/password)."); break;
case USERNAME_PENDING_VERIFICATION:
return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code);
case PASSWORD_CHANGE_REQUIRED:
return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code);
default:
return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break;
} }
return; return;
} }

View File

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

View File

@@ -7,16 +7,8 @@
#include "Poco/JSON/Parser.h" #include "Poco/JSON/Parser.h"
#include "framework/RESTAPI_errors.h" #include "framework/RESTAPI_errors.h"
#include "SMSSender.h" #include "SMSSender.h"
#include "ACLProcessor.h"
namespace OpenWifi { namespace OpenWifi {
static void FilterCredentials(SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
void RESTAPI_user_handler::DoGet() { void RESTAPI_user_handler::DoGet() {
std::string Id = GetBinding("id", ""); std::string Id = GetBinding("id", "");
if(Id.empty()) { if(Id.empty()) {
@@ -33,9 +25,7 @@ namespace OpenWifi {
} else if(!StorageService()->GetUserById(Id,UInfo)) { } else if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound(); return NotFound();
} }
Poco::JSON::Object UserInfoObject; Poco::JSON::Object UserInfoObject;
FilterCredentials(UInfo);
UInfo.to_json(UserInfoObject); UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject); ReturnObject(UserInfoObject);
} }
@@ -51,20 +41,12 @@ namespace OpenWifi {
return NotFound(); return NotFound();
} }
if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
return NotFound(); return NotFound();
} }
if(AuthService()->DeleteUserFromCache(UInfo.email)) { if(AuthService()->DeleteUserFromCache(UInfo.email))
// nothing to do ;
}
StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id);
Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
StorageService()->RevokeAllTokens(UInfo.email); StorageService()->RevokeAllTokens(UInfo.email);
Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
@@ -77,52 +59,49 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::IdMustBe0); return BadRequest(RESTAPI::Errors::IdMustBe0);
} }
SecurityObjects::UserInfo NewUser; SecurityObjects::UserInfo UInfo;
RESTAPI_utils::from_request(NewUser,*Request); RESTAPI_utils::from_request(UInfo,*Request);
if(NewUser.userRole == SecurityObjects::UNKNOWN) { if(UInfo.userRole == SecurityObjects::UNKNOWN) {
return BadRequest(RESTAPI::Errors::InvalidUserRole); return BadRequest(RESTAPI::Errors::InvalidUserRole);
} }
if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { Poco::toLowerInPlace(UInfo.email);
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); if(!Utils::ValidEMailAddress(UInfo.email)) {
}
Poco::toLowerInPlace(NewUser.email);
if(!Utils::ValidEMailAddress(NewUser.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress); return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
} }
if(!NewUser.currentPassword.empty()) { if(!UInfo.currentPassword.empty()) {
if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { if(!AuthService()->ValidatePassword(UInfo.currentPassword)) {
return BadRequest(RESTAPI::Errors::InvalidPassword); return BadRequest(RESTAPI::Errors::InvalidPassword);
} }
} }
if(NewUser.name.empty()) if(UInfo.name.empty())
NewUser.name = NewUser.email; UInfo.name = UInfo.email;
if(!StorageService()->CreateUser(NewUser.email,NewUser)) { if(!StorageService()->CreateUser(UInfo.email,UInfo)) {
Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email)); Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email));
return BadRequest(RESTAPI::Errors::RecordNotCreated); return BadRequest(RESTAPI::Errors::RecordNotCreated);
} }
if(GetParameter("email_verification","false")=="true") { if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifyEmail(NewUser)) if(AuthService::VerifyEmail(UInfo))
Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email)); Logger_.information(Poco::format("Verification e-mail requested for %s",UInfo.email));
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser); StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UInfo.Id,UInfo);
} }
if(!StorageService()->GetUserByEmail(NewUser.email, NewUser)) { if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) {
Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email)); Logger_.information(Poco::format("User '%s' but not retrieved.",UInfo.email));
return NotFound(); return NotFound();
} }
Poco::JSON::Object UserInfoObject; Poco::JSON::Object UserInfoObject;
FilterCredentials(NewUser); UInfo.to_json(UserInfoObject);
NewUser.to_json(UserInfoObject);
ReturnObject(UserInfoObject); ReturnObject(UserInfoObject);
Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email));
Logger_.information(Poco::format("User '%s' has been added by '%s')",UInfo.email, UserInfo_.userinfo.email));
} }
void RESTAPI_user_handler::DoPut() { void RESTAPI_user_handler::DoPut() {
@@ -136,10 +115,6 @@ namespace OpenWifi {
return NotFound(); return NotFound();
} }
if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
SecurityObjects::UserInfo NewUser; SecurityObjects::UserInfo NewUser;
auto RawObject = ParseStream(); auto RawObject = ParseStream();
if(!NewUser.from_json(RawObject)) { if(!NewUser.from_json(RawObject)) {
@@ -161,19 +136,8 @@ namespace OpenWifi {
AssignIfPresent(RawObject,"suspended", Existing.suspended); AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed); AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole")) { if(RawObject->has("userRole"))
auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(NewRole!=Existing.userRole) {
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(Id==UserInfo_.userinfo.Id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Existing.userRole = NewRole;
}
}
if(RawObject->has("notes")) { if(RawObject->has("notes")) {
SecurityObjects::NoteInfoVec NIV; SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
@@ -197,34 +161,26 @@ namespace OpenWifi {
} }
if(RawObject->has("userTypeProprietaryInfo")) { if(RawObject->has("userTypeProprietaryInfo")) {
bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled;
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") {
auto PropInfo = RawObject->get("userTypeProprietaryInfo"); Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); auto MobileStruct = RawObject->get("userTypeProprietaryInfo");
auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>();
if(PInfo->isArray("mobiles")) { if(Info->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
} }
if(!NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
return BadRequest(RESTAPI::Errors::NeedMobileNumber); return BadRequest(RESTAPI::Errors::NeedMobileNumber);
} }
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) {
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber); return BadRequest(RESTAPI::Errors::NeedMobileNumber);
} }
} else if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) {
if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) {
return BadRequest("Unknown MFA method");
}
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method; Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
} else {
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest(RESTAPI::Errors::BadMFAMethod);
} }
if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest("Illegal MFA method");
} }
} }
@@ -232,7 +188,6 @@ namespace OpenWifi {
SecurityObjects::UserInfo NewUserInfo; SecurityObjects::UserInfo NewUserInfo;
StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject; Poco::JSON::Object ModifiedObject;
FilterCredentials(NewUserInfo);
NewUserInfo.to_json(ModifiedObject); NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject); return ReturnObject(ModifiedObject);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -138,7 +138,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"primary", primary); field_to_json(Obj,"primary", primary);
} }
bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) { bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"number",number); field_from_json(Obj,"number",number);
field_from_json(Obj,"verified",verified); field_from_json(Obj,"verified",verified);
@@ -155,7 +155,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"method", method); field_to_json(Obj,"method", method);
} }
bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) { bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"enabled",enabled); field_from_json(Obj,"enabled",enabled);
field_from_json(Obj,"method",method); field_from_json(Obj,"method",method);
@@ -171,7 +171,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "mfa", mfa); field_to_json(Obj, "mfa", mfa);
} }
bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"mobiles",mobiles); field_from_json(Obj,"mobiles",mobiles);
field_from_json(Obj,"mfa",mfa); field_from_json(Obj,"mfa",mfa);
@@ -189,7 +189,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "method", method); field_to_json(Obj, "method", method);
} }
bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) { bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"question",question); field_from_json(Obj,"question",question);
@@ -208,7 +208,7 @@ namespace OpenWifi::SecurityObjects {
} }
bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) { bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"answer",answer); field_from_json(Obj,"answer",answer);
@@ -387,12 +387,11 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"note", note); field_to_json(Obj,"note", note);
} }
bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) { bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"created",created); field_from_json(Obj,"created",created);
field_from_json(Obj,"createdBy",createdBy); field_from_json(Obj,"createdBy",createdBy);
field_from_json(Obj,"note",note); field_from_json(Obj,"note",note);
return true;
} catch(...) { } catch(...) {
} }
@@ -429,11 +428,10 @@ namespace OpenWifi::SecurityObjects {
field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
} }
bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) { bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"resource",resource); field_from_json(Obj,"resource",resource);
field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
return true;
} catch(...) { } catch(...) {
} }
@@ -449,7 +447,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"notes", notes); field_to_json(Obj,"notes", notes);
} }
bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) { bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"id",id); field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name); field_from_json(Obj,"name",name);
@@ -457,7 +455,6 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"policy",policy); field_from_json(Obj,"policy",policy);
field_from_json(Obj,"role",role); field_from_json(Obj,"role",role);
field_from_json(Obj,"notes",notes); field_from_json(Obj,"notes",notes);
return true;
} catch(...) { } catch(...) {
} }
@@ -468,47 +465,9 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "profiles", profiles); field_to_json(Obj, "profiles", profiles);
} }
bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) { bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) {
try { try {
field_from_json(Obj,"profiles",profiles); field_from_json(Obj,"profiles",profiles);
return true;
} catch(...) {
}
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(...) { } catch(...) {
} }

View File

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

View File

@@ -14,18 +14,16 @@
#include "framework/MicroService.h" #include "framework/MicroService.h"
namespace OpenWifi { namespace OpenWifi {
class SMSSender * SMSSender::instance_ = nullptr;
int SMSSender::Start() { int SMSSender::Start() {
Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false); Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws");
if(Enabled_) {
Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws");
if(Provider_=="aws") { if(Provider_=="aws") {
ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_);
} else if(Provider_=="twilio") { } else if(Provider_=="twilio") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
} }
Enabled_ = ProviderImpl_->Initialize(); Enabled_ = ProviderImpl_->Initialize();
}
return 0; return 0;
} }

View File

@@ -18,14 +18,16 @@ namespace OpenWifi {
std::string Number; std::string Number;
std::string Code; std::string Code;
std::string UserName; std::string UserName;
uint64_t Created = std::time(nullptr); uint64_t Created;
bool Validated=false; bool Validated=false;
}; };
class SMSSender : public SubSystemServer { class SMSSender : public SubSystemServer {
public: public:
static SMSSender *instance() { static SMSSender *instance() {
static auto *instance_ = new SMSSender; if (instance_ == nullptr) {
instance_ = new SMSSender;
}
return instance_; return instance_;
} }
@@ -37,6 +39,7 @@ namespace OpenWifi {
bool IsNumberValid(const std::string &Number, const std::string &UserName); bool IsNumberValid(const std::string &Number, const std::string &UserName);
[[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message); [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message);
private: private:
static SMSSender * instance_;
std::string Provider_; std::string Provider_;
bool Enabled_=false; bool Enabled_=false;
std::vector<SMSValidationCacheEntry> Cache_; std::vector<SMSValidationCacheEntry> Cache_;

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,10 +13,36 @@
#include "framework/StorageClass.h" #include "framework/StorageClass.h"
#include "AuthService.h" #include "AuthService.h"
#include "Poco/Timer.h"
namespace OpenWifi { namespace OpenWifi {
static const std::string AllActionLinksFieldsForSelect {
"Id, "
"Action,"
"UserId,"
"template,"
"locale,"
"message,"
"sent,"
"created,"
"expires,"
"completed,"
"canceled"
};
static const std::string AllActionLinksFieldsForUpdate {
"Id=?, "
"Action=?,"
"UserId=?,"
"template=?,"
"locale=?,"
"message=?,"
"sent=?,"
"created=?,"
"expires=?,"
"completed=?,"
"canceled=?"
};
static const std::string AllEmailTemplatesFieldsForCreation { static const std::string AllEmailTemplatesFieldsForCreation {
}; };
@@ -29,12 +55,6 @@ namespace OpenWifi {
}; };
class Archiver {
public:
void onTimer(Poco::Timer & timer);
private:
};
class Storage : public StorageClass { class Storage : public StorageClass {
public: public:
@@ -70,7 +90,7 @@ namespace OpenWifi {
return UNKNOWN; return UNKNOWN;
} }
static std::string from_userType(USER_TYPE U) { static const std::string from_userType(USER_TYPE U) {
switch(U) { switch(U) {
case ROOT: return "root"; case ROOT: return "root";
case ADMIN: return "admin"; case ADMIN: return "admin";
@@ -84,7 +104,9 @@ namespace OpenWifi {
} }
static Storage *instance() { static Storage *instance() {
static auto * instance_ = new Storage; if (instance_ == nullptr) {
instance_ = new Storage;
}
return instance_; return instance_;
} }
@@ -94,8 +116,7 @@ namespace OpenWifi {
/* /*
* All user management functions * All user management functions
*/ */
bool InitializeDefaultUser(); bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser);
bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false);
bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id);
@@ -112,38 +133,28 @@ namespace OpenWifi {
bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name);
bool DeleteAvatar(const std::string & Admin, std::string &Id); bool DeleteAvatar(const std::string & Admin, std::string &Id);
bool AddToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut); bool AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut);
bool RevokeToken( std::string & Token ); bool RevokeToken( std::string & Token );
bool IsTokenRevoked( std::string & Token ); bool IsTokenRevoked( std::string & Token );
bool CleanExpiredTokens(); bool CleanRevokedTokens( uint64_t Oldest );
bool RevokeAllTokens( std::string & UserName ); bool RevokeAllTokens( std::string & UserName );
bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate); bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo);
/* /*
* All ActionLinks functions * All ActionLinks functions
*/ */
bool CreateAction( SecurityObjects::ActionLink & A); bool CreateAction(std::string &ActionId, std::string &Action, USER_ID_TYPE & Id, Types::StringPairVec & Elements );
bool DeleteAction(std::string &ActionId); bool DeleteAction(std::string &ActionId);
bool CompleteAction(std::string &ActionId); bool CompleteAction(std::string &ActionId);
bool CancelAction(std::string &ActionId); bool CancelAction(std::string &ActionId);
bool SentAction(std::string &ActionId);
bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A);
bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200);
void CleanOldActionLinks();
private: private:
static Storage *instance_;
int Create_Tables(); int Create_Tables();
int Create_UserTable(); int Create_UserTable();
int Create_AvatarTable(); int Create_AvatarTable();
int Create_TokensTable(); int Create_TokensTable();
int Create_ActionLinkTable();
Poco::Timer Timer_;
Archiver Archiver_;
std::unique_ptr<Poco::TimerCallback<Archiver>> Archivercallback_;
/// This is to support a mistake that was deployed...
void ReplaceOldDefaultUUID();
}; };
inline Storage * StorageService() { return Storage::instance(); }; inline Storage * StorageService() { return Storage::instance(); };

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -1,201 +0,0 @@
//
// 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;
}
void Storage::CleanOldActionLinks() {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
uint64_t CutOff = std::time(nullptr) - (30 * 24 * 60 * 60);
std::string St{"DELETE from ActionLinks where Created<=?"};
Delete << ConvertParams(St),
Poco::Data::Keywords::use(CutOff);
Delete.execute();
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,30 +0,0 @@
//
// 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,52 +80,7 @@ namespace OpenWifi {
return true; return true;
} }
std::string OldDefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"}; bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser) {
std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"};
void Storage::ReplaceOldDefaultUUID() {
try {
Poco::Data::Session Sess = Pool_->get();
std::string St1{"update users set id=? where id=?"};
Poco::Data::Statement Update(Sess);
Update << ConvertParams(St1),
Poco::Data::Keywords::use(NewDefaultUseridStockUUID),
Poco::Data::Keywords::use(OldDefaultUseridStockUUID);
Update.execute();
} catch (...) {
}
}
// if we do not find a default user, then we need to create one based on the
// 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;
ReplaceOldDefaultUUID();
AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated);
if(!GetUserById(NewDefaultUseridStockUUID,U) && !DefaultUserCreated) {
U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password","");
U.lastPasswords.push_back(U.currentPassword);
U.email = MicroService::instance().ConfigGetString("authentication.default.username","");
U.Id = NewDefaultUseridStockUUID;
U.userRole = SecurityObjects::ROOT;
U.creationDate = std::time(nullptr);
U.validated = true;
U.name = "Default User";
U.description = "Default user should be deleted.";
U.changePassword = true;
CreateUser("SYSTEM",U, true);
AppServiceRegistry().Set("defaultusercreated",true);
return true;
}
return false;
}
bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready ) {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
@@ -148,24 +103,20 @@ namespace OpenWifi {
if(!Records.empty()) if(!Records.empty())
return false; return false;
if(!PasswordHashedAlready) { NewUser.Id = MicroService::instance().CreateUUID();
NewUser.Id = MicroService::CreateUUID();
NewUser.creationDate = std::time(nullptr); NewUser.creationDate = std::time(nullptr);
}
// if there is a password, we assume that we do not want email verification, // if there is a password, we assume that we do not want email verification,
// if there is no password, we will do email verification // if there is no password, we will do email verification
if(NewUser.currentPassword.empty()) { if(NewUser.currentPassword.empty()) {
} else { } else {
if(!PasswordHashedAlready) { NewUser.currentPassword = AuthService()->ComputePasswordHash(NewUser.email,NewUser.currentPassword);
NewUser.currentPassword = AuthService()->ComputeNewPasswordHash(NewUser.email,NewUser.currentPassword);
NewUser.lastPasswords.clear(); NewUser.lastPasswords.clear();
NewUser.lastPasswords.push_back(NewUser.currentPassword); NewUser.lastPasswords.push_back(NewUser.currentPassword);
NewUser.lastPasswordChange = std::time(nullptr); NewUser.lastPasswordChange = std::time(nullptr);
NewUser.validated = true; NewUser.validated = true;
} }
}
auto Notes = RESTAPI_utils::to_string(NewUser.notes); auto Notes = RESTAPI_utils::to_string(NewUser.notes);
auto UserType = SecurityObjects::UserTypeToString(NewUser.userRole); auto UserType = SecurityObjects::UserTypeToString(NewUser.userRole);

View File

@@ -15,23 +15,23 @@ namespace OpenWifi {
"description varchar," "description varchar,"
"avatar varchar," "avatar varchar,"
"email varchar," "email varchar,"
"validated boolean," "validated int,"
"validationEmail varchar," "validationEmail varchar,"
"validationDate bigint," "validationDate bigint,"
"creationDate bigint," "creationDate bigint,"
"validationURI varchar," "validationURI varchar,"
"changePassword boolean," "changePassword int,"
"lastLogin bigint," "lastLogin bigint,"
"currentLoginURI varchar," "currentLoginURI varchar,"
"lastPasswordChange bigint," "lastPasswordChange bigint,"
"lastEmailCheck bigint," "lastEmailCheck bigint,"
"waitingForEmailCheck boolean," "waitingForEmailCheck int,"
"locale varchar," "locale varchar,"
"notes text," "notes text,"
"location varchar," "location varchar,"
"owner varchar," "owner varchar,"
"suspended boolean," "suspended int,"
"blackListed boolean," "blackListed int,"
"userRole varchar," "userRole varchar,"
"userTypeProprietaryInfo text," "userTypeProprietaryInfo text,"
"securityPolicy text," "securityPolicy text,"
@@ -105,29 +105,43 @@ namespace OpenWifi {
"oauthType=?, " "oauthType=?, "
"oauthUserInfo=? "}; "oauthUserInfo=? "};
static const std::string AllActionLinksFieldsForCreation{
"Id varchar(36),"
"Action varchar,"
"UserId varchar,"
"template varchar,"
"locale varchar,"
"message text,"
"sent bigint,"
"created bigint,"
"expires bigint,"
"completed bigint,"
"canceled bigint"
};
typedef Poco::Tuple < typedef Poco::Tuple <
std::string, // Id = 0; std::string, // Id = 0;
std::string, // name; std::string, // name;
std::string, // description; std::string, // description;
std::string, // avatar; std::string, // avatar;
std::string, // email; std::string, // email;
bool, // bool validated = false; uint64_t, // bool validated = false;
std::string, // validationEmail; std::string, // validationEmail;
uint64_t, // validationDate = 0; uint64_t, // validationDate = 0;
uint64_t, // creationDate = 0; uint64_t, // creationDate = 0;
std::string, // validationURI; std::string, // validationURI;
bool, // bool changePassword = true; uint64_t, // bool changePassword = true;
uint64_t, // lastLogin = 0; uint64_t, // lastLogin = 0;
std::string, // currentLoginURI; std::string, // currentLoginURI;
uint64_t, // lastPasswordChange = 0; uint64_t, // lastPasswordChange = 0;
uint64_t, // lastEmailCheck = 0; uint64_t, // lastEmailCheck = 0;
bool, // bool waitingForEmailCheck = false; uint64_t, // bool waitingForEmailCheck = false;
std::string, // locale; std::string, // locale;
std::string, // notes; std::string, // notes;
std::string, // location; std::string, // location;
std::string, // owner; std::string, // owner;
bool, // bool suspended = false; uint64_t, // bool suspended = false;
bool, // bool blackListed = false; uint64_t, // bool blackListed = false;
std::string, // userRole; std::string, // userRole;
std::string, // userTypeProprietaryInfo; std::string, // userTypeProprietaryInfo;
std::string, // securityPolicy; std::string, // securityPolicy;

View File

@@ -35,7 +35,7 @@ fi
token="" token=""
result_file=result.json result_file=result.json
username="tip@ucentral.com" username="tip@ucentral.com"
password="Snoopy99!!!" password="openwifi"
#username="stephb@incognito.com" #username="stephb@incognito.com"
#password="Snoopy98!" #password="Snoopy98!"
browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl) browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl)
@@ -58,8 +58,8 @@ testlogin() {
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$payload" > ${result_file} -d "$payload" > ${result_file}
userMustChangePassword=$(cat ${result_file} | jq -r '.ErrorCode') userMustChangePassword=$(cat ${result_file} | jq -r '.userMustChangePassword')
if [[ ${userMustChangePassword} == "1" ]] if [[ ${userMustChangePassword} == "true" ]]
then then
echo "User must change password to login..." echo "User must change password to login..."
if [[ "$3" == "" ]] if [[ "$3" == "" ]]
@@ -78,10 +78,7 @@ testlogin() {
curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$payload" > ${result_file} -d "$payload" > ${result_file}
token=$(cat ${result_file} | jq -r '.access_token') jq < ${result_file}
else
payload="{ \"userId\" : \"$1\" , \"password\" : \"$2\" }"
token=$(curl ${FLAGS} -X POST -H "Content-Type: application/json" -d "$payload" "https://${OWSEC}/api/v1/oauth2" | jq -r '.access_token')
fi fi
jq < ${result_file} jq < ${result_file}
} }
@@ -375,7 +372,6 @@ case "$1" in
"getsubsystemnames") login; getsubsystemnames; logout ;; "getsubsystemnames") login; getsubsystemnames; logout ;;
"reloadsubsystem") login; reloadsubsystem "$2"; logout ;; "reloadsubsystem") login; reloadsubsystem "$2"; logout ;;
"systeminfo") login; systeminfo ; logout;; "systeminfo") login; systeminfo ; logout;;
"testburst") login; login; login; login; login; login; login; login; login; login; login; login; login; login; login; login;;
"help") login; help ; logout ;; "help") login; help ; logout ;;
*) help ;; *) help ;;
esac esac

View File

@@ -1,26 +0,0 @@
#!/bin/sh
# wait-for-postgres.sh
set -e
host="$1"
shift
export PGUSER=$(grep 'storage.type.postgresql.username' $OWSEC_CONFIG/owsec.properties | awk -F '= ' '{print $2}')
export PGPASSWORD=$(grep 'storage.type.postgresql.password' $OWSEC_CONFIG/owsec.properties | awk -F '= ' '{print $2}')
until psql -h "$host" -c '\q'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
if [ "$1" = '/openwifi/owsec' -a "$(id -u)" = '0' ]; then
if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
fi
exec su-exec "$OWSEC_USER" "$@"
fi
exec "$@"

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB