Compare commits

..

1 Commits

Author SHA1 Message Date
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
194 changed files with 4467 additions and 21952 deletions

View File

@@ -13,7 +13,6 @@ on:
pull_request:
branches:
- main
- 'release/*'
defaults:
run:
@@ -26,78 +25,45 @@ jobs:
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
DOCKER_REGISTRY_USERNAME: ucentral
steps:
- name: Checkout actions repo
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
- uses: actions/checkout@v2
- name: Build and push Docker image
uses: ./github/composite-actions/docker-image-build
with:
image_name: owsec
registry: tip-tip-wlan-cloud-ucentral.jfrog.io
registry_user: ucentral
registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
- name: Build Docker image
run: docker build -t wlan-cloud-owsec:${{ github.sha }} .
- name: Notify on failure via Slack
if: failure() && github.ref == 'refs/heads/main'
uses: rtCamp/action-slack-notify@v2
env:
SLACK_USERNAME: GitHub Actions failure notifier
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_COLOR: "${{ job.status }}"
SLACK_ICON: https://raw.githubusercontent.com/quintessence/slack-icons/master/images/github-logo-slack-icon.png
SLACK_TITLE: Docker build failed for OWSec service
trigger-testing:
if: startsWith(github.ref, 'refs/pull/')
runs-on: ubuntu-latest
needs: docker
steps:
- name: Get base branch name and set as output
id: get_base_branch
- name: Tag Docker image
run: |
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
TAGS="${{ github.sha }}"
- name: Checkout actions repo
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
if [[ ${GITHUB_REF} == "refs/heads/"* ]]
then
CURRENT_TAG=$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-')
TAGS="$TAGS $CURRENT_TAG"
else
if [[ ${GITHUB_REF} == "refs/tags/"* ]]
then
CURRENT_TAG=$(echo ${GITHUB_REF#refs/tags/} | tr '/' '-')
TAGS="$TAGS $CURRENT_TAG"
else # PR build
CURRENT_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
TAGS="$TAGS $CURRENT_TAG"
fi
fi
- name: Trigger testing of OpenWifi Docker Compose deployment and wait for result
uses: ./github/composite-actions/trigger-workflow-and-wait
env:
BASE_BRANCH: ${{ steps.get_base_branch.outputs.branch }}
OWGW_BASE_BRANCH: ${{ steps.get_base_branch.outputs.owgw_branch }}
with:
owner: Telecominfraproject
repo: wlan-testing
workflow: ow_docker-compose.yml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"deployment_version": "${{ env.BASE_BRANCH }}", "owgw_version": "${{ env.OWGW_BASE_BRANCH }}", "owsec_version": "${{ github.sha }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "${{ env.BASE_BRANCH }}", "owanalytics_version": "${{ env.BASE_BRANCH }}", "owsub_version": "${{ env.BASE_BRANCH }}", "microservice": "owsec"}'
echo "Result tags: $TAGS"
trigger-deploy-to-dev:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs:
- docker
steps:
- name: Checkout actions repo
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
for tag in $TAGS; do
docker tag wlan-cloud-owsec:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owsec:$tag
done
- name: Trigger deployment of the latest version to dev instance and wait for result
uses: ./github/composite-actions/trigger-workflow-and-wait
- name: Log into Docker registry
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main'
uses: docker/login-action@v1
with:
owner: Telecominfraproject
repo: wlan-testing
workflow: ucentralgw-dev-deployment.yaml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"force_latest": "true"}'
registry: ${{ env.DOCKER_REGISTRY_URL }}
username: ${{ env.DOCKER_REGISTRY_USERNAME }}
password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
- name: Push Docker images
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main'
run: |
docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/owsec | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {}

View File

@@ -4,7 +4,6 @@ on:
pull_request:
branches:
- main
- 'release/*'
types: [ closed ]
defaults:
@@ -17,10 +16,4 @@ jobs:
steps:
- run: |
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG"
else
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
fi
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owsec/$PR_BRANCH_TAG"

View File

@@ -1,24 +0,0 @@
name: Ensure Jira issue is linked
on:
pull_request:
types: [opened, edited, reopened, synchronize]
branches:
- 'release/*'
jobs:
check_for_issue_key:
runs-on: ubuntu-latest
steps:
- name: Checkout actions repo
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
- name: Run JIRA check
uses: ./github/composite-actions/enforce-jira-issue-key
with:
jira_base_url: ${{ secrets.TIP_JIRA_URL }}
jira_user_email: ${{ secrets.TIP_JIRA_USER_EMAIL }}
jira_api_token: ${{ secrets.TIP_JIRA_API_TOKEN }}

View File

@@ -1,46 +0,0 @@
name: Release chart package
on:
push:
tags:
- 'v*'
defaults:
run:
shell: bash
jobs:
helm-package:
runs-on: ubuntu-20.04
env:
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
HELM_REPO_USERNAME: ucentral
steps:
- name: Checkout uCentral assembly chart repo
uses: actions/checkout@v2
with:
path: wlan-cloud-ucentralsec
- name: Build package
working-directory: wlan-cloud-ucentralsec/helm
run: |
helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm dependency update
mkdir dist
helm package . -d dist
- name: Generate GitHub release body
working-directory: wlan-cloud-ucentralsec/helm
run: |
pip3 install yq -q
echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:$GITHUB_REF_NAME" > release.txt
echo "Helm charted may be attached to this release" >> release.txt
echo "Deployment artifacts may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/$GITHUB_REF_NAME" >> release.txt
- name: Create GitHub release
uses: softprops/action-gh-release@v1
with:
body_path: wlan-cloud-ucentralsec/helm/release.txt
files: wlan-cloud-ucentralsec/helm/dist/*

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owsec VERSION 2.7.0)
project(owsec VERSION 2.3.0)
set(CMAKE_CXX_STANDARD 17)
@@ -20,46 +20,29 @@ endif()
# Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/build BUILD_NUM)
file(READ build BUILD_NUM)
if(BUILD_INCREMENT)
MATH(EXPR BUILD_NUM "${BUILD_NUM}+1")
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
file(WRITE build ${BUILD_NUM})
endif()
else()
set(BUILD_NUM 1)
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
file(WRITE build ${BUILD_NUM})
endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
set(BUILD_SHARED_LIBS 1)
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}")
add_definitions(-DTIP_SECURITY_SERVICE="1")
add_definitions(-DPOCO_LOG_DEBUG="1")
add_compile_options(-Wall -Wextra)
if(ASAN)
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
endif()
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost REQUIRED system)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(fmt REQUIRED)
find_package(AWSSDK REQUIRED COMPONENTS sns)
find_package(nlohmann_json REQUIRED)
find_package(CppKafka REQUIRED)
find_package(PostgreSQL REQUIRED)
find_package(MySQL REQUIRED)
@@ -67,47 +50,35 @@ find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataS
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_executable( owsec
build
src/ow_version.h.in
src/framework/CountryCodes.h
src/framework/KafkaTopics.h
src/framework/MicroService.h
src/framework/OpenWifiTypes.h
src/framework/orm.h
src/framework/RESTAPI_errors.h
src/framework/RESTAPI_protocol.h
src/framework/StorageClass.h
src/framework/ow_constants.h
src/framework/WebSocketClientNotifications.h
src/seclibs/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp
src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h
src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.h
src/framework/uCentral_Protocol.h
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
src/RESTAPI/RESTAPI_oauth2Handler.h src/RESTAPI/RESTAPI_oauth2Handler.cpp
src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h
src/RESTAPI/RESTAPI_validate_token_handler.cpp src/RESTAPI/RESTAPI_validate_token_handler.h
src/RESTAPI/RESTAPI_system_endpoints_handler.cpp src/RESTAPI/RESTAPI_system_endpoints_handler.h
src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h
src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h
src/RESTAPI/RESTAPI_subavatar_handler.cpp src/RESTAPI/RESTAPI_subavatar_handler.h
src/RESTAPI/RESTAPI_validateToken_handler.cpp src/RESTAPI/RESTAPI_validateToken_handler.h
src/RESTAPI/RESTAPI_systemEndpoints_handler.cpp src/RESTAPI/RESTAPI_systemEndpoints_handler.h
src/RESTAPI/RESTAPI_AssetServer.cpp src/RESTAPI/RESTAPI_AssetServer.h
src/RESTAPI/RESTAPI_avatarHandler.cpp src/RESTAPI/RESTAPI_avatarHandler.h
src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h
src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h
src/RESTAPI/RESTAPI_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp
src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp
src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp
src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp src/RESTAPI/RESTAPI_validate_sub_token_handler.h
src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h
src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h
src/RESTAPI/RESTAPI_subpreferences.cpp src/RESTAPI/RESTAPI_subpreferences.h
src/RESTAPI/RESTAPI_routers.cpp
src/storage/storage_avatar.cpp src/storage/storage_avatar.h src/storage/storage_users.h
src/storage/storage_tables.cpp src/storage/storage_users.cpp src/storage/storage_tokens.cpp
src/APIServers.cpp
src/Daemon.h src/Daemon.cpp
src/SpecialUserHelpers.h
src/AuthService.h src/AuthService.cpp
src/StorageService.cpp src/StorageService.h
src/SMTPMailerService.cpp src/SMTPMailerService.h
@@ -115,26 +86,12 @@ add_executable( owsec
src/MFAServer.cpp src/MFAServer.h
src/SMS_provider_aws.cpp src/SMS_provider_aws.h
src/SMS_provider.cpp src/SMS_provider.h
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
src/ActionLinkManager.cpp src/ActionLinkManager.h
src/ACLProcessor.h
src/framework/OpenWifiTypes.h
src/storage/orm_users.cpp src/storage/orm_users.h
src/storage/orm_tokens.cpp src/storage/orm_tokens.h
src/storage/orm_preferences.cpp src/storage/orm_preferences.h
src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
src/storage/orm_avatar.cpp src/storage/orm_avatar.h
src/SpecialUserHelpers.h
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h)
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h)
if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC
${Poco_LIBRARIES}
${MySQL_LIBRARIES}
${ZLIB_LIBRARIES}
CppKafka::cppkafka
${AWSSDK_LINK_LIBRARIES}
fmt::fmt
${Poco_LIBRARIES} ${Boost_LIBRARIES} ${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
CppKafka::cppkafka ${AWSSDK_LINK_LIBRARIES}
)
if(UNIX AND NOT APPLE)
target_link_libraries(owsec PUBLIC PocoJSON)

View File

@@ -1,81 +1,17 @@
ARG ALPINE_VERSION=3.16.2
ARG POCO_VERSION=poco-tip-v1
ARG FMTLIB_VERSION=9.0.0
ARG CPPKAFKA_VERSION=tip-v1
ARG JSON_VALIDATOR_VERSION=2.1.0
ARG AWS_SDK_VERSION=1.9.315
FROM alpine:$ALPINE_VERSION AS build-base
FROM alpine AS builder
RUN apk add --update --no-cache \
make cmake g++ git \
unixodbc-dev postgresql-dev mariadb-dev \
librdkafka-dev boost-dev openssl-dev \
zlib-dev nlohmann-json \
curl-dev
openssl openssh \
ncurses-libs \
bash util-linux coreutils curl libcurl \
make cmake gcc g++ libstdc++ libgcc git zlib-dev \
openssl-dev boost-dev curl-dev unixodbc-dev postgresql-dev mariadb-dev \
apache2-utils yaml-dev apr-util-dev \
librdkafka-dev
FROM build-base AS poco-build
ARG POCO_VERSION
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
WORKDIR /poco
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS fmtlib-build
ARG FMTLIB_VERSION
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
WORKDIR /fmtlib
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
FROM build-base AS cppkafka-build
ARG CPPKAFKA_VERSION
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
WORKDIR /cppkafka
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS json-schema-validator-build
ARG JSON_VALIDATOR_VERSION
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
WORKDIR /json-schema-validator
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
FROM build-base AS aws-sdk-cpp-build
ARG AWS_SDK_VERSION
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp
RUN git clone https://github.com/stephb9959/poco /poco
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
WORKDIR /aws-sdk-cpp
RUN mkdir cmake-build
@@ -87,34 +23,31 @@ RUN cmake .. -DBUILD_ONLY="sns;s3" \
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS owsec-build
WORKDIR /cppkafka
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
WORKDIR /poco
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
ADD CMakeLists.txt build /owsec/
ADD cmake /owsec/cmake
ADD src /owsec/src
ADD .git /owsec/.git
COPY --from=poco-build /usr/local/include /usr/local/include
COPY --from=poco-build /usr/local/lib /usr/local/lib
COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
COPY --from=fmtlib-build /usr/local/include /usr/local/include
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
WORKDIR /owsec
RUN mkdir cmake-build
WORKDIR /owsec/cmake-build
RUN cmake .. \
-Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
-DBUILD_SHARED_LIBS=ON
RUN cmake ..
RUN cmake --build . --config Release -j8
FROM alpine:$ALPINE_VERSION
FROM alpine
ENV OWSEC_USER=owsec \
OWSEC_ROOT=/owsec-data \
@@ -126,27 +59,22 @@ RUN addgroup -S "$OWSEC_USER" && \
RUN mkdir /openwifi
RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
mariadb-connector-c libpq unixodbc postgresql-client
COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
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 /cppkafka/cmake-build/src/lib/* /lib/
COPY --from=builder /poco/cmake-build/lib/* /lib/
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /lib/
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /lib/
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /lib/
COPY owsec.properties.tmpl /
COPY wwwassets /dist/wwwassets
COPY templates /dist/templates
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 \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
COPY readiness_check /readiness_check
EXPOSE 16001 17001 16101

View File

@@ -1,37 +0,0 @@
# Operator Support
In order to support multiple tenants and operators, you must prepare the security service to serve
customized e-mails and messages.
## Structure for `templates`
Any file in the root of the directory will be used as defaults. The following files must be present:
- email_invitation.html/txt : This email message will be sent to a newly added user.
- email_verification.html/txt : This email is sent when an email verification is required.
- password_reset.html/txt : This is sent when a pasword reset is requested.
- verification_code.html/txt : This is used during MFA when email based.
- signup_verification.html/txt : This email is send to a new subscriber who signed up for service.
- sub_email_verification.html/txt : This is sent to a subscriber requiring an email verification.
- sub_verification_code.html/txt : This is used during MFA when email based for a subscriber.
- logo.jpg : The default logo to use in any of these emails.
## Structure for `wwwassets`
Any file in the root of the directory will be used as defaults. The following files must be present:
- email_verification_error.html : Used when email verification has failed.
- email_verification_success.html : Used when emil verification has succeeded.
- invitation_error.html :
- invitation_success.html :
- password_policy.html :
- password_reset.html :
- password_reset_success.html :
- password_reset_error.html :
- signup_verification.html :
- signup_verification_error.html :
- signup_verification_success.html :
- favicon.ico : icon for the application
- 404_error.html : your customized 404 page
- the_logo : the logo to use.
## For tenants
When creating a tenant/operator, you must create a subdirectory inside each `wwwassets` and `templates` and replicate
all the files that appear at the root level. You need to use the short Operator name (also known as RegistrantId in the API). This means
no spaces, all lowercase characters and numbers. No special characters: 0-9 and a-z.

View File

@@ -98,45 +98,11 @@ to get a sample. The default is
### `authentication.oldpasswords`
The number of older passwords to keep. Default is 5.
### Changing default password
On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
```
export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
export OWSEC_DEFAULT_PASSWORD=weLoveWifi # default password __in cleartext__ from property 'authentication.default.password'
export OWSEC_NEW_PASSWORD=NewPass123% # new password that must be set for the user (must comply with 'authentication.validation.expression')
test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
```
CLI is also included in Docker image if you want to run it this way:
```
export OWSEC=openwifi.wlan.local:16001
#export FLAGS="-k"
export OWSEC_DEFAULT_USERNAME=root@system.com
export OWSEC_DEFAULT_PASSWORD=weLoveWifi
export OWSEC_NEW_PASSWORD=NewPass123%
docker run --rm -ti \
--network=host \
--env OWSEC \
--env FLAGS \
--env OWSEC_DEFAULT_USERNAME \
--env OWSEC_DEFAULT_PASSWORD \
--env OWSEC_NEW_PASSWORD \
tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:main \
/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
```
### Kafka integration
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
```
```asm
openwifi.kafka.group.id = security
openwifi.kafka.client.id = security1
openwifi.kafka.enable = true
@@ -166,7 +132,7 @@ Here are the parameters for the public interface. The important files are:
- `restapi-key.pem` : the key associated with this certificate
- `openwifi.restapi.host.0.key.password` : if you key is password protected, you may supply that password here.
```
```asm
openwifi.restapi.host.0.backlog = 100
openwifi.restapi.host.0.security = relaxed
openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
@@ -181,7 +147,7 @@ openwifi.restapi.host.0.key.password = mypassword
The private interface is used for service-to-service communication. You can use self-signed certificates here or letsencrypt. The file names are similar
to the filenames used in the previous section.
```
```asm
openwifi.internal.restapi.host.0.backlog = 100
openwifi.internal.restapi.host.0.security = relaxed
openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
@@ -196,7 +162,7 @@ openwifi.internal.restapi.host.0.key.password = mypassword
Here are other important values you must set.
```
```asm
openwifi.system.data = $OWSEC_ROOT/data
openwifi.system.uri.private = https://localhost:17001
openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001
@@ -218,11 +184,10 @@ This is the FQDN used externally serving the OpenAPI interface.
`owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so,
an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS
#### AWS SMS
#### AWS SNS
For SNS you must create an IAM ID that has sns:sendmessage rights.
```
smssender.enabled = true
```asm
smssender.provider = aws
smssender.aws.secretkey = ***************************************
smssender.aws.accesskey = ***************************************
@@ -232,8 +197,7 @@ smssender.aws.region = **************
#### Twilio
For Twilio, you must provide the following
```
smssender.enabled = true
```asm
smssender.provider = twilio
smssender.twilio.sid = ***********************
smssender.twilio.token = **********************
@@ -245,8 +209,7 @@ smssender.twilio.phonenumber = +18888888888
with GMail and AWS SES. For each, you must obtain the proper credentials and insert them in this configuration as well
as the proper mail host.
```
mailer.enabled = true
```asm
mailer.hostname = smtp.gmail.com
mailer.username = ************************
mailer.password = ************************
@@ -255,13 +218,3 @@ mailer.loginmethod = login
mailer.port = 587
mailer.templates = $OWSEC_ROOT/templates
```
#### Google Authenticator
In order to use the Google Time-based One-Time Password (TOTP), the user must download the Google Authenticator
on any other app that support the TOTP protocol. You should include the following in your configuration
```
totp.issuer = OrgName
```
It is very important that you not use spaces in your OrgName.

2
build
View File

@@ -1 +1 @@
19
12

View File

@@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
update-ca-certificates
fi
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; then
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWSEC_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16001"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWSEC_ROOT/certs/restapi-cert.pem"} \
@@ -23,30 +23,16 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17001"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16001"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \
SMSSENDER_PROVIDER=${SMSSENDER_PROVIDER:-""} \
SMSSENDER_AWS_SECRETKEY=${SMSSENDER_AWS_SECRETKEY:-""} \
SMSSENDER_AWS_ACCESSKEY=${SMSSENDER_AWS_ACCESSKEY:-""} \
SMSSENDER_AWS_REGION=${SMSSENDER_AWS_REGION:-""} \
SMSSENDER_TWILIO_SID=${SMSSENDER_TWILIO_SID:-""} \
SMSSENDER_TWILIO_TOKEN=${SMSSENDER_TWILIO_TOKEN:-""} \
SMSSENDER_TWILIO_PHONENUMBER=${SMSSENDER_TWILIO_PHONENUMBER:-""} \
MAILER_ENABLED=${MAILER_ENABLED:-"false"} \
MAILER_HOSTNAME=${MAILER_HOSTNAME:-"localhost"} \
MAILER_USERNAME=${MAILER_USERNAME:-""} \
MAILER_PASSWORD=${MAILER_PASSWORD:-""} \
MAILER_HOSTNAME=${MAILER_HOSTNAME:-"smtp.gmail.com"} \
MAILER_USERNAME=${MAILER_USERNAME:-"************************"} \
MAILER_PASSWORD=${MAILER_PASSWORD:-"************************"} \
MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \
MAILER_PORT=${MAILER_PORT:-"587"} \
MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \
KAFKA_SSL_CERTIFICATE_LOCATION=${KAFKA_SSL_CERTIFICATE_LOCATION:-""} \
KAFKA_SSL_KEY_LOCATION=${KAFKA_SSL_KEY_LOCATION:-""} \
KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \
DOCUMENT_POLICY_ACCESS=${DOCUMENT_POLICY_ACCESS:-"\$OWSEC_ROOT/persist/wwwassets/access_policy.html"} \
DOCUMENT_POLICY_PASSWORD=${DOCUMENT_POLICY_PASSWORD:-"\$OWSEC_ROOT/persist/wwwassets/password_policy.html"} \
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \

2
helm/.gitignore vendored
View File

@@ -1,3 +1 @@
*.swp
Chart.lock
charts/

View File

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

View File

@@ -70,8 +70,8 @@ The following table lists the configurable parameters of the chart and their def
| persistence.size | string | Defines PV size | `'10Gi'` |
| public_env_variables | hash | Defines list of environment variables to be passed to the Security | |
| configProperties | hash | Configuration properties that should be passed to the application in `owsec.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
| existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` |
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owsec` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. | |
| certs | hash | Defines files (keys and certificates) that should be passed to the Security (PEM format is adviced to be used) (see `volumes.owsec` on where it is mounted) | |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

View File

@@ -30,13 +30,3 @@ Create chart name and version as used by the chart label.
{{- define "owsec.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- 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

@@ -1,5 +1,4 @@
{{- $root := . -}}
{{- $storageType := index .Values.configProperties "storage.type" -}}
---
apiVersion: apps/v1
kind: Deployment
@@ -14,7 +13,6 @@ spec:
replicas: {{ .Values.replicaCount }}
strategy:
type: {{ .Values.strategyType }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "owsec.name" . }}
@@ -26,9 +24,6 @@ spec:
metadata:
annotations:
checksum/config: {{ include "owsec.config" . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
app.kubernetes.io/name: {{ include "owsec.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
@@ -37,49 +32,6 @@ spec:
{{- end }}
spec:
initContainers:
- name: wait-kafka
image: "{{ .Values.images.dockerize.repository }}:{{ .Values.images.dockerize.tag }}"
imagePullPolicy: {{ .Values.images.dockerize.pullPolicy }}
args:
- -wait
- tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }}
- -timeout
- 600s
{{- if eq $storageType "postgresql" }}
- name: wait-postgres
image: "{{ .Values.images.owsec.repository }}:{{ .Values.images.owsec.tag }}"
imagePullPolicy: {{ .Values.images.owsec.pullPolicy }}
command:
- /wait-for-postgres.sh
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
- echo
- "PostgreSQL is ready"
env:
- name: KUBERNETES_DEPLOYED
value: "{{ now }}"
{{- range $key, $value := .Values.public_env_variables }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- range $key, $value := .Values.secret_env_variables }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ include "owsec.fullname" $root }}-env
key: {{ $key }}
{{- end }}
volumeMounts:
{{- range .Values.volumes.owsec }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- if .subPath }}
subPath: {{ .subPath }}
{{- end }}
{{- end }}
{{- end }}
containers:
- name: owsec

View File

@@ -2,7 +2,7 @@
{{- range $ingress, $ingressValue := .Values.ingresses }}
{{- if $ingressValue.enabled }}
---
apiVersion: {{ include "owsec.ingress.apiVersion" $root }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ include "owsec.fullname" $root }}-{{ $ingress }}
@@ -36,25 +36,11 @@ spec:
paths:
{{- range $ingressValue.paths }}
- path: {{ .path }}
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
pathType: {{ .pathType | default "ImplementationSpecific" }}
{{- end }}
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 }}
servicePort: {{ .servicePort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -1,7 +1,6 @@
# System
replicaCount: 1
strategyType: Recreate
revisionHistoryLimit: 2
nameOverride: ""
fullnameOverride: ""
@@ -9,20 +8,16 @@ fullnameOverride: ""
images:
owsec:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
tag: v2.7.0-RC2
tag: v2.3.0-RC1
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
# username: username
# password: password
dockerize:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/dockerize
tag: 0.16.0
pullPolicy: IfNotPresent
services:
owsec:
type: ClusterIP
type: LoadBalancer
ports:
restapi:
servicePort: 16001
@@ -43,6 +38,7 @@ checks:
exec:
command:
- /readiness_check
failureThreshold: 1
ingresses:
restapi:
@@ -54,7 +50,6 @@ ingresses:
- restapi.chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
serviceName: owsec
servicePort: restapi
@@ -71,7 +66,7 @@ volumes:
mountPath: /owsec-data/certs
volumeDefinition: |
secret:
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owsec.fullname" . }}-certs{{ end }}
secretName: {{ include "owsec.fullname" . }}-certs
# Change this if you want to use another volume type
- name: persist
mountPath: /owsec-data/persist
@@ -100,8 +95,6 @@ tolerations: []
affinity: {}
podAnnotations: {}
persistence:
enabled: true
# storageClassName: "-"
@@ -146,17 +139,11 @@ configProperties:
authentication.default.access: master
authentication.service.type: internal
# Mailer
mailer.enabled: "false"
mailer.hostname: smtp.gmail.com
mailer.sender: OpenWIFI
mailer.loginmethod: login
mailer.port: 587
mailer.templates: $OWSEC_ROOT/persist/templates
# SMS
smssender.enabled: "false"
smssender.provider: "aws"
#smssender.aws.region: ""
#smssender.twilio.phonenumber: ""
# ALB
alb.enable: "true"
alb.port: 16101
@@ -167,10 +154,6 @@ configProperties:
openwifi.kafka.brokerlist: localhost:9092
openwifi.kafka.auto.commit: false
openwifi.kafka.queue.buffering.max.ms: 50
openwifi.kafka.ssl.ca.location: ""
openwifi.kafka.ssl.certificate.location: ""
openwifi.kafka.ssl.key.location: ""
openwifi.kafka.ssl.key.password: ""
# Storage
storage.type: sqlite # (sqlite|postgresql|mysql|odbc)
## SQLite
@@ -200,9 +183,22 @@ configProperties:
openwifi.system.uri.ui: https://localhost
openwifi.system.commandchannel: /tmp/app_owsec
# Logging
logging.type: console
logging.path: $OWSEC_ROOT/logs
logging.level: debug
logging.formatters.f1.class: PatternFormatter
logging.formatters.f1.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t"
logging.formatters.f1.times: UTC
logging.channels.c1.class: ConsoleChannel
logging.channels.c1.formatter: f1
logging.channels.c2.class: FileChannel
logging.channels.c2.path: /tmp/log_owsec
logging.channels.c2.formatter.class: PatternFormatter
logging.channels.c2.formatter.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t"
logging.channels.c2.rotation: "20 M"
logging.channels.c2.archive: timestamp
logging.channels.c2.purgeCount: 20
logging.channels.c3.class: ConsoleChannel
logging.channels.c3.pattern: "%s: [%p] %t"
logging.loggers.root.channel: c1
logging.loggers.root.level: debug
# -> Secret part
# REST API
@@ -214,12 +210,6 @@ configProperties:
# Mailer
mailer.username: no-reply@arilia.com
mailer.password: "**************************"
# SMS
#smssender.aws.secretkey: ""
#smssender.aws.accesskey: ""
#smssender.twilio.sid: ""
#smssender.twilio.token: ""
#
# Storage
## PostgreSQL
storage.type.postgresql.username: stephb
@@ -228,9 +218,6 @@ configProperties:
storage.type.mysql.username: stephb
storage.type.mysql.password: snoopy99
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
existingCertsSecret: ""
certs:
# restapi-ca.pem: ""
# restapi-cert.pem: ""

View File

@@ -2,7 +2,7 @@ openapi: 3.0.1
info:
title: uCentral Security API
description: A process to manage security logins.
version: 2.5.0
version: 2.0.0
license:
name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
@@ -51,22 +51,6 @@ components:
properties:
ErrorCode:
type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # EXPIRED_TOKEN
- 10 # RATE_LIMIT_EXCEEDED
- 11 # BAD_MFA_TRANSACTION
- 12 # MFA_FAILURE
- 13 # SECURITY_SERVICE_UNREACHABLE
- 14 # CANNOT REFRESH TOKEN
ErrorDetails:
type: string
ErrorDescription:
@@ -85,20 +69,8 @@ components:
Code:
type: integer
BadRequest:
description: The requested operation failed.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: integer
schemas:
WebTokenRequest:
description: User Id and password.
type: object
@@ -121,15 +93,6 @@ components:
userId: support@example.com
password: support
WebTokenRefreshRequest:
type: object
properties:
userId:
type: string
default: support@example.com
refresh_token:
type: string
WebTokenResult:
description: Login and Refresh Tokens to be used in subsequent API calls.
type: object
@@ -253,7 +216,7 @@ components:
enum:
- sms
- email
- authenticator
- voice
UserLoginLoginExtensions:
type: object
@@ -262,8 +225,6 @@ components:
type: array
items:
$ref: '#/components/schemas/MobilePhoneNumber'
authenticatorSecret:
type: string
mfa:
$ref: '#/components/schemas/MfaAuthInfo'
@@ -360,14 +321,8 @@ components:
securityPolicyChange:
type: integer
format: int64
modified:
type: integer
format: int64
userTypeProprietaryInfo:
$ref: '#/components/schemas/UserLoginLoginExtensions'
signupUUID:
type: string
format: uuid
UserList:
type: object
@@ -426,24 +381,6 @@ components:
answer:
type: string
SubMfaConfig:
type: object
properties:
id:
type: string
format: uuid
type:
type: string
enum:
- disabled
- sms
- email
email:
type: string
format: email
sms:
type: string
#########################################################################################
##
## These are endpoints that all services in the uCentral stack must provide
@@ -688,22 +625,6 @@ components:
items:
$ref: '#/components/schemas/TagValuePair'
Preferences:
type: object
properties:
modified:
type: integer
format: int64
data:
type: array
items:
type: object
properties:
tag:
type: string
value:
type: string
#########################################################################################
##
## End of uCentral system wide values
@@ -746,12 +667,6 @@ paths:
schema:
type: boolean
required: false
- in: query
name: grant_type
schema:
type: string
example: refresh_token
required: false
requestBody:
description: User id and password
required: true
@@ -761,72 +676,6 @@ paths:
oneOf:
- $ref: '#/components/schemas/WebTokenRequest'
- $ref: '#/components/schemas/MFAChallengeResponse'
- $ref: '#/components/schemas/WebTokenRefreshRequest'
responses:
200:
description: successful operation
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/WebTokenResult'
- $ref: '#/components/schemas/MFAChallengeRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/suboauth2:
post:
tags:
- Authentication
summary: Get access token - to be used as Bearer token header for all other API requests.
operationId: getSubAccessToken
parameters:
- in: query
name: newPassword
description: used when a user is trying to change her password. This will be the new password.
schema:
type: string
required: false
- in: query
name: forgotPassword
description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
schema:
type: boolean
required: false
- in: query
name: requirements
description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
schema:
type: boolean
required: false
- in: query
name: resendMFACode
schema:
type: boolean
required: false
- in: query
name: completeMFAChallenge
schema:
type: boolean
required: false
- in: query
name: grant_type
schema:
type: string
example: refresh_token
required: false
requestBody:
description: User id and password
required: true
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/WebTokenRequest'
- $ref: '#/components/schemas/MFAChallengeResponse'
- $ref: '#/components/schemas/WebTokenRefreshRequest'
responses:
200:
description: successful operation
@@ -866,31 +715,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/suboauth2/{token}:
delete:
tags:
- Authentication
summary: Revoke a token.
operationId: removeSubAccessToken
parameters:
- in: path
name: token
schema:
type:
string
required: true
responses:
204:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/systemEndpoints:
get:
tags:
@@ -947,72 +771,6 @@ paths:
type: string
example: id1,id2,id3,id4,id5
required: false
- in: query
description: Name matching
name: nameSearch
schema:
type: string
- in: query
description: Name matching
name: emailSearch
schema:
type: string
responses:
200:
$ref: '#/components/schemas/UserList'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/subusers:
get:
tags:
- Subscribers
summary: Retrieve a list of existing users as well as some information about them.
operationId: getSubUsers
parameters:
- in: query
name: offset
schema:
type: integer
format: int64
required: false
- in: query
name: limit
schema:
type: integer
format: int64
required: false
- in: query
description: Selecting this option means the newest record will be returned. Use limit to select how many.
name: filter
schema:
type: string
required: false
- in: query
description: Return only the ids.
name: idOnly
schema:
type: boolean
required: false
- in: query
description: Return only the ids.
name: select
schema:
type: string
example: id1,id2,id3,id4,id5
required: false
- in: query
description: Name matching
name: nameSearch
schema:
type: string
- in: query
description: Name matching
name: emailSearch
schema:
type: string
responses:
200:
$ref: '#/components/schemas/UserList'
@@ -1111,134 +869,6 @@ paths:
schema:
type: boolean
required: false
- in: query
name: forgotPassword
schema:
type: boolean
default: false
required: false
- in: query
name: resetMFA
schema:
type: boolean
default: false
required: false
requestBody:
description: User details (some fields are ignored during update)
content:
application/json:
schema:
$ref: '#/components/schemas/UserInfo'
responses:
200:
$ref: '#/components/schemas/UserInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/subuser/{id}:
get:
tags:
- Subscribers
operationId: getSubUser
summary: Retrieve the information for a single user.
parameters:
- in: path
name: id
schema:
type: string
format: uuid
required: true
responses:
200:
$ref: '#/components/schemas/UserInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- Subscribers
operationId: deleteSubUser
summary: Delete a single user.
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
responses:
204:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
post:
tags:
- Subscribers
operationId: createSubUser
summary: Create a single user.
parameters:
- in: path
name: id
#must be set to 0 for user creation
schema:
type: integer
format: int64
required: true
- in: query
name: email_verification
schema:
type: boolean
required: false
requestBody:
description: User details (some fields are ignored during creation)
content:
application/json:
schema:
$ref: '#/components/schemas/UserInfo'
responses:
200:
$ref: '#/components/schemas/UserInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- Subscribers
operationId: updateSubUser
summary: Modify a single user.
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
- in: query
name: email_verification
schema:
type: boolean
required: false
- in: query
name: forgotPassword
schema:
type: boolean
default: false
required: false
- in: query
name: resetMFA
schema:
type: boolean
default: false
required: false
requestBody:
description: User details (some fields are ignored during update)
content:
@@ -1423,219 +1053,6 @@ paths:
items:
type: string
/userPreferences:
get:
tags:
- Preferences
operationId: getUserPreferences
summary: Get the list of recorded preferences for a user
responses:
200:
$ref: '#/components/schemas/Preferences'
400:
$ref: '#/components/responses/BadRequest'
post:
tags:
- Preferences
operationId: setUserPreferences
summary: Set the list of recorded preferences for a user
requestBody:
description: Setting the list of preferences
content:
application/json:
schema:
$ref: '#/components/schemas/Preferences'
responses:
200:
$ref: '#/components/schemas/Preferences'
400:
$ref: '#/components/responses/BadRequest'
/submfa:
get:
tags:
- MFA
summary: Retrieve the cyrrent setting for MFA
operationId: getMFS
responses:
200:
$ref: '#/components/schemas/SubMfaConfig'
put:
tags:
- MFA
summary: Retrieve the cyrrent setting for MFA
operationId: modifyMFS
parameters:
- in: query
name: startValidation
schema:
type: boolean
required: false
- in: query
name: completeValidation
schema:
type: boolean
required: false
- in: query
name: challengeCode
schema:
type: string
required: false
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SubMfaConfig'
responses:
200:
$ref: '#/components/schemas/SubMfaConfig'
400:
$ref: '#/components/responses/BadRequest'
/totp:
get:
tags:
- Security
summary: Retrieve the Authenticator QR Code
operationId: getTotpQrCode
parameters:
- in: query
name: reset
schema:
type: boolean
default: false
required: false
responses:
200:
description: QRCode
content:
image/svg+xml:
schema:
type: string
format: binary
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
put:
tags:
- Security
summary: Send the first security code to validate your setup
operationId: sendToptTestCode
parameters:
- in: query
name: value
schema:
type: integer
format: int64
required: true
- in: query
name: index
schema:
type: integer
format: int64
example: 1,2,3
required: true
responses:
200:
description: Succesful posting of response.
content:
application/json:
schema:
type: object
properties:
nextIndex:
type: integer
moreCodes:
type: boolean
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
/signup:
post:
tags:
- Subscriber Registration
summary: This call allows a new subscriber to register themselves and their devices.
operationId: postSignup
parameters:
- in: query
name: email
schema:
type: string
format: email
required: true
- in: query
name: signupUUID
schema:
type: string
format: uuid
required: true
responses:
200:
$ref: '#/components/schemas/UserInfo'
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- Subscriber Registration
summary: modify the signup command in play
operationId: modifySignup
parameters:
- in: query
name: signupUUID
schema:
type: string
format: uuid
required: true
- in: query
name: operation
schema:
type: string
enum:
- cancel
- success
- inprogress
- failed
- poll
- emailVerified
required: true
requestBody:
content:
application/json:
schema:
type: object
properties:
reason:
type: string
time:
type: integer
format: int64
errorCode:
type: integer
format: int32
required: false
responses:
200:
$ref: '#/components/responses/Success'
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
#########################################################################################
##
## These are endpoints that all services in the uCentral stack must provide
@@ -1711,27 +1128,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/validateSubToken:
get:
tags:
- Security
- Subscribers
summary: Allows any microservice to validate a token and get security policy for a specific user.
operationId: validateSubToken
parameters:
- in: query
name: token
schema:
type: string
required: true
responses:
200:
$ref: '#/components/schemas/TokenValidationResult'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/system:
post:
tags:

View File

@@ -36,12 +36,10 @@ openwifi.system.data = $OWSEC_ROOT/data
openwifi.system.uri.private = https://localhost:17001
openwifi.system.uri.public = https://local.dpaas.arilia.com:16001
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
openwifi.security.restapi.disable = false
openwifi.system.commandchannel = /tmp/app.ucentralsec
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
openwifi.service.key.password = mypassword
smssender.enabled = false
smssender.provider = aws
smssender.aws.secretkey = ***************************************
smssender.aws.accesskey = ***************************************
@@ -55,7 +53,6 @@ smssender.aws.region = **************
#
# Security Microservice Specific Section
#
mailer.enabled = false
mailer.hostname = smtp.gmail.com
mailer.username = ************************
mailer.password = ************************
@@ -83,16 +80,10 @@ openwifi.kafka.enable = true
openwifi.kafka.brokerlist = a1.arilia.com:9092
openwifi.kafka.auto.commit = false
openwifi.kafka.queue.buffering.max.ms = 50
openwifi.kafka.ssl.ca.location =
openwifi.kafka.ssl.certificate.location =
openwifi.kafka.ssl.key.location =
openwifi.kafka.ssl.key.password =
openwifi.document.policy.access = /wwwassets/access_policy.html
openwifi.document.policy.password = /wwwassets/password_policy.html
openwifi.avatar.maxsize = 2000000
totp.issuer = OpenWiFi
#
# This section select which form of persistence you need
# Only one selected at a time. If you select multiple, this service will die if a horrible
@@ -125,12 +116,44 @@ storage.type.mysql.database = ucentral
storage.type.mysql.port = 3306
storage.type.mysql.connectiontimeout = 60
########################################################################
########################################################################
#
# Logging: please leave as is for now.
#
########################################################################
logging.type = file
logging.path = $OWSEC_ROOT/logs
logging.level = debug
logging.formatters.f1.class = PatternFormatter
logging.formatters.f1.pattern = %s: [%p] %t
logging.formatters.f1.times = UTC
logging.channels.c1.class = ConsoleChannel
logging.channels.c1.formatter = f1
# This is where the logs will be written. This path MUST exist
logging.channels.c2.class = FileChannel
logging.channels.c2.path = $OWSEC_ROOT/logs/log
logging.channels.c2.formatter.class = PatternFormatter
logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
logging.channels.c2.rotation = 20 M
logging.channels.c2.archive = timestamp
logging.channels.c2.purgeCount = 20
logging.channels.c3.class = ConsoleChannel
logging.channels.c3.pattern = %s: [%p] %t
# External Channel
logging.loggers.root.channel = c2
logging.loggers.root.level = debug
# Inline Channel with PatternFormatter
# logging.loggers.l1.name = logger1
# logging.loggers.l1.channel.class = ConsoleChannel
# logging.loggers.l1.channel.pattern = %s: [%p] %t
# logging.loggers.l1.level = information
# SplitterChannel
# logging.channels.splitter.class = SplitterChannel
# logging.channels.splitter.channels = l1,l2
# logging.loggers.l2.name = logger2
# logging.loggers.l2.channel = splitter

View File

@@ -36,26 +36,13 @@ openwifi.system.data = ${SYSTEM_DATA}
openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
openwifi.system.commandchannel = /tmp/app.ucentralsec
openwifi.service.key = ${SERVICE_KEY}
openwifi.service.key.password = ${SERVICE_KEY_PASSWORD}
smssender.enabled = ${SMSSENDER_ENABLED}
smssender.provider = ${SMSSENDER_PROVIDER}
smssender.aws.secretkey = ${SMSSENDER_AWS_SECRETKEY}
smssender.aws.accesskey = ${SMSSENDER_AWS_ACCESSKEY}
smssender.aws.region = ${SMSSENDER_AWS_REGION}
smssender.twilio.sid = ${SMSSENDER_TWILIO_SID}
smssender.twilio.token = ${SMSSENDER_TWILIO_TOKEN}
smssender.twilio.phonenumber = ${SMSSENDER_TWILIO_PHONENUMBER}
#
# Security Microservice Specific Section
#
mailer.enabled = ${MAILER_ENABLED}
mailer.hostname = ${MAILER_HOSTNAME}
mailer.username = ${MAILER_USERNAME}
mailer.password = ${MAILER_PASSWORD}
@@ -83,10 +70,6 @@ openwifi.kafka.enable = ${KAFKA_ENABLE}
openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST}
openwifi.kafka.auto.commit = false
openwifi.kafka.queue.buffering.max.ms = 50
openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION}
openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION}
openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION}
openwifi.kafka.ssl.key.password = ${KAFKA_SSL_KEY_PASSWORD}
openwifi.document.policy.access = ${DOCUMENT_POLICY_ACCESS}
openwifi.document.policy.password = ${DOCUMENT_POLICY_PASSWORD}
@@ -127,6 +110,37 @@ storage.type.mysql.connectiontimeout = 60
# Logging: please leave as is for now.
#
########################################################################
logging.type = console
logging.path = $OWSEC_ROOT/logs
logging.level = debug
logging.formatters.f1.class = PatternFormatter
logging.formatters.f1.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
logging.formatters.f1.times = UTC
logging.channels.c1.class = ConsoleChannel
logging.channels.c1.formatter = f1
# This is where the logs will be written. This path MUST exist
logging.channels.c2.class = FileChannel
logging.channels.c2.path = $OWSEC_ROOT/logs/log
logging.channels.c2.formatter.class = PatternFormatter
logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
logging.channels.c2.rotation = 20 M
logging.channels.c2.archive = timestamp
logging.channels.c2.purgeCount = 20
logging.channels.c3.class = ConsoleChannel
logging.channels.c3.pattern = %s: [%p] %t
# External Channel
logging.loggers.root.channel = c1
logging.loggers.root.level = debug
# Inline Channel with PatternFormatter
# logging.loggers.l1.name = logger1
# logging.loggers.l1.channel.class = ConsoleChannel
# logging.loggers.l1.channel.pattern = %s: [%p] %t
# logging.loggers.l1.level = information
# SplitterChannel
# logging.channels.splitter.class = SplitterChannel
# logging.channels.splitter.channels = l1,l2
# logging.loggers.l2.name = logger2
# logging.loggers.l2.channel = splitter

View File

@@ -13,9 +13,6 @@ then
exit 1
fi
if [[ "${READINESS_METHOD}" == "systeminfo" ]]
then
if [[ "${OWSEC_USERNAME}" == "" ]]
then
echo "You must set the variable OWSEC_USERNAME in order to use this script. Something like"
@@ -30,6 +27,8 @@ then
exit 1
fi
if [[ "${READINESS_METHOD}" == "systeminfo" ]]
then
export RESTAPI_PORT=$(grep 'openwifi.restapi.host.0.port' $OWSEC_CONFIG/owsec.properties | awk -F '=' '{print $2}' | xargs | envsubst)
# Get OAuth token from OWSEC and cache it or use cached one
payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }"

View File

@@ -1,90 +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
};
/*
* 0) You can only delete yourself if you are a subscriber
1) You cannot delete yourself
2) If you are root, you can do anything.
3) You can do anything to yourself
4) Nobody can touch a root, unless they are a root, unless it is to get information on a ROOT
5) Creation rules:
ROOT -> create anything
PARTNER -> (multi-tenant owner) admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning
ADMIN -> admin-subs-csr-installer-noc-accounting
ACCOUNTING -> subs-installer-csr
*/
static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) {
// rule 0
if(User.id == Target.id && User.userRole == SecurityObjects::SUBSCRIBER && Op == DELETE)
return true;
// rule 1
if(User.id == Target.id && Op==DELETE)
return false;
// rule 2
if(User.userRole==SecurityObjects::ROOT)
return true;
// rule 3
if(User.id == Target.id)
return true;
// rule 4
if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
return false;
if(Op==CREATE) {
if(User.userRole==SecurityObjects::ROOT)
return true;
if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN ||
Target.userRole==SecurityObjects::SUBSCRIBER ||
Target.userRole==SecurityObjects::CSR ||
Target.userRole==SecurityObjects::INSTALLER ||
Target.userRole==SecurityObjects::NOC ||
Target.userRole==SecurityObjects::ACCOUNTING))
return true;
if(User.userRole==SecurityObjects::ADMIN &&
(Target.userRole==SecurityObjects::ADMIN ||
Target.userRole==SecurityObjects::SUBSCRIBER ||
Target.userRole==SecurityObjects::CSR ||
Target.userRole==SecurityObjects::INSTALLER ||
Target.userRole==SecurityObjects::NOC ||
Target.userRole==SecurityObjects::ACCOUNTING))
return true;
if(User.userRole==SecurityObjects::ACCOUNTING &&
(Target.userRole==SecurityObjects::SUBSCRIBER ||
Target.userRole==SecurityObjects::INSTALLER ||
Target.userRole==SecurityObjects::CSR))
return true;
return false;
}
return true;
}
private:
};
}
#endif //OWSEC_ACLPROCESSOR_H

47
src/APIServers.cpp Normal file
View File

@@ -0,0 +1,47 @@
//
// Created by stephane bourque on 2021-10-23.
//
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_oauth2Handler.h"
#include "RESTAPI/RESTAPI_user_handler.h"
#include "RESTAPI/RESTAPI_users_handler.h"
#include "RESTAPI/RESTAPI_action_links.h"
#include "RESTAPI/RESTAPI_systemEndpoints_handler.h"
#include "RESTAPI/RESTAPI_AssetServer.h"
#include "RESTAPI/RESTAPI_avatarHandler.h"
#include "RESTAPI/RESTAPI_email_handler.h"
#include "RESTAPI/RESTAPI_sms_handler.h"
#include "RESTAPI/RESTAPI_validateToken_handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S) {
return RESTAPI_Router<
RESTAPI_oauth2Handler,
RESTAPI_users_handler,
RESTAPI_user_handler,
RESTAPI_system_command,
RESTAPI_AssetServer,
RESTAPI_systemEndpoints_handler,
RESTAPI_action_links,
RESTAPI_avatarHandler,
RESTAPI_email_handler,
RESTAPI_sms_handler
>(Path, Bindings, L, S);
}
Poco::Net::HTTPRequestHandler * RESTAPI_internal_server(const char *Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S) {
return RESTAPI_Router_I<
RESTAPI_users_handler,
RESTAPI_user_handler,
RESTAPI_system_command,
RESTAPI_action_links,
RESTAPI_validateToken_handler,
RESTAPI_sms_handler
>(Path, Bindings, L, S);
}
}

View File

@@ -1,126 +0,0 @@
//
// Created by stephane bourque on 2021-11-08.
//
#include "ActionLinkManager.h"
#include "StorageService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "MessagingTemplates.h"
namespace OpenWifi {
int ActionLinkManager::Start() {
poco_information(Logger(),"Starting...");
if(!Running_)
Thr_.start(*this);
return 0;
}
void ActionLinkManager::Stop() {
poco_information(Logger(),"Stopping...");
if(Running_) {
Running_ = false;
Thr_.wakeUp();
Thr_.join();
}
poco_information(Logger(),"Stopped...");
}
void ActionLinkManager::run() {
Running_ = true ;
Utils::SetThreadName("action-mgr");
while(Running_) {
Poco::Thread::trySleep(2000);
if(!Running_)
break;
std::vector<SecurityObjects::ActionLink> Links;
{
std::lock_guard G(Mutex_);
StorageService()->ActionLinksDB().GetActions(Links);
}
if(Links.empty())
continue;
for(auto &i:Links) {
if(!Running_)
break;
SecurityObjects::UserInfo UInfo;
if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) {
StorageService()->ActionLinksDB().CancelAction(i.id);
continue;
} else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL ||
i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) {
StorageService()->ActionLinksDB().CancelAction(i.id);
continue;
} else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) &&
(OpenWifi::Now()-i.created)>(24*60*60)) {
StorageService()->ActionLinksDB().CancelAction(i.id);
continue;
}
switch(i.action) {
case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) {
poco_information(Logger(),fmt::format("Send password reset link to {}",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) {
poco_information(Logger(),fmt::format("Send email verification link to {}",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) {
poco_information(Logger(),fmt::format("Send new subscriber email invitation link to {}",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) {
poco_information(Logger(),fmt::format("Send subscriber password reset link to {}",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
poco_information(Logger(),fmt::format("Send subscriber email verification link to {}",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
poco_information(Logger(),fmt::format("Send new subscriber email verification link to {}",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
default: {
StorageService()->ActionLinksDB().SentAction(i.id);
}
}
}
}
}
}

View File

@@ -1,36 +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:
static ActionLinkManager * instance() {
static auto instance_ = new ActionLinkManager;
return instance_;
}
int Start() final;
void Stop() final;
void run() final;
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

@@ -8,23 +8,20 @@
#include <ctime>
#include "framework/MicroService.h"
#include "framework/KafkaTopics.h"
#include "Poco/Net/OAuth20Credentials.h"
#include "Poco/JWT/Token.h"
#include "Poco/JWT/Signer.h"
#include "Poco/StringTokenizer.h"
#include "framework/MicroService.h"
#include "StorageService.h"
#include "AuthService.h"
#include "framework/KafkaTopics.h"
#include "SMTPMailerService.h"
#include "MFAServer.h"
#include "MessagingTemplates.h"
namespace OpenWifi {
class AuthService *AuthService::instance_ = nullptr;
AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
switch (C) {
@@ -45,260 +42,108 @@ namespace OpenWifi {
return 1; // some compilers complain...
}
static const std::string DefaultPassword_8_u_l_n_1{"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\.\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{8,}$"};
int AuthService::Start() {
poco_information(Logger(),"Starting...");
Signer_.setRSAKey(MicroService::instance().Key());
Signer_.addAllAlgorithms();
Logger_.notice("Starting...");
Secure_ = MicroService::instance().ConfigGetBool("authentication.enabled",true);
DefaultPassword_ = MicroService::instance().ConfigGetString("authentication.default.password","");
DefaultUserName_ = MicroService::instance().ConfigGetString("authentication.default.username","");
Mechanism_ = MicroService::instance().ConfigGetString("authentication.service.type","internal");
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600);
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html");
PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html");
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1);
SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1);
SubAccessPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.access", "/wwwassets/access_policy.html");
SubPasswordPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.password", "/wwwassets/password_policy.html");
return 0;
}
void AuthService::Stop() {
poco_information(Logger(),"Stopping...");
poco_information(Logger(),"Stopped...");
Logger_.notice("Stopping...");
}
bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
try {
std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken();
}
if (CallToken.empty()) {
return false;
}
uint64_t RevocationDate=0;
std::string UserId;
if(StorageService()->UserTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) {
auto now = OpenWifi::Now();
// Create a new token
auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM);
auto NewRefreshToken = RefreshToken;
if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) {
NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM);
UI.webtoken.lastRefresh_ = now;
}
StorageService()->UserTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ );
UI.webtoken.access_token_ = NewToken;
UI.webtoken.refresh_token_ = NewRefreshToken;
return true;
}
return false;
} catch (...) {
}
return false;
}
bool AuthService::RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
try {
std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken();
}
if (CallToken.empty()) {
return false;
}
uint64_t RevocationDate=0;
std::string UserId;
if(StorageService()->SubTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) {
auto now = OpenWifi::Now();
// Create a new token
auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM);
auto NewRefreshToken = RefreshToken;
if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) {
NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM);
UI.webtoken.lastRefresh_ = now;
}
StorageService()->SubTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ );
UI.webtoken.access_token_ = NewToken;
UI.webtoken.refresh_token_ = NewRefreshToken;
return true;
}
return false;
} catch (...) {
}
return false;
}
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired )
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo )
{
// std::lock_guard Guard(Mutex_);
if(!Secure_)
return true;
std::lock_guard Guard(Mutex_);
std::string CallToken;
Expired = false;
try {
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken();
}
if(CallToken.empty()) {
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
return false;
}
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
std::string UserId;
if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0) {
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
return false;
}
auto now=OpenWifi::Now();
Expired = (WT.created_ + WT.expires_in_) < now;
if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) {
UInfo.webtoken = WT;
SessionToken = CallToken;
poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken));
return true;
}
}
} catch(const Poco::Exception &E) {
Logger().log(E);
}
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
if(!CallToken.empty()) {
if(StorageService()->IsTokenRevoked(CallToken))
return false;
}
auto Client = UserCache_.find(CallToken);
if( Client == UserCache_.end() )
return ValidateToken(CallToken, CallToken, UInfo);
bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired )
{
// std::lock_guard Guard(Mutex_);
std::string CallToken;
Expired = false;
try {
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken();
}
if(CallToken.empty()) {
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
return false;
}
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
std::string UserId;
if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0) {
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
return false;
}
auto now=OpenWifi::Now();
Expired = (WT.created_ + WT.expires_in_) < now;
if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) {
UInfo.webtoken = WT;
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken;
poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken));
UInfo = Client->second ;
return true;
}
}
} catch(const Poco::Exception &E) {
Logger().log(E);
}
poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
UserCache_.erase(CallToken);
StorageService()->RevokeToken(CallToken);
return false;
}
void AuthService::RevokeToken(std::string & Token) {
StorageService()->UserTokenDB().RevokeToken(Token);
return false;
}
void AuthService::RevokeSubToken(std::string & Token) {
StorageService()->SubTokenDB().RevokeToken(Token);
}
bool AuthService::DeleteUserFromCache(const std::string &UserName) {
std::lock_guard Guard(Mutex_);
bool AuthService::DeleteUserFromCache(const std::string &Id) {
return StorageService()->UserTokenDB().DeleteRecordsFromCache("userName",Id);
for(auto i=UserCache_.begin();i!=UserCache_.end();) {
if (i->second.userinfo.email==UserName) {
Logout(i->first, false);
i = UserCache_.erase(i);
} else {
++i;
}
bool AuthService::DeleteSubUserFromCache(const std::string &Id) {
return StorageService()->SubTokenDB().DeleteRecordsFromCache("userName",Id);
}
return true;
}
bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) {
return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer::MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method));
return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer().MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method));
}
bool AuthService::ValidatePassword(const std::string &Password) {
return std::regex_match(Password, PasswordValidation_);
}
bool AuthService::ValidateSubPassword(const std::string &Password) {
return std::regex_match(Password, SubPasswordValidation_);
}
void AuthService::Logout(const std::string &token, bool EraseFromCache) {
std::lock_guard Guard(Mutex_);
if(EraseFromCache)
UserCache_.erase(token);
void AuthService::RemoveTokenSystemWide(const std::string &token) {
try {
if(KafkaManager()->Enabled()) {
Poco::JSON::Object Obj;
Obj.set("event", "remove-token");
Obj.set("id", MicroService::instance().ID());
Obj.set("token", token);
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(),
ResultText.str(),
std::string Tmp{token};
StorageService()->RevokeToken(Tmp);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(),
false);
}
} catch (const Poco::Exception &E) {
Logger().log(E);
Logger_.log(E);
}
}
void AuthService::Logout(const std::string &Token,[[maybe_unused]] bool EraseFromCache) {
std::lock_guard Guard(Mutex_);
try {
auto tToken{Token};
StorageService()->UserTokenDB().DeleteRecord("token",tToken);
StorageService()->LoginDB().AddLogout(Token);
} catch (const Poco::Exception &E) {
Logger().log(E);
}
}
void AuthService::SubLogout(const std::string &Token, [[maybe_unused]] bool EraseFromCache) {
std::lock_guard Guard(Mutex_);
try {
auto tToken{Token};
StorageService()->SubTokenDB().DeleteRecord("token",tToken);
StorageService()->SubLoginDB().AddLogout(Token);
} catch (const Poco::Exception &E) {
Logger().log(E);
}
}
[[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, [[maybe_unused]] ACCESS_TYPE Type) {
std::string Identity(UserName + ":" + fmt::format("{}",OpenWifi::Now()) + ":" + std::to_string(rand()));
[[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) {
std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)));
HMAC_.update(Identity);
return Poco::DigestEngine::digestToHex(HMAC_.digest());
}
@@ -318,11 +163,33 @@ namespace OpenWifi {
T.payload().set("identity", Identity);
T.setIssuedAt(Poco::Timestamp());
T.setExpiration(Poco::Timestamp() + (long long)TokenAging_);
std::string JWT = MicroService::instance().Sign(T,Poco::JWT::Signer::ALGO_RS256);
std::string JWT = Signer_.sign(T,Poco::JWT::Signer::ALGO_RS256);
return JWT;
}
bool AuthService::ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
std::lock_guard Guard(Mutex_);
try {
auto E = UserCache_.find(SessionToken);
if(E == UserCache_.end()) {
if(StorageService()->GetToken(SessionToken,UInfo)) {
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
} else {
UInfo = E->second;
return true;
}
} catch (const Poco::Exception &E ) {
Logger_.log(E);
}
return false;
}
void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
{
std::lock_guard Guard(Mutex_);
@@ -333,170 +200,50 @@ namespace OpenWifi {
UInfo.webtoken.expires_in_ = TokenAging_ ;
UInfo.webtoken.idle_timeout_ = 5 * 60;
UInfo.webtoken.token_type_ = "Bearer";
UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM);
UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME);
UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME);
UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,CUSTOM);
UInfo.webtoken.created_ = time(nullptr);
UInfo.webtoken.username_ = UserName;
UInfo.webtoken.errorCode = 0;
UInfo.webtoken.userMustChangePassword = false;
StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id);
StorageService()->UserTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
UserCache_[UInfo.webtoken.access_token_] = UInfo;
StorageService()->SetLastLogin(UInfo.userinfo.Id);
StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_,
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
StorageService()->LoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ );
}
void AuthService::CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
{
std::lock_guard Guard(Mutex_);
SecurityObjects::AclTemplate ACL;
ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
UInfo.webtoken.acl_template_ = ACL;
UInfo.webtoken.expires_in_ = TokenAging_ ;
UInfo.webtoken.idle_timeout_ = 5 * 60;
UInfo.webtoken.token_type_ = "Bearer";
UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM);
UInfo.webtoken.created_ = time(nullptr);
UInfo.webtoken.username_ = UserName;
UInfo.webtoken.errorCode = 0;
UInfo.webtoken.userMustChangePassword = false;
StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
StorageService()->SubTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
StorageService()->SubLoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ );
}
bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
std::lock_guard G(Mutex_);
Poco::toLowerInPlace(UInfo.email);
for (const auto &i:UInfo.lastPasswords) {
auto Tokens = Poco::StringTokenizer(i,"|");
if(Tokens.count()==2) {
const auto & Salt = Tokens[0];
for(const auto &j:UInfo.lastPasswords) {
auto OldTokens = Poco::StringTokenizer(j,"|");
if(OldTokens.count()==2) {
SHA2_.update(Salt+NewPassword+UInfo.email);
if(OldTokens[1]==Utils::ToHex(SHA2_.digest()))
auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword);
for (auto const &i:UInfo.lastPasswords) {
if (i == NewPasswordHash) {
return false;
}
}
} else {
SHA2_.update(NewPassword+UInfo.email);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
}
auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
UInfo.lastPasswords.push_back(NewHash);
UInfo.currentPassword = NewHash;
UInfo.lastPasswords.push_back(NewPasswordHash);
UInfo.currentPassword = NewPasswordHash;
UInfo.changePassword = false;
return true;
}
bool AuthService::SetSubPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
std::lock_guard G(Mutex_);
Poco::toLowerInPlace(UInfo.email);
for (const auto &i:UInfo.lastPasswords) {
auto Tokens = Poco::StringTokenizer(i,"|");
if(Tokens.count()==2) {
const auto & Salt = Tokens[0];
for(const auto &j:UInfo.lastPasswords) {
auto OldTokens = Poco::StringTokenizer(j,"|");
if(OldTokens.count()==2) {
SHA2_.update(Salt+NewPassword+UInfo.email);
if(OldTokens[1]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
} else {
SHA2_.update(NewPassword+UInfo.email);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
}
auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
UInfo.lastPasswords.push_back(NewHash);
UInfo.currentPassword = NewHash;
UInfo.changePassword = false;
return true;
}
static std::string GetMeSomeSalt() {
auto start = std::chrono::high_resolution_clock::now();
return std::to_string(start.time_since_epoch().count());
}
std::string AuthService::ComputeNewPasswordHash(const std::string &UserName, const std::string &Password) {
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Salt = GetMeSomeSalt();
SHA2_.update(Salt + Password + UName );
return Salt + "|" + Utils::ToHex(SHA2_.digest());
}
bool AuthService::ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
std::lock_guard G(Mutex_);
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Tokens = Poco::StringTokenizer(StoredPassword,"|");
if(Tokens.count()==1) {
SHA2_.update(Password+UName);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return true;
} else if (Tokens.count()==2) {
SHA2_.update(Tokens[0]+Password+UName);
if(Tokens[1]==Utils::ToHex(SHA2_.digest()))
return true;
}
return false;
}
bool AuthService::ValidateSubPasswordHash(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 , [[maybe_unused]] bool & Expired )
AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo )
{
std::lock_guard Guard(Mutex_);
SecurityObjects::AclTemplate ACL;
Poco::toLowerInPlace(UserName);
auto PasswordHash = ComputePasswordHash(UserName, Password);
if(StorageService()->UserDB().GetUserByEmail(UserName,UInfo.userinfo)) {
if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION;
}
if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
if(PasswordHash != UInfo.userinfo.currentPassword) {
return INVALID_CREDENTIALS;
}
@@ -514,124 +261,64 @@ namespace OpenWifi {
UInfo.webtoken.errorCode = 1;
return PASSWORD_ALREADY_USED;
}
UInfo.userinfo.lastPasswordChange = OpenWifi::Now();
UInfo.userinfo.lastPasswordChange = std::time(nullptr);
UInfo.userinfo.changePassword = false;
UInfo.userinfo.modified = OpenWifi::Now();
StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo);
StorageService()->UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.Id,UInfo.userinfo);
}
// so we have a good password, password up date has taken place if need be, now generate the token.
UInfo.userinfo.lastLogin=OpenWifi::Now();
StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id);
UInfo.userinfo.lastLogin=std::time(nullptr);
StorageService()->SetLastLogin(UInfo.userinfo.Id);
CreateToken(UserName, UInfo );
return SUCCESS;
}
return INVALID_CREDENTIALS;
}
UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired )
if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_)
{
std::lock_guard Guard(Mutex_);
Poco::toLowerInPlace(UserName);
if(StorageService()->SubDB().GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION;
}
if(!ValidateSubPasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
return INVALID_CREDENTIALS;
}
if(UInfo.userinfo.changePassword && NewPassword.empty()) {
UInfo.webtoken.userMustChangePassword = true ;
return PASSWORD_CHANGE_REQUIRED;
}
if(!NewPassword.empty() && !ValidateSubPassword(NewPassword)) {
return PASSWORD_INVALID;
}
if(UInfo.userinfo.changePassword || !NewPassword.empty()) {
if(!SetSubPassword(NewPassword,UInfo.userinfo)) {
UInfo.webtoken.errorCode = 1;
return PASSWORD_ALREADY_USED;
}
UInfo.userinfo.lastPasswordChange = OpenWifi::Now();
UInfo.userinfo.changePassword = false;
UInfo.userinfo.modified = OpenWifi::Now();
StorageService()->SubDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo);
}
// so we have a good password, password update has taken place if need be, now generate the token.
UInfo.userinfo.lastLogin=OpenWifi::Now();
StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
CreateSubToken(UserName, UInfo );
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;
}
bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Challenge) {
auto OperatorParts = Poco::StringTokenizer(UInfo.userinfo.signingUp,":");
if(UInfo.userinfo.signingUp.empty() || OperatorParts.count()!=2) {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
Attrs[LOGO] = AuthService::GetLogoAssetURI();
Attrs[SUBJECT] = "Login validation code";
Attrs[CHALLENGE_CODE] = Challenge;
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs);
} else {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
Attrs[LOGO] = AuthService::GetLogoAssetURI();
Attrs[SUBJECT] = "Login validation code";
Attrs[CHALLENGE_CODE] = Challenge;
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,OperatorParts[0]), Attrs);
}
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(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason) {
bool AuthService::SendEmailToUser(std::string &Email, EMAIL_REASON Reason) {
SecurityObjects::UserInfo UInfo;
if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) {
if(StorageService()->GetUserByEmail(Email,UInfo)) {
switch (Reason) {
case MessagingTemplates::FORGOT_PASSWORD: {
case FORGOT_PASSWORD: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=password_reset&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs);
Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
}
break;
case MessagingTemplates::EMAIL_VERIFICATION: {
case EMAIL_VERIFICATION: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "e-mail Address Verification";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_verification&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs);
UInfo.waitingForEmailCheck = true;
}
break;
case MessagingTemplates::EMAIL_INVITATION: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "e-mail Invitation";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_invitation&id=" + LinkId ;
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_invitation&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_INVITATION), Attrs);
Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true;
}
break;
@@ -639,130 +326,33 @@ namespace OpenWifi {
default:
break;
}
return true;
}
return false;
}
bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName ) {
SecurityObjects::UserInfo UInfo;
if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) {
switch (Reason) {
case MessagingTemplates::SUB_FORGOT_PASSWORD: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_password_reset&id=" + LinkId ;
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_password_reset&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD, OperatorName), Attrs);
}
break;
case MessagingTemplates::SUB_EMAIL_VERIFICATION: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "e-mail Address Verification";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_email_verification&id=" + LinkId ;
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_email_verification&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION, OperatorName), Attrs);
UInfo.waitingForEmailCheck = true;
}
break;
case MessagingTemplates::SIGNUP_VERIFICATION: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "Signup e-mail Address Verification";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ;
Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=signup_verification&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SIGNUP_VERIFICATION, OperatorName), Attrs);
UInfo.waitingForEmailCheck = true;
}
break;
default:
break;
}
return true;
}
return false;
}
bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
SecurityObjects::ActionLink A;
MessageAttributes Attrs;
A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
A.userId = UInfo.id;
A.id = MicroService::CreateUUID();
A.created = OpenWifi::Now();
A.expires = A.created + 24*60*60;
A.userAction = true;
StorageService()->ActionLinksDB().CreateAction(A);
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] =
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true;
UInfo.validated = false;
return true;
}
bool AuthService::VerifySubEmail(SecurityObjects::UserInfo &UInfo) {
SecurityObjects::ActionLink A;
A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL;
A.userId = UInfo.id;
A.id = MicroService::CreateUUID();
A.created = OpenWifi::Now();
A.expires = A.created + 24*60*60;
A.userAction = false;
StorageService()->ActionLinksDB().CreateAction(A);
UInfo.waitingForEmailCheck = true;
UInfo.validated = false;
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_);
Expired = false;
auto It = UserCache_.find(Token);
std::string TToken{Token}, UserId;
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0)
if(It==UserCache_.end())
return false;
Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now();
if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) {
WebToken = WT;
WebToken = It->second.webtoken;
UserInfo = It->second.userinfo;
return true;
}
return false;
}
// return IsValidSubToken(Token, WebToken, UserInfo, Expired);
return false;
}
bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
std::lock_guard G(Mutex_);
Expired = false;
std::string TToken{Token}, UserId;
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now();
if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) {
WebToken = WT;
return true;
}
return false;
}
return false;
}
} // end of namespace

View File

@@ -11,8 +11,6 @@
#include <regex>
#include "framework/MicroService.h"
#include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
@@ -20,10 +18,9 @@
#include "Poco/SHA2Engine.h"
#include "Poco/Crypto/DigestEngine.h"
#include "Poco/HMACEngine.h"
#include "Poco/ExpireLRUCache.h"
#include "framework/MicroService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "MessagingTemplates.h"
namespace OpenWifi{
@@ -38,97 +35,71 @@ namespace OpenWifi{
CUSTOM
};
enum AUTH_ERROR {
SUCCESS,
PASSWORD_CHANGE_REQUIRED,
INVALID_CREDENTIALS,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR
};
enum EMAIL_REASON {
FORGOT_PASSWORD,
EMAIL_VERIFICATION
};
static ACCESS_TYPE IntToAccessType(int C);
static int AccessTypeToInt(ACCESS_TYPE T);
static auto instance() {
static auto instance_ = new AuthService;
static AuthService *instance() {
if (instance_ == nullptr) {
instance_ = new AuthService;
}
return instance_;
}
int Start() override;
void Stop() override;
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
[[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
[[nodiscard]] 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);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo );
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
void Logout(const std::string &token, bool EraseFromCache=true);
[[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;};
void SubLogout(const std::string &token, bool EraseFromCache=true);
void RemoveTokenSystemWide(const std::string &token);
bool ValidatePassword(const std::string &pwd);
bool ValidateSubPassword(const std::string &pwd);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
[[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo);
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
[[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password);
[[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
[[nodiscard]] bool ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::WebToken & UserInfo );
[[nodiscard]] std::string ComputePasswordHash(const std::string &UserName, const std::string &Password);
[[nodiscard]] 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]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
[[nodiscard]] std::string ResetSubPassword(const std::string &Admin, const std::string &UserName);
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason);
[[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName);
[[nodiscard]] static bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason);
[[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code);
bool DeleteUserFromCache(const std::string &UserName);
bool DeleteSubUserFromCache(const std::string &UserName);
void RevokeToken(std::string & Token);
void RevokeSubToken(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";
}
inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; }
bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
private:
static AuthService *instance_;
bool Secure_ = false ;
std::string DefaultUserName_;
std::string DefaultPassword_;
std::string Mechanism_;
Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_;
std::string AccessPolicy_;
std::string PasswordPolicy_;
std::string SubAccessPolicy_;
std::string SubPasswordPolicy_;
SecurityObjects::UserInfoCache UserCache_;
std::string PasswordValidationStr_;
std::string SubPasswordValidationStr_;
std::regex PasswordValidation_;
std::regex SubPasswordValidation_;
uint64_t TokenAging_ = 15 * 24 * 60 * 60;
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
uint64_t HowManyOldPassword_=5;
uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ;
class SHA256Engine : public Poco::Crypto::DigestEngine
{
@@ -154,13 +125,10 @@ namespace OpenWifi{
}
};
inline auto AuthService() { return AuthService::instance(); }
inline AuthService * AuthService() { return AuthService::instance(); }
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , std::uint64_t TID, bool & Expired, bool Sub ) {
if(Sub)
return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, TID, Expired );
else
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, TID, Expired );
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
return AuthService()->IsAuthorized(Request, SessionToken, UInfo );
}
} // end of namespace

View File

@@ -10,6 +10,8 @@
// Arilia Wireless Inc.
//
#include <cstdlib>
#include <boost/algorithm/string.hpp>
#include "Poco/Util/Application.h"
#include "Poco/Util/Option.h"
@@ -18,14 +20,16 @@
#include "Daemon.h"
#include <aws/core/Aws.h>
#include <aws/s3/model/CreateBucketRequest.h>
#include <aws/s3/model/PutObjectRequest.h>
#include <aws/s3/model/AccessControlPolicy.h>
#include <aws/s3/model/PutBucketAclRequest.h>
#include <aws/s3/model/GetBucketAclRequest.h>
#include "StorageService.h"
#include "SMTPMailerService.h"
#include "AuthService.h"
#include "SMSSender.h"
#include "ActionLinkManager.h"
#include "TotpCache.h"
namespace OpenWifi {
class Daemon *Daemon::instance_ = nullptr;
@@ -40,18 +44,21 @@ namespace OpenWifi {
SubSystemVec{
StorageService(),
SMSSender(),
ActionLinkManager(),
SMTPMailerService(),
RESTAPI_RateLimiter(),
TotpCache(),
AuthService()
});
}
return instance_;
}
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
void Daemon::initialize() {
AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html");
PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html");
}
void MicroServicePostInitialization() {
Daemon()->initialize();
}
}

View File

@@ -10,8 +10,6 @@
#include <vector>
#include <set>
#include "framework/MicroService.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
@@ -22,14 +20,16 @@
#include "Poco/Crypto/CipherFactory.h"
#include "Poco/Crypto/Cipher.h"
#include "framework/OpenWifiTypes.h"
#include "framework/MicroService.h"
namespace OpenWifi {
[[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties";
[[maybe_unused]] static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT";
[[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG";
[[maybe_unused]] static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str();
[[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000;
static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties";
static const char * vDAEMON_ROOT_ENV_VAR = "OWSEC_ROOT";
static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG";
static const char * vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str();
static const uint64_t vDAEMON_BUS_TIMER = 5000;
class Daemon : public MicroService {
public:
@@ -41,18 +41,19 @@ namespace OpenWifi {
const SubSystemVec & SubSystems) :
MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
void PostInitialization(Poco::Util::Application &self);
void initialize();
static Daemon *instance();
inline const std::string & AssetDir() { return AssetDir_; }
inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
private:
static Daemon *instance_;
std::string AssetDir_;
std::string PasswordPolicy_;
std::string AccessPolicy_;
};
inline Daemon * Daemon() { return Daemon::instance(); }
inline void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
}
}
#endif //UCENTRALSEC_DAEMON_H

View File

@@ -2,16 +2,15 @@
// Created by stephane bourque on 2021-10-11.
//
#include "framework/MicroService.h"
#include "MFAServer.h"
#include "SMSSender.h"
#include "SMTPMailerService.h"
#include "AuthService.h"
#include "TotpCache.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class MFAServer * MFAServer::instance_ = nullptr;
int MFAServer::Start() {
return 0;
}
@@ -28,12 +27,11 @@ namespace OpenWifi {
return false;
std::string Challenge = MakeChallenge();
std::string uuid = MicroService::CreateUUID();
uint64_t Created = OpenWifi::Now();
std::string uuid = MicroService::instance().CreateUUID();
uint64_t Created = std::time(nullptr);
ChallengeStart.set("uuid",uuid);
ChallengeStart.set("created", Created);
ChallengeStart.set("question", "mfa challenge");
ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method };
@@ -41,13 +39,18 @@ namespace OpenWifi {
}
bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) {
if(Method==MFAMETHODS::SMS && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
if(Method=="sms" && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen.";
return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message);
} else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
return AuthService()->SendEmailChallengeCode(UInfo,Challenge);
} else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
return true;
}
if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
Attrs[LOGO] = "logo.jpg";
Attrs[SUBJECT] = "Login validation code";
Attrs[CHALLENGE_CODE] = Challenge;
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
}
return false;
@@ -61,7 +64,7 @@ namespace OpenWifi {
return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
}
bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) {
bool MFAServer::CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) {
std::lock_guard G(Mutex_);
if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
@@ -69,17 +72,11 @@ namespace OpenWifi {
auto uuid = ChallengeResponse->get("uuid").toString();
auto Hint = Cache_.find(uuid);
if(Hint == end(Cache_)) {
if(Hint == end(Cache_))
return false;
}
auto answer = ChallengeResponse->get("answer").toString();
std::string Expecting;
if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) {
if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) {
return false;
}
} else if(Hint->second.Answer!=answer) {
if(Hint->second.Answer!=answer) {
return false;
}
@@ -89,21 +86,18 @@ namespace OpenWifi {
}
bool MFAServer::MethodEnabled(const std::string &Method) {
if(Method==MFAMETHODS::SMS)
if(Method=="sms")
return SMSSender()->Enabled();
if(Method==MFAMETHODS::EMAIL)
if(Method=="email")
return SMTPMailerService()->Enabled();
if(Method==MFAMETHODS::AUTHENTICATOR)
return true;
return false;
}
void MFAServer::CleanCache() {
// it is assumed that you have locked Cache_ at this point.
uint64_t Now = OpenWifi::Now();
uint64_t Now = std::time(nullptr);
for(auto i=begin(Cache_);i!=end(Cache_);) {
if((Now-i->second.Created)>300) {
i = Cache_.erase(i);

View File

@@ -2,24 +2,14 @@
// Created by stephane bourque on 2021-10-11.
//
#pragma once
#ifndef OWSEC_MFASERVER_H
#define OWSEC_MFASERVER_H
#include "framework/MicroService.h"
#include "Poco/JSON/Object.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
namespace MFAMETHODS {
inline const static std::string SMS{"sms"};
inline const static std::string EMAIL{"email"};
inline const static std::string AUTHENTICATOR{"authenticator"};
inline const static std::vector<std::string> Methods{ SMS, EMAIL, AUTHENTICATOR };
inline bool Validate(const std::string &M) {
return std::find(cbegin(Methods), cend(Methods),M)!=Methods.end();
}
}
struct MFACacheEntry {
SecurityObjects::UserInfoAndPolicy UInfo;
std::string Answer;
@@ -27,29 +17,31 @@ namespace OpenWifi {
std::string Method;
};
typedef std::map<std::string,MFACacheEntry> MFAChallengeCache;
class MFAServer : public SubSystemServer{
public:
int Start() override;
void Stop() override;
static auto instance() {
static auto instance_ = new MFAServer;
static MFAServer *instance() {
if (instance_ == nullptr) {
instance_ = new MFAServer;
}
return instance_;
}
bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
static bool MethodEnabled(const std::string &Method);
bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
bool MethodEnabled(const std::string &Method);
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() {
return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) );
return std::to_string(rand() % 999999);
}
private:
static MFAServer * instance_;
MFAChallengeCache Cache_;
MFAServer() noexcept:
SubSystemServer("MFServer", "MFA-SVR", "mfa")
@@ -59,6 +51,7 @@ namespace OpenWifi {
void CleanCache();
};
inline auto MFAServer() { return MFAServer::instance(); }
inline MFAServer & MFAServer() { return *MFAServer::instance(); }
}
#endif //OWSEC_MFASERVER_H

View File

@@ -1,8 +0,0 @@
//
// Created by stephane bourque on 2022-07-25.
//
#include "MessagingTemplates.h"
namespace OpenWifi {
} // OpenWifi

View File

@@ -1,75 +0,0 @@
//
// Created by stephane bourque on 2022-07-25.
//
#pragma once
#include <string>
#include <vector>
namespace OpenWifi {
class MessagingTemplates {
public:
static MessagingTemplates & instance() {
static auto instance = new MessagingTemplates;
return *instance;
}
enum EMAIL_REASON {
FORGOT_PASSWORD = 0,
EMAIL_VERIFICATION,
SIGNUP_VERIFICATION,
EMAIL_INVITATION,
VERIFICATION_CODE,
SUB_FORGOT_PASSWORD,
SUB_EMAIL_VERIFICATION,
SUB_VERIFICATION_CODE
};
static std::string AddOperator(const std::string & filename, const std::string &OperatorName) {
if(OperatorName.empty())
return "/" + filename;
return "/" + OperatorName + "/" + filename;
}
static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") {
switch (r) {
case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName);
case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName);
case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName);
case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName);
case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName);
case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName);
case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName);
case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName);
default:
return "";
}
}
static std::string Logo(const std::string &OperatorName = "" ) {
return AddOperator("logo.jpg", OperatorName);
}
static std::string SubLogo(const std::string &OperatorName = "" ) {
return AddOperator("sub_logo.jpg", OperatorName);
}
private:
inline const static std::vector<std::string> EmailTemplateNames = {
"password_reset",
"email_verification",
"signup_verification",
"email_invitation",
"verification_code",
"sub_password_reset",
"sub_email_verification",
"sub_verification_code"
};
};
inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); }
} // OpenWifi

View File

@@ -2,13 +2,13 @@
// Created by stephane bourque on 2021-07-10.
//
#include "RESTAPI_asset_server.h"
#include "RESTAPI_AssetServer.h"
#include "Poco/File.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_protocol.h"
#include "Daemon.h"
namespace OpenWifi {
void RESTAPI_asset_server::DoGet() {
void RESTAPI_AssetServer::DoGet() {
Poco::File AssetFile;
if(Request->getURI().find("/favicon.ico") != std::string::npos) {

View File

@@ -2,14 +2,15 @@
// Created by stephane bourque on 2021-07-10.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_ASSETSERVER_H
#define UCENTRALSEC_RESTAPI_ASSETSERVER_H
#include "../framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_asset_server : public RESTAPIHandler {
class RESTAPI_AssetServer : public RESTAPIHandler {
public:
RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_AssetServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_POST,
@@ -18,9 +19,8 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal, false) {}
static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" ,
static const std::list<const char *> PathName() { return std::list<const char *>{"/wwwassets/{id}" ,
"/favicon.ico"}; };
void DoGet() final;
void DoPost() final {};
@@ -32,3 +32,5 @@ namespace OpenWifi {
};
}
#endif //UCENTRALSEC_RESTAPI_ASSETSERVER_H

View File

@@ -11,81 +11,46 @@
#include "Daemon.h"
namespace OpenWifi {
void RESTAPI_action_links::DoGet() {
auto Action = GetParameter("action","");
auto Id = GetParameter("id","");
SecurityObjects::ActionLink Link;
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
return DoReturnA404();
if(Action=="password_reset")
return RequestResetPassword(Link);
else if(Action=="sub_password_reset")
return RequestSubResetPassword(Link);
return RequestResetPassword(Id);
else if(Action=="email_verification")
return DoEmailVerification(Link);
else if(Action=="sub_email_verification")
return DoSubEmailVerification(Link);
else if(Action=="signup_verification")
return DoNewSubVerification(Link);
return DoEmailVerification(Id);
else
return DoReturnA404();
}
void RESTAPI_action_links::DoPost() {
auto Action = GetParameter("action","");
auto Id = GetParameter("id","");
Logger_.information(Poco::format("COMPLETE-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
if(Action=="password_reset")
return CompleteResetPassword();
else if(Action=="sub_password_reset")
return CompleteResetPassword();
else if(Action=="signup_completion")
return CompleteSubVerification();
else if(Action=="email_invitation")
return CompleteEmailInvitation();
CompleteResetPassword(Id);
else
return DoReturnA404();
DoReturnA404();
}
void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId));
void RESTAPI_action_links::RequestResetPassword(std::string &Id) {
Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id));
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
Types::StringPairVec FormVars{ {"UUID", Link.id},
Types::StringPairVec FormVars{ {"UUID", Id},
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
SendHTMLFileBack(FormFile,FormVars);
}
void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}", Request->clientAddress().toString(), Link.userId));
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification.html"};
Types::StringPairVec FormVars{ {"UUID", Link.id},
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
SendHTMLFileBack(FormFile,FormVars);
}
void RESTAPI_action_links::CompleteResetPassword() {
void RESTAPI_action_links::CompleteResetPassword(std::string &Id) {
// form has been posted...
RESTAPI_PartHandler PartHandler;
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
if (!Form.empty()) {
auto Password1 = Form.get("password1","bla");
auto Password2 = Form.get("password2","blu");
auto Id = Form.get("id","");
auto now = OpenWifi::Now();
SecurityObjects::ActionLink Link;
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
return DoReturnA404();
if(now > Link.expires) {
StorageService()->ActionLinksDB().CancelAction(Id);
return DoReturnA404();
}
auto Password2 = Form.get("password1","blu");
Id = Form.get("id","");
if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
@@ -97,9 +62,7 @@ namespace OpenWifi {
}
SecurityObjects::UserInfo UInfo;
bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
if(!Found) {
if(!StorageService()->GetUserById(Id,UInfo)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
@@ -113,156 +76,43 @@ namespace OpenWifi {
return SendHTMLFileBack(FormFile,FormVars);
}
bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo);
if(!GoodPassword) {
if(!AuthService()->SetPassword(Password1,UInfo)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
return SendHTMLFileBack(FormFile,FormVars);
}
UInfo.modified = OpenWifi::Now();
if(Link.userAction)
StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
else
StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
StorageService()->UpdateUserInfo(UInfo.email,Id,UInfo);
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"USERNAME", UInfo.email},
{"ACTION_LINK",MicroService::instance().GetUIURI()}};
StorageService()->ActionLinksDB().CompleteAction(Id);
SendHTMLFileBack(FormFile,FormVars);
} else {
DoReturnA404();
}
}
void RESTAPI_action_links::CompleteSubVerification() {
RESTAPI_PartHandler PartHandler;
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
if (!Form.empty()) {
auto Password1 = Form.get("password1","bla");
auto Password2 = Form.get("password2","blu");
auto Id = Form.get("id","");
auto now = OpenWifi::Now();
SecurityObjects::ActionLink Link;
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) {
return DoReturnA404();
}
if(now > Link.expires) {
StorageService()->ActionLinksDB().CancelAction(Id);
return DoReturnA404();
}
if(Password1!=Password2 || !AuthService()->ValidateSubPassword(Password1)) {
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
" accepted password creation restrictions. Please consult our on-line help"
" to look at the our password policy. If you would like to contact us, please mention"
" id(" + Id + ")"}};
return SendHTMLFileBack(FormFile,FormVars);
}
void RESTAPI_action_links::DoEmailVerification(std::string &Id) {
SecurityObjects::UserInfo UInfo;
bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo);
if(!Found) {
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
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 request does not contain a valid user ID. Please contact your system administrator."}};
return SendHTMLFileBack(FormFile,FormVars);
}
if(UInfo.blackListed || UInfo.suspended) {
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
return SendHTMLFileBack(FormFile,FormVars);
}
bool GoodPassword = AuthService()->SetSubPassword(Password1,UInfo);
if(!GoodPassword) {
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
return SendHTMLFileBack(FormFile,FormVars);
}
UInfo.modified = OpenWifi::Now();
UInfo.changePassword = false;
UInfo.lastEmailCheck = OpenWifi::Now();
UInfo.waitingForEmailCheck = false;
UInfo.validated = OpenWifi::Now();
StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"};
Types::StringPairVec FormVars{ {"UUID", Id},
{"USERNAME", UInfo.email} };
StorageService()->ActionLinksDB().CompleteAction(Id);
// Send the update to the provisioning service
Poco::JSON::Object Body;
auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":");
Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]);
OpenAPIRequestPut ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup",
{
{"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} ,
{"operation", "emailVerified"}
},
Body,30000);
Logger().information(fmt::format("({}): Completed subscriber e-mail verification and password.",UInfo.email));
Poco::JSON::Object::Ptr Response;
auto Status = ProvRequest.Do(Response);
std::stringstream ooo;
if(Response!= nullptr)
Response->stringify(ooo);
Logger().information(fmt::format("({}): Completed subscriber e-mail verification. Provisioning notified, Error={}.",
UInfo.email, Status));
SendHTMLFileBack(FormFile,FormVars);
Logger().information(fmt::format("({}): Completed subscriber e-mail verification. FORM notified.",UInfo.email));
} else {
DoReturnA404();
}
}
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
auto now = OpenWifi::Now();
if(now > Link.expires) {
StorageService()->ActionLinksDB().CancelAction(Link.id);
return DoReturnA404();
}
SecurityObjects::UserInfo UInfo;
bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
if (!Found) {
Types::StringPairVec FormVars{{"UUID", Link.id},
{"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
return SendHTMLFileBack(FormFile, FormVars);
}
Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(),
UInfo.email));
UInfo.waitingForEmailCheck = false;
UInfo.validated = true;
UInfo.lastEmailCheck = OpenWifi::Now();
UInfo.validationDate = OpenWifi::Now();
UInfo.modified = OpenWifi::Now();
if(Link.userAction)
StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
else
StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
Types::StringPairVec FormVars{{"UUID", Link.id},
UInfo.lastEmailCheck = std::time(nullptr);
UInfo.validationDate = std::time(nullptr);
StorageService()->UpdateUserInfo(UInfo.email, Id, UInfo);
Types::StringPairVec FormVars{{"UUID", Id},
{"USERNAME", UInfo.email},
{"ACTION_LINK",MicroService::instance().GetUIURI()}};
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
StorageService()->ActionLinksDB().CompleteAction(Link.id);
SendHTMLFileBack(FormFile, FormVars);
}
@@ -272,16 +122,4 @@ namespace OpenWifi {
SendHTMLFileBack(FormFile, FormVars);
}
void RESTAPI_action_links::CompleteEmailInvitation() {
/// TODO:
}
void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) {
}
void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) {
}
}

View File

@@ -2,34 +2,29 @@
// Created by stephane bourque on 2021-06-22.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_ACTION_LINKS_H
#define UCENTRALSEC_RESTAPI_ACTION_LINKS_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_action_links : public RESTAPIHandler {
public:
RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal,
false,
true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
void RequestResetPassword(SecurityObjects::ActionLink &Link);
void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
void CompleteResetPassword();
void CompleteSubVerification();
void DoEmailVerification(SecurityObjects::ActionLink &Link);
void DoSubEmailVerification(SecurityObjects::ActionLink &Link);
false) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
void RequestResetPassword(std::string &Id);
void CompleteResetPassword(std::string &Id);
void DoEmailVerification(std::string &Id);
void DoReturnA404();
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
void CompleteEmailInvitation();
void DoGet() final;
void DoPost() final;
@@ -37,3 +32,5 @@ namespace OpenWifi {
void DoPut() final {};
};
}
#endif //UCENTRALSEC_RESTAPI_ACTION_LINKS_H

View File

@@ -5,9 +5,10 @@
#include <fstream>
#include <iostream>
#include "RESTAPI_avatar_handler.h"
#include "RESTAPI_avatarHandler.h"
#include "StorageService.h"
#include "Poco/Net/HTMLForm.h"
#include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h"
namespace OpenWifi {
@@ -21,27 +22,33 @@ namespace OpenWifi {
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
}
Poco::CountingInputStream InputStream(Stream);
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
Length_ = OutputStream_.str().size();
std::ofstream OutputStream(TempFile_.path(), std::ofstream::out);
Poco::StreamCopier::copyStream(InputStream, OutputStream);
Length_ = InputStream.chars();
};
void RESTAPI_avatar_handler::DoPost() {
std::string Id = UserInfo_.userinfo.id;
void RESTAPI_avatarHandler::DoPost() {
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
SecurityObjects::UserInfo UInfo;
std::stringstream SS;
AvatarPartHandler partHandler(Id, Logger_, SS);
if (Id.empty() || !StorageService()->GetUserById(Id, UInfo)) {
return NotFound();
}
// if there is an avatar, just remove it...
StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id);
Poco::TemporaryFile TmpFile;
AvatarPartHandler partHandler(Id, Logger_, TmpFile);
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
Poco::JSON::Object Answer;
if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
Answer.set(RESTAPI::Protocol::AVATARID, Id);
Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email,
Id, SS.str(), partHandler.ContentType(), partHandler.Name());
StorageService()->UserDB().SetAvatar(Id,"1");
Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email));
Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType()));
StorageService()->SetAvatar(UserInfo_.userinfo.email,
Id, TmpFile, partHandler.ContentType(), partHandler.Name());
} else {
Answer.set(RESTAPI::Protocol::AVATARID, Id);
Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
@@ -50,33 +57,27 @@ namespace OpenWifi {
ReturnObject(Answer);
}
void RESTAPI_avatar_handler::DoGet() {
void RESTAPI_avatarHandler::DoGet() {
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
if (Id.empty()) {
return NotFound();
}
std::string Type, Name, AvatarContent;
if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
Poco::TemporaryFile TempAvatar;
std::string Type, Name;
if (!StorageService()->GetAvatar(UserInfo_.userinfo.email, Id, TempAvatar, Type, Name)) {
return NotFound();
}
Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size()));
return SendFileContent(AvatarContent, Type, Name);
SendFile(TempAvatar, Type, Name);
}
void RESTAPI_avatar_handler::DoDelete() {
void RESTAPI_avatarHandler::DoDelete() {
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
if (Id.empty()) {
return NotFound();
}
if (!StorageService()->DeleteAvatar(UserInfo_.userinfo.email, Id)) {
return NotFound();
}
Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
StorageService()->UserDB().SetAvatar(Id,"");
OK();
}
}

View File

@@ -1,7 +1,10 @@
//
// Created by stephane bourque on 2021-07-15.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_AVATARHANDLER_H
#define UCENTRALSEC_RESTAPI_AVATARHANDLER_H
#include "framework/MicroService.h"
@@ -9,30 +12,28 @@ namespace OpenWifi {
class AvatarPartHandler : public Poco::Net::PartHandler {
public:
AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
AvatarPartHandler(std::string Id, Poco::Logger &Logger, Poco::TemporaryFile &TmpFile) :
Id_(std::move(Id)),
Logger_(Logger),
OutputStream_(ofs){
TempFile_(TmpFile){
}
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
[[nodiscard]] uint64_t Length() const { return Length_; }
[[nodiscard]] std::string &Name() { return Name_; }
[[nodiscard]] std::string &ContentType() { return FileType_; }
[[nodiscard]] std::string FileName() const { return TempFile_.path(); }
private:
uint64_t Length_ = 0;
std::string FileType_;
std::string Name_;
std::string Id_;
Poco::Logger &Logger_;
std::stringstream &OutputStream_;
inline Poco::Logger & Logger() { return Logger_; };
Poco::TemporaryFile &TempFile_;
};
class RESTAPI_avatar_handler : public RESTAPIHandler {
class RESTAPI_avatarHandler : public RESTAPIHandler {
public:
RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_avatarHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,
@@ -40,9 +41,8 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/avatar/{id}"}; };
void DoGet() final;
void DoPost() final;
@@ -51,3 +51,4 @@ namespace OpenWifi {
};
}
#endif //UCENTRALSEC_RESTAPI_AVATARHANDLER_H

View File

@@ -1,17 +0,0 @@
//
// Created by stephane bourque on 2022-01-01.
//
#pragma once
#include "framework/orm.h"
namespace OpenWifi {
inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
}

View File

@@ -9,12 +9,12 @@
#include "Poco/JSON/Parser.h"
#include "SMTPMailerService.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/MicroService.h"
namespace OpenWifi {
void RESTAPI_email_handler::DoPost() {
const auto & Obj = ParsedBody_;
auto Obj = ParseStream();
if (Obj->has("subject") &&
Obj->has("from") &&
Obj->has("text") &&

View File

@@ -2,24 +2,27 @@
// Created by stephane bourque on 2021-09-02.
//
#pragma once
#ifndef OWSEC_RESTAPI_EMAIL_HANDLER_H
#define OWSEC_RESTAPI_EMAIL_HANDLER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_email_handler : public RESTAPIHandler {
public:
RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/email"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/email"};}
void DoGet() final {};
void DoPost() final;
void DoDelete() final {};
void DoPut() final {};
};
}
#endif //OWSEC_RESTAPI_EMAIL_HANDLER_H

View File

@@ -0,0 +1,125 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#include "Poco/JSON/Parser.h"
#include "Daemon.h"
#include "AuthService.h"
#include "RESTAPI_oauth2Handler.h"
#include "MFAServer.h"
#include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h"
namespace OpenWifi {
void RESTAPI_oauth2Handler::DoGet() {
if (!IsAuthorized()) {
return UnAuthorized("Not authorized.");
}
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
if(GetMe) {
Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
Poco::JSON::Object Me;
UserInfo_.userinfo.to_json(Me);
return ReturnObject(Me);
}
BadRequest("Ill-formed request. Please consult documentation.");
}
void RESTAPI_oauth2Handler::DoDelete() {
if (!IsAuthorized()) {
return UnAuthorized("Not authorized.");
}
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
if (Token == SessionToken_) {
AuthService()->Logout(Token);
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
}
Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
NotFound();
}
void RESTAPI_oauth2Handler::DoPost() {
auto Obj = ParseStream();
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
Poco::toLowerInPlace(userId);
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) {
Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString()));
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, Daemon()->GetAccessPolicy());
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, Daemon()->GetPasswordPolicy());
return ReturnObject(Answer);
}
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
// Send an email to the userId
Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
SecurityObjects::UserInfoAndPolicy UInfo;
if(AuthService::SendEmailToUser(userId,AuthService::FORGOT_PASSWORD))
Logger_.information(Poco::format("Send password reset link to %s",userId));
UInfo.webtoken.userMustChangePassword=true;
Poco::JSON::Object ReturnObj;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) {
Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
auto uuid = Obj->get("uuid").toString();
if(MFAServer().ResendCode(uuid))
return OK();
return UnAuthorized("Unrecognized credentials (username/password).");
}
return UnAuthorized("Unrecognized credentials (username/password).");
}
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
SecurityObjects::UserInfoAndPolicy UInfo;
if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
Poco::JSON::Object ReturnObj;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
}
return UnAuthorized("Unrecognized credentials (username/password).");
}
SecurityObjects::UserInfoAndPolicy UInfo;
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo);
if (Code==AuthService::SUCCESS) {
Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) {
if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
return ReturnObject(ReturnObj);
}
Logger_.warning("MFA Seems ot be broken. Please fix. Disabling MFA checking for now.");
}
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
} else {
switch(Code) {
case AuthService::INVALID_CREDENTIALS: return UnAuthorized("Unrecognized credentials (username/password)."); break;
case AuthService::PASSWORD_INVALID: return UnAuthorized("Invalid password."); break;
case AuthService::PASSWORD_ALREADY_USED: return UnAuthorized("Password already used previously."); break;
case AuthService::USERNAME_PENDING_VERIFICATION: return UnAuthorized("User access pending email verification."); break;
case AuthService::PASSWORD_CHANGE_REQUIRED: return UnAuthorized("Password change expected."); break;
default: return UnAuthorized("Unrecognized credentials (username/password)."); break;
}
return;
}
}
}

View File

@@ -6,27 +6,27 @@
// Arilia Wireless Inc.
//
#pragma once
#ifndef UCENTRAL_RESTAPI_OAUTH2HANDLER_H
#define UCENTRAL_RESTAPI_OAUTH2HANDLER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_oauth2_handler : public RESTAPIHandler {
class RESTAPI_oauth2Handler : public RESTAPIHandler {
public:
RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {}
static auto PathName() { return std::list<std::string>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
Internal, false) {}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
void DoGet() final;
void DoPost() final;
void DoDelete() final;
void DoPut() final {};
};
}
#endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H

View File

@@ -1,178 +0,0 @@
//
// License type: BSD 3-Clause License
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
//
#include "Poco/JSON/Parser.h"
#include "AuthService.h"
#include "RESTAPI_oauth2_handler.h"
#include "MFAServer.h"
#include "framework/ow_constants.h"
#include "framework/MicroService.h"
#include "StorageService.h"
#include "RESTAPI_db_helpers.h"
namespace OpenWifi {
void RESTAPI_oauth2_handler::DoGet() {
bool Expired = false, Contacted = false;
if (!IsAuthorized(Expired, Contacted)) {
if (Expired)
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
}
if (GetBoolParameter(RESTAPI::Protocol::ME)) {
Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
UserInfo_.userinfo.email));
Poco::JSON::Object Me;
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
Sanitize(UserInfo_, ReturnedUser);
ReturnedUser.to_json(Me);
return ReturnObject(Me);
}
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
}
void RESTAPI_oauth2_handler::DoDelete() {
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
std::string SessionToken;
try {
Poco::Net::OAuth20Credentials Auth(*Request);
if (Auth.getScheme() == "Bearer") {
SessionToken = Auth.getBearerToken();
}
} catch (const Poco::Exception &E) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if (Token.empty() || (Token != SessionToken)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
AuthService()->Logout(Token);
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
}
void RESTAPI_oauth2_handler::DoPost() {
const auto & Obj = ParsedBody_;
if(Obj == nullptr) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
auto refreshToken = GetS("refreshToken", Obj);
auto grant_type = GetParameter("grant_type");
Poco::toLowerInPlace(userId);
if(!refreshToken.empty() && grant_type == "refresh_token") {
SecurityObjects::UserInfoAndPolicy UInfo;
if(AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) {
Poco::JSON::Object Answer;
UInfo.webtoken.to_json(Answer);
return ReturnObject(Answer);
} else {
return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
}
}
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
return ReturnObject(Answer);
}
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
SecurityObjects::UserInfo UInfo1;
auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1);
if(UserExists) {
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
NewLink.id = MicroService::CreateUUID();
NewLink.userId = UInfo1.id;
NewLink.created = OpenWifi::Now();
NewLink.expires = NewLink.created + (24*60*60);
NewLink.userAction = true;
StorageService()->ActionLinksDB().CreateAction(NewLink);
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
} else {
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
}
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
auto uuid = Obj->get("uuid").toString();
if(MFAServer()->ResendCode(uuid))
return OK();
}
return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
}
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
SecurityObjects::UserInfoAndPolicy UInfo;
if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) {
Poco::JSON::Object ReturnObj;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
}
return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
}
SecurityObjects::UserInfoAndPolicy UInfo;
bool Expired=false;
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
if (Code==SUCCESS) {
Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) {
if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
return ReturnObject(ReturnObj);
}
Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
}
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
} else {
switch(Code) {
case INVALID_CREDENTIALS:
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
case PASSWORD_INVALID:
return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
case PASSWORD_ALREADY_USED:
return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
case USERNAME_PENDING_VERIFICATION:
return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
case PASSWORD_CHANGE_REQUIRED:
return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
default:
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
}
return;
}
}
}

View File

@@ -1,36 +0,0 @@
//
// Created by stephane bourque on 2021-11-16.
//
#include "RESTAPI_preferences.h"
#include "StorageService.h"
namespace OpenWifi {
void RESTAPI_preferences::DoGet() {
SecurityObjects::Preferences P;
Poco::JSON::Object Answer;
StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
P.to_json(Answer);
ReturnObject(Answer);
}
void RESTAPI_preferences::DoPut() {
SecurityObjects::Preferences P;
const auto & RawObject = ParsedBody_;
if(!P.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
P.id = UserInfo_.userinfo.id;
P.modified = OpenWifi::Now();
StorageService()->PreferencesDB().SetPreferences(P);
Poco::JSON::Object Answer;
P.to_json(Answer);
ReturnObject(Answer);
}
}

View File

@@ -1,27 +0,0 @@
//
// Created by stephane bourque on 2021-11-16.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_preferences : public RESTAPIHandler {
public:
RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; };
void DoGet() final;
void DoPut() final;
void DoPost() final {};
void DoDelete() final {};
};
}

View File

@@ -1,88 +0,0 @@
//
// Created by stephane bourque on 2021-10-23.
//
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_oauth2_handler.h"
#include "RESTAPI/RESTAPI_user_handler.h"
#include "RESTAPI/RESTAPI_users_handler.h"
#include "RESTAPI/RESTAPI_action_links.h"
#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
#include "RESTAPI/RESTAPI_asset_server.h"
#include "RESTAPI/RESTAPI_avatar_handler.h"
#include "RESTAPI/RESTAPI_subavatar_handler.h"
#include "RESTAPI/RESTAPI_email_handler.h"
#include "RESTAPI/RESTAPI_sms_handler.h"
#include "RESTAPI/RESTAPI_validate_token_handler.h"
#include "RESTAPI/RESTAPI_preferences.h"
#include "RESTAPI/RESTAPI_subpreferences.h"
#include "RESTAPI/RESTAPI_suboauth2_handler.h"
#include "RESTAPI/RESTAPI_subuser_handler.h"
#include "RESTAPI/RESTAPI_subusers_handler.h"
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
#include "RESTAPI/RESTAPI_submfa_handler.h"
#include "RESTAPI/RESTAPI_totp_handler.h"
#include "RESTAPI/RESTAPI_subtotp_handler.h"
#include "RESTAPI/RESTAPI_signup_handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S,
uint64_t TransactionId) {
return RESTAPI_Router<
RESTAPI_oauth2_handler,
RESTAPI_user_handler,
RESTAPI_users_handler,
RESTAPI_system_command,
RESTAPI_asset_server,
RESTAPI_system_endpoints_handler,
RESTAPI_action_links,
RESTAPI_avatar_handler,
RESTAPI_subavatar_handler,
RESTAPI_email_handler,
RESTAPI_sms_handler,
RESTAPI_preferences,
RESTAPI_subpreferences,
RESTAPI_suboauth2_handler,
RESTAPI_subuser_handler,
RESTAPI_subusers_handler,
RESTAPI_submfa_handler,
RESTAPI_totp_handler,
RESTAPI_subtotp_handler,
RESTAPI_signup_handler,
RESTAPI_validate_sub_token_handler,
RESTAPI_validate_token_handler
>(Path, Bindings, L, S,TransactionId);
}
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
return RESTAPI_Router_I<
RESTAPI_oauth2_handler,
RESTAPI_user_handler,
RESTAPI_users_handler,
RESTAPI_system_command,
RESTAPI_asset_server,
RESTAPI_system_endpoints_handler,
RESTAPI_action_links,
RESTAPI_avatar_handler,
RESTAPI_subavatar_handler,
RESTAPI_email_handler,
RESTAPI_sms_handler,
RESTAPI_preferences,
RESTAPI_subpreferences,
RESTAPI_suboauth2_handler,
RESTAPI_subuser_handler,
RESTAPI_subusers_handler,
RESTAPI_submfa_handler,
RESTAPI_totp_handler,
RESTAPI_subtotp_handler,
RESTAPI_validate_sub_token_handler,
RESTAPI_validate_token_handler,
RESTAPI_signup_handler
>(Path, Bindings, L, S, TransactionId);
}
}

View File

@@ -1,74 +0,0 @@
//
// Created by stephane bourque on 2022-02-20.
//
#include "RESTAPI_signup_handler.h"
#include "StorageService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#define __DBG__ std::cout << __LINE__ << std::endl;
namespace OpenWifi {
void RESTAPI_signup_handler::DoPost() {
auto UserName = GetParameter("email");
auto signupUUID = GetParameter("signupUUID");
auto owner = GetParameter("owner");
auto operatorName = GetParameter("operatorName");
if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) {
Logger().error("Signup requires: email, signupUUID, operatorName, and owner.");
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if(!Utils::ValidEMailAddress(UserName)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
}
// Do we already exist? Can only signup once...
SecurityObjects::UserInfo Existing;
if(StorageService()->SubDB().GetUserByEmail(UserName,Existing)) {
if(Existing.signingUp.empty()) {
return BadRequest(RESTAPI::Errors::SignupAlreadySigned);
}
if(Existing.waitingForEmailCheck) {
return BadRequest(RESTAPI::Errors::SignupEmailCheck);
}
return BadRequest(RESTAPI::Errors::SignupWaitingForDevice);
}
SecurityObjects::UserInfo NewSub;
NewSub.signingUp = operatorName + ":" + signupUUID;
NewSub.waitingForEmailCheck = true;
NewSub.name = UserName;
NewSub.modified = OpenWifi::Now();
NewSub.creationDate = OpenWifi::Now();
NewSub.id = MicroService::instance().CreateUUID();
NewSub.email = UserName;
NewSub.userRole = SecurityObjects::SUBSCRIBER;
NewSub.changePassword = true;
NewSub.owner = owner;
StorageService()->SubDB().CreateRecord(NewSub);
Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName));
SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
NewLink.id = MicroService::CreateUUID();
NewLink.userId = NewSub.id;
NewLink.created = OpenWifi::Now();
NewLink.expires = NewLink.created + (1*60*60); // 1 hour
NewLink.userAction = false;
StorageService()->ActionLinksDB().CreateAction(NewLink);
Poco::JSON::Object Answer;
NewSub.to_json(Answer);
return ReturnObject(Answer);
}
void RESTAPI_signup_handler::DoPut() {
// TODO
}
}

View File

@@ -1,39 +0,0 @@
//
// Created by stephane bourque on 2022-02-20.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_signup_handler : public RESTAPIHandler {
public:
RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_OPTIONS,
Poco::Net::HTTPRequest::HTTP_PUT},
Server,
TransactionId,
Internal, false, true ){}
static auto PathName() { return std::list<std::string>{"/api/v1/signup"}; };
/* inline bool RoleIsAuthorized(std::string & Reason) {
if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) {
Reason = "User must be a subscriber";
return false;
}
return true;
}
*/
void DoGet() final {};
void DoPost() final;
void DoPut() final ;
void DoDelete() final {};
private:
};
}

View File

@@ -4,17 +4,13 @@
#include "RESTAPI_sms_handler.h"
#include "SMSSender.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_errors.h"
#include "framework/MicroService.h"
namespace OpenWifi {
void OpenWifi::RESTAPI_sms_handler::DoPost() {
const auto &Obj = ParsedBody_;
if(!SMSSender()->Enabled()) {
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
}
auto Obj = ParseStream();
std::string Arg;
if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) {
@@ -22,7 +18,7 @@ namespace OpenWifi {
if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
return OK();
}
return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
return BadRequest("SMS could not be sent to validate device, try later or change the phone number.");
}
std::string Code;
@@ -34,13 +30,7 @@ namespace OpenWifi {
if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
return OK();
}
return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
}
if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER &&
UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
return BadRequest("Code and number could not be validated");
}
if (Obj->has("to") &&
@@ -51,7 +41,7 @@ namespace OpenWifi {
if(SMSSender()->Send(PhoneNumber, Text))
return OK();
return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
return InternalError("SMS Message could not be sent.");
}
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}

View File

@@ -2,24 +2,27 @@
// Created by stephane bourque on 2021-10-09.
//
#pragma once
#ifndef OWSEC_RESTAPI_SMS_HANDLER_H
#define OWSEC_RESTAPI_SMS_HANDLER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_sms_handler : public RESTAPIHandler {
public:
RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/sms"};}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/sms"};}
void DoGet() final {};
void DoPost() final;
void DoDelete() final {};
void DoPut() final {};
};
}
#endif //OWSEC_RESTAPI_SMS_HANDLER_H

View File

@@ -1,81 +0,0 @@
//
// Created by stephane bourque on 2021-07-15.
//
#include <fstream>
#include <iostream>
#include "RESTAPI_subavatar_handler.h"
#include "StorageService.h"
#include "Poco/Net/HTMLForm.h"
#include "framework/MicroService.h"
namespace OpenWifi {
void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
std::string Disposition;
Poco::Net::NameValueCollection Parameters;
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
}
Poco::CountingInputStream InputStream(Stream);
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
Length_ = OutputStream_.str().size();
};
void RESTAPI_subavatar_handler::DoPost() {
std::string Id = UserInfo_.userinfo.id;
SecurityObjects::UserInfo UInfo;
std::stringstream SS;
SubAvatarPartHandler partHandler(Id, Logger_, SS);
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
Poco::JSON::Object Answer;
if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
Answer.set(RESTAPI::Protocol::AVATARID, Id);
Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email,
Id, SS.str(), partHandler.ContentType(), partHandler.Name());
StorageService()->SubDB().SetAvatar(Id,"1");
Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email));
} else {
Answer.set(RESTAPI::Protocol::AVATARID, Id);
Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
}
ReturnObject(Answer);
}
void RESTAPI_subavatar_handler::DoGet() {
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
if (Id.empty()) {
return NotFound();
}
std::string Type, Name, AvatarContent;
if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
return NotFound();
}
Logger().information(fmt::format("Retrieving avatar for {}",UserInfo_.userinfo.email));
return SendFileContent(AvatarContent, Type, Name);
}
void RESTAPI_subavatar_handler::DoDelete() {
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
return NotFound();
}
Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
StorageService()->SubDB().SetAvatar(Id,"");
OK();
}
}

View File

@@ -1,53 +0,0 @@
//
// Created by stephane bourque on 2021-07-15.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class SubAvatarPartHandler : public Poco::Net::PartHandler {
public:
SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
Id_(std::move(Id)),
Logger_(Logger),
OutputStream_(ofs){
}
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
[[nodiscard]] uint64_t Length() const { return Length_; }
[[nodiscard]] std::string &Name() { return Name_; }
[[nodiscard]] std::string &ContentType() { return FileType_; }
private:
uint64_t Length_ = 0;
std::string FileType_;
std::string Name_;
std::string Id_;
Poco::Logger &Logger_;
std::stringstream &OutputStream_;
inline Poco::Logger & Logger() { return Logger_; }
};
class RESTAPI_subavatar_handler : public RESTAPIHandler {
public:
RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; };
void DoGet() final;
void DoPost() final;
void DoDelete() final;
void DoPut() final {};
};
}

View File

@@ -1,137 +0,0 @@
//
// Created by stephane bourque on 2021-12-01.
//
#include "RESTAPI_submfa_handler.h"
#include "StorageService.h"
#include "SMSSender.h"
namespace OpenWifi {
void RESTAPI_submfa_handler::DoGet() {
SecurityObjects::UserInfo User;
if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) {
Poco::JSON::Object Answer;
SecurityObjects::SubMfaConfig MFC;
MFC.id = User.id;
if(User.userTypeProprietaryInfo.mfa.enabled) {
if(User.userTypeProprietaryInfo.mfa.method == "sms") {
MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
MFC.type = "sms";
} else if(User.userTypeProprietaryInfo.mfa.method == "email") {
MFC.email = User.email;
MFC.type = "email";
}
} else {
MFC.type = "disabled";
}
MFC.to_json(Answer);
return ReturnObject(Answer);
}
NotFound();
}
void RESTAPI_submfa_handler::DoPut() {
try {
const auto & Body = ParsedBody_;
SecurityObjects::SubMfaConfig MFC;
if (!MFC.from_json(Body)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if (MFC.type == "disabled") {
SecurityObjects::UserInfo User;
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
User.userTypeProprietaryInfo.mfa.enabled = false;
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
Poco::JSON::Object Answer;
MFC.to_json(Answer);
return ReturnObject(Answer);
} else if (MFC.type == "email") {
SecurityObjects::UserInfo User;
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
User.userTypeProprietaryInfo.mfa.enabled = true;
User.userTypeProprietaryInfo.mfa.method = "email";
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
MFC.sms = MFC.sms;
MFC.type = "email";
MFC.email = UserInfo_.userinfo.email;
MFC.id = MicroService::instance().CreateUUID();
Poco::JSON::Object Answer;
MFC.to_json(Answer);
return ReturnObject(Answer);
} else if (MFC.type == "sms") {
if (GetBoolParameter("startValidation", false)) {
if (MFC.sms.empty()) {
return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
}
if(!SMSSender()->Enabled()) {
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
}
if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
return OK();
} else {
return InternalError(RESTAPI::Errors::SMSTryLater);
}
} else if (GetBoolParameter("completeValidation", false)) {
if(!SMSSender()->Enabled()) {
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
}
auto ChallengeCode = GetParameter("challengeCode", "");
if (ChallengeCode.empty()) {
return BadRequest(RESTAPI::Errors::SMSMissingChallenge);
}
if (MFC.sms.empty()) {
return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
}
if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) {
SecurityObjects::UserInfo User;
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
User.userTypeProprietaryInfo.mfa.enabled = true;
User.userTypeProprietaryInfo.mfa.method = "sms";
SecurityObjects::MobilePhoneNumber PhoneNumber;
PhoneNumber.number = MFC.sms;
PhoneNumber.primary = true;
PhoneNumber.verified = true;
User.userTypeProprietaryInfo.mobiles.clear();
User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
MFC.sms = MFC.sms;
MFC.type = "sms";
MFC.email = UserInfo_.userinfo.email;
MFC.id = MicroService::instance().CreateUUID();
Poco::JSON::Object Answer;
MFC.to_json(Answer);
return ReturnObject(Answer);
} else {
return InternalError(RESTAPI::Errors::SMSTryLater);
}
}
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
}

View File

@@ -1,27 +0,0 @@
//
// Created by stephane bourque on 2021-12-01.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_submfa_handler : public RESTAPIHandler {
public:
RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10},
true) {}
static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
void DoPut() final ;
};
}

View File

@@ -1,165 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#include "RESTAPI_suboauth2_handler.h"
#include "AuthService.h"
#include "MFAServer.h"
#include "framework/MicroService.h"
#include "StorageService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
namespace OpenWifi {
void RESTAPI_suboauth2_handler::DoGet() {
bool Expired = false, Contacted = false;
if (!IsAuthorized(Expired, Contacted, true)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
}
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
if(GetMe) {
Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
UserInfo_.userinfo.email));
Poco::JSON::Object Me;
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
Sanitize(UserInfo_, ReturnedUser);
ReturnedUser.to_json(Me);
return ReturnObject(Me);
}
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
}
void RESTAPI_suboauth2_handler::DoDelete() {
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
std::string SessionToken;
try {
Poco::Net::OAuth20Credentials Auth(*Request);
if (Auth.getScheme() == "Bearer") {
SessionToken = Auth.getBearerToken();
}
} catch (const Poco::Exception &E) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
if (Token.empty() || (Token != SessionToken)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
AuthService()->SubLogout(Token);
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
}
void RESTAPI_suboauth2_handler::DoPost() {
const auto & Obj = ParsedBody_;
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
auto refreshToken = GetS("refreshToken", Obj);
auto grant_type = GetParameter("grant_type");
Poco::toLowerInPlace(userId);
if(!refreshToken.empty() && grant_type == "refresh_token") {
SecurityObjects::UserInfoAndPolicy UInfo;
if(AuthService()->RefreshSubToken(*Request, refreshToken, UInfo)) {
Poco::JSON::Object Answer;
UInfo.webtoken.to_json(Answer);
return ReturnObject(Answer);
} else {
return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
}
}
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression());
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy());
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy());
return ReturnObject(Answer);
}
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
SecurityObjects::UserInfo UInfo1;
auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1);
if(UserExists) {
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
NewLink.id = MicroService::CreateUUID();
NewLink.userId = UInfo1.id;
NewLink.created = OpenWifi::Now();
NewLink.expires = NewLink.created + (24*60*60);
NewLink.userAction = false;
StorageService()->ActionLinksDB().CreateAction(NewLink);
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
} else {
Poco::JSON::Object ReturnObj;
SecurityObjects::UserInfoAndPolicy UInfo;
UInfo.webtoken.userMustChangePassword = true;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
}
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId));
if(Obj->has("uuid")) {
auto uuid = Obj->get("uuid").toString();
if(MFAServer()->ResendCode(uuid))
return OK();
}
return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
}
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) {
Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId));
if(Obj->has("uuid") && Obj->has("answer")) {
SecurityObjects::UserInfoAndPolicy UInfo;
if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) {
Poco::JSON::Object ReturnObj;
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
}
}
return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
}
SecurityObjects::UserInfoAndPolicy UInfo;
bool Expired=false;
auto Code=AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
if (Code==SUCCESS) {
Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) {
if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
return ReturnObject(ReturnObj);
}
Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
}
UInfo.webtoken.to_json(ReturnObj);
return ReturnObject(ReturnObj);
} else {
switch(Code) {
case INVALID_CREDENTIALS:
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
case PASSWORD_INVALID:
return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
case PASSWORD_ALREADY_USED:
return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
case USERNAME_PENDING_VERIFICATION:
return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
case PASSWORD_CHANGE_REQUIRED:
return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
default:
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break;
}
return;
}
}
}

View File

@@ -1,27 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_suboauth2_handler : public RESTAPIHandler {
public:
RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10},
false) {}
static auto PathName() { return std::list<std::string>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; };
void DoGet() final;
void DoPost() final;
void DoDelete() final;
void DoPut() final {};
};
}

View File

@@ -1,36 +0,0 @@
//
// Created by stephane bourque on 2021-11-16.
//
#include "RESTAPI_subpreferences.h"
#include "StorageService.h"
namespace OpenWifi {
void RESTAPI_subpreferences::DoGet() {
SecurityObjects::Preferences P;
Poco::JSON::Object Answer;
StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
P.to_json(Answer);
ReturnObject(Answer);
}
void RESTAPI_subpreferences::DoPut() {
SecurityObjects::Preferences P;
const auto & RawObject = ParsedBody_;
if(!P.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
P.id = UserInfo_.userinfo.id;
P.modified = OpenWifi::Now();
StorageService()->SubPreferencesDB().SetPreferences(P);
Poco::JSON::Object Answer;
P.to_json(Answer);
ReturnObject(Answer);
}
}

View File

@@ -1,27 +0,0 @@
//
// Created by stephane bourque on 2021-11-16.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_subpreferences : public RESTAPIHandler {
public:
RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; };
void DoGet() final;
void DoPut() final;
void DoPost() final {};
void DoDelete() final {};
};
}

View File

@@ -1,37 +0,0 @@
//
// Created by stephane bourque on 2022-01-31.
//
#include "RESTAPI_subtotp_handler.h"
#include "TotpCache.h"
namespace OpenWifi {
void RESTAPI_subtotp_handler::DoGet() {
auto Reset = GetBoolParameter("reset",false);
std::string QRCode;
if(TotpCache()->StartValidation(UserInfo_.userinfo,true,QRCode,Reset)) {
return SendFileContent(QRCode, "image/svg+xml","qrcode.svg");
}
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
void RESTAPI_subtotp_handler::DoPut() {
auto Value = GetParameter("value","");
auto nextIndex = GetParameter("index",0);
bool moreCodes=false;
RESTAPI::Errors::msg Error;
if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, Error )) {
Poco::JSON::Object Answer;
Answer.set("nextIndex", nextIndex);
Answer.set("moreCodes", moreCodes);
return ReturnObject(Answer);
}
return BadRequest(Error);
}
}

View File

@@ -1,29 +0,0 @@
//
// Created by stephane bourque on 2022-01-31.
//
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_subtotp_handler : public RESTAPIHandler {
public:
RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_OPTIONS
},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
void DoPut() final;
private:
};
}

View File

@@ -1,316 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#include "RESTAPI_subuser_handler.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "SMSSender.h"
#include "SMTPMailerService.h"
#include "ACLProcessor.h"
#include "AuthService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
#include "MFAServer.h"
#include "TotpCache.h"
namespace OpenWifi {
void RESTAPI_subuser_handler::DoGet() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
Poco::toLowerInPlace(Id);
std::string Arg;
SecurityObjects::UserInfo UInfo;
if(HasParameter("byEmail",Arg) && Arg=="true") {
if(!StorageService()->SubDB().GetUserByEmail(Id,UInfo)) {
return NotFound();
}
} else if(!StorageService()->SubDB().GetUserById(Id,UInfo)) {
return NotFound();
}
Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, UInfo);
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
}
void RESTAPI_subuser_handler::DoDelete() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
SecurityObjects::UserInfo TargetUser;
if(!StorageService()->SubDB().GetUserById(Id,TargetUser)) {
return NotFound();
}
if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
return NotFound();
}
AuthService()->DeleteSubUserFromCache(Id);
StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
StorageService()->SubAvatarDB().DeleteRecord("id", Id);
Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email));
OK();
}
void RESTAPI_subuser_handler::DoPost() {
std::string Id = GetBinding("id", "");
if(Id!="0") {
return BadRequest(RESTAPI::Errors::IdMustBe0);
}
SecurityObjects::UserInfo NewUser;
const auto & RawObject = ParsedBody_;
if(!NewUser.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
Poco::toLowerInPlace(NewUser.email);
SecurityObjects::UserInfo Existing;
if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) {
return BadRequest(RESTAPI::Errors::UserAlreadyExists);
}
if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
Poco::toLowerInPlace(NewUser.email);
if(!Utils::ValidEMailAddress(NewUser.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
}
if(!NewUser.currentPassword.empty()) {
if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
return BadRequest(RESTAPI::Errors::InvalidPassword);
}
}
if(NewUser.name.empty())
NewUser.name = NewUser.email;
// You cannot enable MFA during user creation
NewUser.userTypeProprietaryInfo.mfa.enabled = false;
NewUser.userTypeProprietaryInfo.mfa.method = "";
NewUser.userTypeProprietaryInfo.mobiles.clear();
NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
if(!StorageService()->SubDB().CreateUser(UserInfo_.userinfo.email, NewUser)) {
Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email));
return BadRequest(RESTAPI::Errors::RecordNotCreated);
}
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifySubEmail(NewUser))
Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email));
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
}
if(!StorageService()->SubDB().GetUserByEmail(NewUser.email, NewUser)) {
Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email));
return NotFound();
}
Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, NewUser);
NewUser.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email));
}
void RESTAPI_subuser_handler::DoPut() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
SecurityObjects::UserInfo Existing;
if(!StorageService()->SubDB().GetUserById(Id,Existing)) {
return NotFound();
}
if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(GetBoolParameter("resetMFA")) {
if( (UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) ||
(UserInfo_.userinfo.id == Id)) {
Existing.userTypeProprietaryInfo.mfa.enabled = false;
Existing.userTypeProprietaryInfo.mfa.method.clear();
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.modified = OpenWifi::Now();
Existing.notes.push_back( SecurityObjects::NoteInfo{
.created=OpenWifi::Now(),
.createdBy=UserInfo_.userinfo.email,
.note="MFA Reset by " + UserInfo_.userinfo.email});
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing);
SecurityObjects::UserInfo NewUserInfo;
StorageService()->SubDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject;
Sanitize(UserInfo_, NewUserInfo);
NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject);
} else {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
}
if(GetBoolParameter("forgotPassword")) {
Existing.changePassword = true;
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), Existing.email));
SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
NewLink.id = MicroService::CreateUUID();
NewLink.userId = Existing.id;
NewLink.created = OpenWifi::Now();
NewLink.expires = NewLink.created + (24*60*60);
NewLink.userAction = false;
StorageService()->ActionLinksDB().CreateAction(NewLink);
return OK();
}
SecurityObjects::UserInfo NewUser;
const auto & RawObject = ParsedBody_;
if(!NewUser.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
// some basic validations
if(RawObject->has("userRole") &&
(SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN ||
SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
// The only valid things to change are: changePassword, name,
AssignIfPresent(RawObject,"name", Existing.name);
AssignIfPresent(RawObject,"description", Existing.description);
AssignIfPresent(RawObject,"owner", Existing.owner);
AssignIfPresent(RawObject,"location", Existing.location);
AssignIfPresent(RawObject,"locale", Existing.locale);
AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole")) {
auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(NewRole!=Existing.userRole) {
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(Id==UserInfo_.userinfo.id) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
Existing.userRole = NewRole;
}
}
if(RawObject->has("notes")) {
SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
Existing.notes.push_back(ii);
}
}
if(RawObject->has("currentPassword")) {
if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
return BadRequest(RESTAPI::Errors::InvalidPassword);
}
if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) {
return BadRequest(RESTAPI::Errors::PasswordRejected);
}
}
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifySubEmail(Existing))
Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email));
}
if(RawObject->has("userTypeProprietaryInfo")) {
if(NewUser.userTypeProprietaryInfo.mfa.enabled) {
if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
return BadRequest(RESTAPI::Errors::BadMFAMethod);
}
if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS &&
!SMSSender()->Enabled()) {
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
}
if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL &&
!SMTPMailerService()->Enabled()) {
return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
}
Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
Existing.userTypeProprietaryInfo.mfa.enabled = true;
if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
if(NewUser.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
std::string Secret;
Existing.userTypeProprietaryInfo.mobiles.clear();
if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
// we allow someone to use their old secret
} else {
return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
}
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
}
} else {
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.mfa.enabled = false;
}
}
if(StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
SecurityObjects::UserInfo NewUserInfo;
StorageService()->SubDB().GetUserById(Id,NewUserInfo);
Poco::JSON::Object ModifiedObject;
Sanitize(UserInfo_, NewUserInfo);
NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject);
}
BadRequest(RESTAPI::Errors::RecordNotUpdated);
}
}

View File

@@ -1,31 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_subuser_handler : public RESTAPIHandler {
public:
RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; };
void DoGet() final;
void DoPost() final;
void DoDelete() final;
void DoPut() final;
private:
};
}

View File

@@ -1,80 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#include "RESTAPI_subusers_handler.h"
#include "StorageService.h"
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
namespace OpenWifi {
void RESTAPI_subusers_handler::DoGet() {
bool IdOnly = GetBoolParameter("idOnly");
auto operatorId = GetParameter("operatorId");
auto nameSearch = GetParameter("nameSearch");
auto emailSearch = GetParameter("emailSearch");
std::string baseQuery;
if(!nameSearch.empty() || !emailSearch.empty()) {
if(!nameSearch.empty())
baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) );
if(!emailSearch.empty())
baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch))
: fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch));
}
if(QB_.CountOnly) {
std::string whereClause;
if(!operatorId.empty()) {
whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) :
fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
auto count = StorageService()->SubDB().Count(whereClause);
return ReturnCountOnly(count);
}
auto count = StorageService()->UserDB().Count();
return ReturnCountOnly(count);
} else if(QB_.Select.empty()) {
std::string whereClause;
if(!operatorId.empty()) {
whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) :
fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
}
SecurityObjects::UserInfoList Users;
if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, whereClause)) {
for (auto &i : Users.users) {
Sanitize(UserInfo_, i);
}
}
if(IdOnly) {
Poco::JSON::Array Arr;
Poco::JSON::Object Answer;
for(const auto &i:Users.users) {
Arr.add(i.id);
}
Answer.set("users",Arr);
return ReturnObject(Answer);
}
Poco::JSON::Object Answer;
Users.to_json(Answer);
return ReturnObject(Answer);
} else {
SecurityObjects::UserInfoList Users;
for(auto &i:SelectedRecords()) {
SecurityObjects::UserInfo UInfo;
if(StorageService()->SubDB().GetUserById(i,UInfo)) {
Poco::JSON::Object Obj;
Sanitize(UserInfo_, UInfo);
Users.users.emplace_back(UInfo);
}
}
Poco::JSON::Object Answer;
Users.to_json(Answer);
return ReturnObject(Answer);
}
}
}

View File

@@ -1,26 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_subusers_handler : public RESTAPIHandler {
public:
RESTAPI_subusers_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/subusers"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
void DoPut() final {};
};
};

View File

@@ -2,12 +2,12 @@
// Created by stephane bourque on 2021-07-01.
//
#include "RESTAPI_system_endpoints_handler.h"
#include "RESTAPI_systemEndpoints_handler.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
void RESTAPI_system_endpoints_handler::DoGet() {
void RESTAPI_systemEndpoints_handler::DoGet() {
auto Services = MicroService::instance().GetServices();
SecurityObjects::SystemEndpointList L;
for(const auto &i:Services) {

View File

@@ -2,24 +2,26 @@
// Created by stephane bourque on 2021-07-01.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
#define UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
#include "../framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_system_endpoints_handler : public RESTAPIHandler {
class RESTAPI_systemEndpoints_handler : public RESTAPIHandler {
public:
RESTAPI_system_endpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_systemEndpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/systemEndpoints"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/systemEndpoints"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
void DoPut() final {};
};
}
#endif //UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H

View File

@@ -1,35 +0,0 @@
//
// Created by stephane bourque on 2022-01-31.
//
#include "RESTAPI_totp_handler.h"
#include "TotpCache.h"
namespace OpenWifi {
void RESTAPI_totp_handler::DoGet() {
auto Reset = GetBoolParameter("reset",false);
std::string QRCode;
if(TotpCache()->StartValidation(UserInfo_.userinfo,false,QRCode,Reset)) {
return SendFileContent(QRCode, "image/svg+xml","qrcode.svg");
}
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
void RESTAPI_totp_handler::DoPut() {
auto Value = GetParameter("value","");
auto nextIndex = GetParameter("index",0);
bool moreCodes=false;
RESTAPI::Errors::msg Err;
if(TotpCache()->ContinueValidation(UserInfo_.userinfo,false,Value,nextIndex,moreCodes, Err)) {
Poco::JSON::Object Answer;
Answer.set("nextIndex", nextIndex);
Answer.set("moreCodes", moreCodes);
return ReturnObject(Answer);
}
return BadRequest(Err);
}
}

View File

@@ -1,31 +0,0 @@
//
// Created by stephane bourque on 2022-01-31.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_totp_handler : public RESTAPIHandler {
public:
RESTAPI_totp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_OPTIONS
},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/totp"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
void DoPut() final;
private:
};
}

View File

@@ -4,17 +4,11 @@
#include "RESTAPI_user_handler.h"
#include "StorageService.h"
#include "framework/ow_constants.h"
#include "Poco/JSON/Parser.h"
#include "framework/RESTAPI_errors.h"
#include "SMSSender.h"
#include "SMTPMailerService.h"
#include "ACLProcessor.h"
#include "AuthService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
#include "MFAServer.h"
#include "TotpCache.h"
namespace OpenWifi {
void RESTAPI_user_handler::DoGet() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
@@ -25,19 +19,13 @@ namespace OpenWifi {
std::string Arg;
SecurityObjects::UserInfo UInfo;
if(HasParameter("byEmail",Arg) && Arg=="true") {
if(!StorageService()->UserDB().GetUserByEmail(Id,UInfo)) {
if(!StorageService()->GetUserByEmail(Id,UInfo)) {
return NotFound();
}
} else if(!StorageService()->UserDB().GetUserById(Id,UInfo)) {
} else if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound();
}
if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, UInfo);
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
}
@@ -49,159 +37,86 @@ namespace OpenWifi {
}
SecurityObjects::UserInfo UInfo;
if(!StorageService()->UserDB().GetUserById(Id,UInfo)) {
if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound();
}
if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) {
return NotFound();
}
AuthService()->DeleteUserFromCache(Id);
StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id);
StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id);
StorageService()->UserTokenDB().RevokeAllTokens(Id);
Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email));
if(AuthService()->DeleteUserFromCache(UInfo.email))
;
Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
StorageService()->RevokeAllTokens(UInfo.email);
Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
OK();
}
void RESTAPI_user_handler::DoPost() {
std::string Id = GetBinding("id", "");
if(Id!="0") {
return BadRequest(RESTAPI::Errors::IdMustBe0);
}
SecurityObjects::UserInfo NewUser;
const auto & RawObject = ParsedBody_;
if(!NewUser.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
SecurityObjects::UserInfo UInfo;
RESTAPI_utils::from_request(UInfo,*Request);
if(NewUser.userRole == SecurityObjects::UNKNOWN) {
if(UInfo.userRole == SecurityObjects::UNKNOWN) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
if(UserInfo_.userinfo.userRole==SecurityObjects::ROOT) {
NewUser.owner = GetParameter("entity","");
} else {
NewUser.owner = UserInfo_.userinfo.owner;
}
if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
Poco::toLowerInPlace(NewUser.email);
if(!Utils::ValidEMailAddress(NewUser.email)) {
Poco::toLowerInPlace(UInfo.email);
if(!Utils::ValidEMailAddress(UInfo.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
}
SecurityObjects::UserInfo Existing;
if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) {
return BadRequest(RESTAPI::Errors::UserAlreadyExists);
}
if(!NewUser.currentPassword.empty()) {
if(!AuthService()->ValidatePassword(NewUser.currentPassword)) {
if(!UInfo.currentPassword.empty()) {
if(!AuthService()->ValidatePassword(UInfo.currentPassword)) {
return BadRequest(RESTAPI::Errors::InvalidPassword);
}
}
if(NewUser.name.empty())
NewUser.name = NewUser.email;
if(UInfo.name.empty())
UInfo.name = UInfo.email;
// You cannot enable MFA during user creation
NewUser.userTypeProprietaryInfo.mfa.enabled = false;
NewUser.userTypeProprietaryInfo.mfa.method = "";
NewUser.userTypeProprietaryInfo.mobiles.clear();
NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
NewUser.validated = true;
if(!StorageService()->UserDB().CreateUser(NewUser.email,NewUser)) {
Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email));
if(!StorageService()->CreateUser(UInfo.email,UInfo)) {
Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email));
return BadRequest(RESTAPI::Errors::RecordNotCreated);
}
if(GetBoolParameter("email_verification")) {
if(AuthService::VerifyEmail(NewUser))
Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email));
StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifyEmail(UInfo))
Logger_.information(Poco::format("Verification e-mail requested for %s",UInfo.email));
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UInfo.Id,UInfo);
}
if(!StorageService()->UserDB().GetUserByEmail(NewUser.email, NewUser)) {
Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email));
if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) {
Logger_.information(Poco::format("User '%s' but not retrieved.",UInfo.email));
return NotFound();
}
Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, NewUser);
NewUser.to_json(UserInfoObject);
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
Logger_.information(fmt::format("User '{}' has been added by '{}')",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() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
SecurityObjects::UserInfo Existing;
if(!StorageService()->UserDB().GetUserById(Id,Existing)) {
if(!StorageService()->GetUserById(Id,Existing)) {
return NotFound();
}
if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(GetBoolParameter("resetMFA")) {
if( (UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) ||
(UserInfo_.userinfo.id == Id)) {
Existing.userTypeProprietaryInfo.mfa.enabled = false;
Existing.userTypeProprietaryInfo.mfa.method.clear();
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.modified = OpenWifi::Now();
Existing.notes.push_back( SecurityObjects::NoteInfo{
.created=OpenWifi::Now(),
.createdBy=UserInfo_.userinfo.email,
.note="MFA Reset by " + UserInfo_.userinfo.email});
StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing);
SecurityObjects::UserInfo NewUserInfo;
StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject;
Sanitize(UserInfo_, NewUserInfo);
NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject);
} else {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
}
if(GetBoolParameter("forgotPassword")) {
Existing.changePassword = true;
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), Existing.email));
SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
NewLink.id = MicroService::CreateUUID();
NewLink.userId = Existing.id;
NewLink.created = OpenWifi::Now();
NewLink.expires = NewLink.created + (24*60*60);
NewLink.userAction = true;
StorageService()->ActionLinksDB().CreateAction(NewLink);
return OK();
}
SecurityObjects::UserInfo NewUser;
const auto & RawObject = ParsedBody_;
auto RawObject = ParseStream();
if(!NewUser.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
@@ -211,39 +126,23 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
if(RawObject->has("owner")) {
if (UserInfo_.userinfo.userRole == SecurityObjects::ROOT && Existing.owner.empty()) {
AssignIfPresent(RawObject, "owner", Existing.owner);
}
}
// The only valid things to change are: changePassword, name,
AssignIfPresent(RawObject,"name", Existing.name);
AssignIfPresent(RawObject,"description", Existing.description);
AssignIfPresent(RawObject,"owner", Existing.owner);
AssignIfPresent(RawObject,"location", Existing.location);
AssignIfPresent(RawObject,"locale", Existing.locale);
AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole")) {
auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(NewRole!=Existing.userRole) {
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
if(Id==UserInfo_.userinfo.id) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
Existing.userRole = NewRole;
}
}
if(RawObject->has("userRole"))
Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(RawObject->has("notes")) {
SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note};
Existing.notes.push_back(ii);
}
}
@@ -256,69 +155,39 @@ namespace OpenWifi {
}
}
if(GetBoolParameter("email_verification")) {
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifyEmail(Existing))
Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email));
Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email));
}
if(RawObject->has("userTypeProprietaryInfo")) {
if(NewUser.userTypeProprietaryInfo.mfa.enabled) {
if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
auto MobileStruct = RawObject->get("userTypeProprietaryInfo");
auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>();
if(Info->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
}
if(!NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
} else if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
} else {
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest(RESTAPI::Errors::BadMFAMethod);
}
if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS &&
!SMSSender()->Enabled()) {
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
}
if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL &&
!SMTPMailerService()->Enabled()) {
return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
}
Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
Existing.userTypeProprietaryInfo.mfa.enabled = true;
if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
if(NewUser.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
std::string Secret;
Existing.userTypeProprietaryInfo.mobiles.clear();
if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
// we allow someone to use their old secret
} else {
return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
}
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
}
} else {
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.mfa.enabled = false;
}
}
Existing.modified = OpenWifi::Now();
if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
SecurityObjects::UserInfo NewUserInfo;
StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject;
Sanitize(UserInfo_, NewUserInfo);
NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject);
}

View File

@@ -2,14 +2,15 @@
// Created by stephane bourque on 2021-06-21.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_USER_HANDLER_H
#define UCENTRALSEC_RESTAPI_USER_HANDLER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_user_handler : public RESTAPIHandler {
public:
RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_user_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_POST,
@@ -18,9 +19,8 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/user/{id}"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/user/{id}"}; };
void DoGet() final;
void DoPost() final;
void DoDelete() final;
@@ -29,3 +29,6 @@ namespace OpenWifi {
};
}
#endif //UCENTRALSEC_RESTAPI_USER_HANDLER_H

View File

@@ -4,55 +4,48 @@
#include "RESTAPI_users_handler.h"
#include "StorageService.h"
#include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
namespace OpenWifi {
void RESTAPI_users_handler::DoGet() {
std::vector<SecurityObjects::UserInfo> Users;
bool IdOnly = (GetParameter("idOnly","false")=="true");
auto nameSearch = GetParameter("nameSearch");
auto emailSearch = GetParameter("emailSearch");
std::string baseQuery;
if(!nameSearch.empty() || !emailSearch.empty()) {
if(!nameSearch.empty())
baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) );
if(!emailSearch.empty())
baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch))
: fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch));
}
if(QB_.Select.empty()) {
SecurityObjects::UserInfoList Users;
if(StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, baseQuery)) {
for (auto &i : Users.users) {
Sanitize(UserInfo_, i);
}
Poco::JSON::Array ArrayObj;
Poco::JSON::Object Answer;
if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) {
for (const auto &i : Users) {
Poco::JSON::Object Obj;
if (IdOnly) {
Poco::JSON::Array Arr;
for(const auto &i:Users.users)
Arr.add(i.id);
Poco::JSON::Object Answer;
Answer.set("users", Arr);
return ReturnObject(Answer);
ArrayObj.add(i.Id);
} else {
i.to_json(Obj);
ArrayObj.add(Obj);
}
}
Poco::JSON::Object Answer;
Users.to_json(Answer);
Answer.set(RESTAPI::Protocol::USERS, ArrayObj);
}
return ReturnObject(Answer);
} else {
SecurityObjects::UserInfoList Users;
for(auto &i:SelectedRecords()) {
Types::StringVec IDs = Utils::Split(QB_.Select);
Poco::JSON::Array ArrayObj;
for(auto &i:IDs) {
SecurityObjects::UserInfo UInfo;
if(StorageService()->UserDB().GetUserById(i,UInfo)) {
if(StorageService()->GetUserById(i,UInfo)) {
Poco::JSON::Object Obj;
Sanitize(UserInfo_, UInfo);
Users.users.emplace_back(UInfo);
}
}
Poco::JSON::Object Answer;
Users.to_json(Answer);
return ReturnObject(Answer);
if (IdOnly) {
ArrayObj.add(UInfo.Id);
} else {
UInfo.to_json(Obj);
ArrayObj.add(Obj);
}
}
}
Poco::JSON::Object RetObj;
RetObj.set(RESTAPI::Protocol::USERS, ArrayObj);
return ReturnObject(RetObj);
}
}
}

View File

@@ -2,22 +2,22 @@
// Created by stephane bourque on 2021-06-21.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_USERS_HANDLER_H
#define UCENTRALSEC_RESTAPI_USERS_HANDLER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_users_handler : public RESTAPIHandler {
public:
RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_users_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/users"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/users"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
@@ -25,3 +25,5 @@ namespace OpenWifi {
};
};
#endif //UCENTRALSEC_RESTAPI_USERS_HANDLER_H

View File

@@ -2,19 +2,18 @@
// Created by stephane bourque on 2021-07-01.
//
#include "RESTAPI_validate_token_handler.h"
#include "RESTAPI_validateToken_handler.h"
#include "AuthService.h"
namespace OpenWifi {
void RESTAPI_validate_token_handler::DoGet() {
void RESTAPI_validateToken_handler::DoGet() {
Poco::URI URI(Request->getURI());
auto Parameters = URI.getQueryParameters();
for(auto const &i:Parameters) {
if (i.first == "token") {
// can we find this token?
SecurityObjects::UserInfoAndPolicy SecObj;
bool Expired = false;
if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) {
if (AuthService()->IsValidToken(i.second, SecObj.webtoken, SecObj.userinfo)) {
Poco::JSON::Object Obj;
SecObj.to_json(Obj);
return ReturnObject(Obj);

View File

@@ -2,22 +2,22 @@
// Created by stephane bourque on 2021-07-01.
//
#pragma once
#ifndef UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
#define UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_validate_token_handler : public RESTAPIHandler {
class RESTAPI_validateToken_handler : public RESTAPIHandler {
public:
RESTAPI_validate_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
RESTAPI_validateToken_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {};
static auto PathName() { return std::list<std::string>{"/api/v1/validateToken"}; };
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateToken"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
@@ -25,3 +25,4 @@ namespace OpenWifi {
};
}
#endif //UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H

View File

@@ -1,26 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#include "RESTAPI_validate_sub_token_handler.h"
#include "AuthService.h"
namespace OpenWifi {
void RESTAPI_validate_sub_token_handler::DoGet() {
Poco::URI URI(Request->getURI());
auto Parameters = URI.getQueryParameters();
for(auto const &i:Parameters) {
if (i.first == "token") {
// can we find this token?
SecurityObjects::UserInfoAndPolicy SecObj;
bool Expired = false;
if (AuthService()->IsValidSubToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) {
Poco::JSON::Object Obj;
SecObj.to_json(Obj);
return ReturnObject(Obj);
}
}
}
return NotFound();
}
}

View File

@@ -1,26 +0,0 @@
//
// Created by stephane bourque on 2021-11-30.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class RESTAPI_validate_sub_token_handler : public RESTAPIHandler {
public:
RESTAPI_validate_sub_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {};
static auto PathName() { return std::list<std::string>{"/api/v1/validateSubToken"}; };
void DoGet() final;
void DoPost() final {};
void DoDelete() final {};
void DoPut() final {};
};
}

View File

@@ -1,624 +0,0 @@
//
// Created by stephane bourque on 2022-01-10.
//
#include "RESTAPI_AnalyticsObjects.h"
#include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::AnalyticsObjects {
void Report::reset() {
}
void Report::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
}
void VenueInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"name",name);
field_to_json(Obj,"description",description);
field_to_json(Obj,"retention",retention);
field_to_json(Obj,"interval",interval);
field_to_json(Obj,"monitorSubVenues",monitorSubVenues);
}
bool VenueInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name);
field_from_json(Obj,"description",description);
field_from_json(Obj,"retention",retention);
field_from_json(Obj,"interval",interval);
field_from_json(Obj,"monitorSubVenues",monitorSubVenues);
return true;
} catch(...) {
}
return false;
}
void BoardInfo::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
field_to_json(Obj,"venueList",venueList);
}
bool BoardInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
field_from_json(Obj,"venueList",venueList);
return true;
} catch(...) {
}
return false;
}
void DeviceInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"boardId",boardId);
field_to_json(Obj,"type",type);
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"deviceType",deviceType);
field_to_json(Obj,"lastContact",lastContact);
field_to_json(Obj,"lastPing",lastPing);
field_to_json(Obj,"lastState",lastState);
field_to_json(Obj,"lastFirmware",lastFirmware);
field_to_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate);
field_to_json(Obj,"lastConnection",lastConnection);
field_to_json(Obj,"lastDisconnection",lastDisconnection);
field_to_json(Obj,"pings",pings);
field_to_json(Obj,"states",states);
field_to_json(Obj,"connected",connected);
field_to_json(Obj,"connectionIp",connectionIp);
field_to_json(Obj,"associations_2g",associations_2g);
field_to_json(Obj,"associations_5g",associations_5g);
field_to_json(Obj,"associations_6g",associations_6g);
field_to_json(Obj,"health",health);
field_to_json(Obj,"lastHealth",lastHealth);
field_to_json(Obj,"locale",locale);
field_to_json(Obj,"uptime",uptime);
field_to_json(Obj,"memory",memory);
}
bool DeviceInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"boardId",boardId);
field_from_json(Obj,"type",type);
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"deviceType",deviceType);
field_from_json(Obj,"lastContact",lastContact);
field_from_json(Obj,"lastPing",lastPing);
field_from_json(Obj,"lastState",lastState);
field_from_json(Obj,"lastFirmware",lastFirmware);
field_from_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate);
field_from_json(Obj,"lastConnection",lastConnection);
field_from_json(Obj,"lastDisconnection",lastDisconnection);
field_from_json(Obj,"pings",pings);
field_from_json(Obj,"states",states);
field_from_json(Obj,"connected",connected);
field_from_json(Obj,"connectionIp",connectionIp);
field_from_json(Obj,"associations_2g",associations_2g);
field_from_json(Obj,"associations_5g",associations_5g);
field_from_json(Obj,"associations_6g",associations_6g);
field_from_json(Obj,"health",health);
field_from_json(Obj,"lastHealth",lastHealth);
field_from_json(Obj,"locale",locale);
field_from_json(Obj,"uptime",uptime);
field_from_json(Obj,"memory",memory);
return true;
} catch(...) {
}
return false;
}
void DeviceInfoList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"devices",devices);
}
bool DeviceInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"devices",devices);
return true;
} catch(...) {
}
return false;
}
void UE_rate::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"bitrate",bitrate);
field_to_json(Obj,"mcs",mcs);
field_to_json(Obj,"nss",nss);
field_to_json(Obj,"ht",ht);
field_to_json(Obj,"sgi",sgi);
field_to_json(Obj,"chwidth",chwidth);
}
bool UE_rate::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"bitrate",bitrate);
field_from_json(Obj,"mcs",mcs);
field_from_json(Obj,"nss",nss);
field_from_json(Obj,"ht",ht);
field_from_json(Obj,"sgi",sgi);
field_from_json(Obj,"chwidth",chwidth);
return true;
} catch(...) {
}
return false;
}
void UETimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"station",station);
field_to_json(Obj,"rssi",rssi);
field_to_json(Obj,"tx_bytes",tx_bytes);
field_to_json(Obj,"rx_bytes",rx_bytes);
field_to_json(Obj,"tx_duration",tx_duration);
field_to_json(Obj,"rx_packets",rx_packets);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"tx_retries",tx_retries);
field_to_json(Obj,"tx_failed",tx_failed);
field_to_json(Obj,"connected",connected);
field_to_json(Obj,"inactive",inactive);
field_to_json(Obj,"tx_rate",tx_rate);
field_to_json(Obj,"rx_rate",rx_rate);
// field_to_json(Obj, "tidstats", tidstats);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
field_to_json(Obj,"tx_failed_delta",tx_failed_delta);
field_to_json(Obj,"tx_retries_delta",tx_retries_delta);
field_to_json(Obj,"tx_duration_delta",tx_duration_delta);
}
bool UETimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"station",station);
field_from_json(Obj,"rssi",rssi);
field_from_json(Obj,"tx_bytes",tx_bytes);
field_from_json(Obj,"rx_bytes",rx_bytes);
field_from_json(Obj,"tx_duration",tx_duration);
field_from_json(Obj,"rx_packets",rx_packets);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"tx_retries",tx_retries);
field_from_json(Obj,"tx_failed",tx_failed);
field_from_json(Obj,"connected",connected);
field_from_json(Obj,"inactive",inactive);
field_from_json(Obj,"tx_rate",tx_rate);
field_from_json(Obj,"rx_rate",rx_rate);
// field_from_json(Obj,"tidstats",tidstats);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
field_from_json(Obj,"tx_failed_delta",tx_failed_delta);
field_from_json(Obj,"tx_retries_delta",tx_retries_delta);
field_from_json(Obj,"tx_duration_delta",tx_duration_delta);
return true;
} catch(...) {
}
return false;
}
void APTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"collisions",collisions);
field_to_json(Obj,"multicast",multicast);
field_to_json(Obj,"rx_bytes",rx_bytes);
field_to_json(Obj,"rx_dropped",rx_dropped);
field_to_json(Obj,"rx_errors",rx_errors);
field_to_json(Obj,"rx_packets",rx_packets);
field_to_json(Obj,"tx_bytes",tx_bytes);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"tx_dropped",tx_dropped);
field_to_json(Obj,"tx_errors",tx_errors);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_to_json(Obj,"rx_dropped_delta",rx_dropped_delta);
field_to_json(Obj,"tx_dropped_delta",tx_dropped_delta);
field_to_json(Obj,"rx_packets_delta",rx_packets_delta);
field_to_json(Obj,"tx_packets_delta",tx_packets_delta);
field_to_json(Obj,"rx_errors_delta",rx_errors_delta);
field_to_json(Obj,"tx_errors_delta",tx_errors_delta);
}
bool APTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"collisions",collisions);
field_from_json(Obj,"multicast",multicast);
field_from_json(Obj,"rx_bytes",rx_bytes);
field_from_json(Obj,"rx_dropped",rx_dropped);
field_from_json(Obj,"rx_errors",rx_errors);
field_from_json(Obj,"rx_packets",rx_packets);
field_from_json(Obj,"tx_bytes",tx_bytes);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"tx_dropped",tx_dropped);
field_from_json(Obj,"tx_errors",tx_errors);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta);
field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta);
field_from_json(Obj,"rx_dropped_delta",rx_dropped_delta);
field_from_json(Obj,"tx_dropped_delta",tx_dropped_delta);
field_from_json(Obj,"rx_packets_delta",rx_packets_delta);
field_from_json(Obj,"tx_packets_delta",tx_packets_delta);
field_from_json(Obj,"rx_errors_delta",rx_errors_delta);
field_from_json(Obj,"tx_errors_delta",tx_errors_delta);
return true;
} catch(...) {
}
return false;
}
void TIDstat_entry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"rx_msdu",rx_msdu);
field_to_json(Obj,"tx_msdu",tx_msdu);
field_to_json(Obj,"tx_msdu_failed",tx_msdu_failed);
field_to_json(Obj,"tx_msdu_retries",tx_msdu_retries);
}
bool TIDstat_entry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"rx_msdu",rx_msdu);
field_from_json(Obj,"tx_msdu",tx_msdu);
field_from_json(Obj,"tx_msdu_failed",tx_msdu_failed);
field_from_json(Obj,"tx_msdu_retries",tx_msdu_retries);
return true;
} catch(...) {
}
return false;
}
void RadioTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"band",band);
field_to_json(Obj,"channel_width",channel_width);
field_to_json(Obj,"active_ms",active_ms);
field_to_json(Obj,"busy_ms",busy_ms);
field_to_json(Obj,"receive_ms",receive_ms);
field_to_json(Obj,"transmit_ms",transmit_ms);
field_to_json(Obj,"tx_power",tx_power);
field_to_json(Obj,"channel",channel);
field_to_json(Obj,"temperature",temperature);
field_to_json(Obj,"noise",noise);
field_to_json(Obj,"active_pct",active_pct);
field_to_json(Obj,"busy_pct",busy_pct);
field_to_json(Obj,"receive_pct",receive_pct);
field_to_json(Obj,"transmit_pct",transmit_pct);
}
bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"band",band);
field_from_json(Obj,"channel_width",channel_width);
field_from_json(Obj,"active_ms",active_ms);
field_from_json(Obj,"busy_ms",busy_ms);
field_from_json(Obj,"receive_ms",receive_ms);
field_from_json(Obj,"transmit_ms",transmit_ms);
field_from_json(Obj,"tx_power",tx_power);
field_from_json(Obj,"channel",channel);
field_from_json(Obj,"temperature",temperature);
field_from_json(Obj,"noise",noise);
field_from_json(Obj,"active_pct",active_pct);
field_from_json(Obj,"busy_pct",busy_pct);
field_from_json(Obj,"receive_pct",receive_pct);
field_from_json(Obj,"transmit_pct",transmit_pct);
return true;
} catch(...) {
}
return false;
}
void AveragePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"min",min);
field_to_json(Obj,"max",max);
field_to_json(Obj,"avg",avg);
}
bool AveragePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"min",min);
field_from_json(Obj,"max",max);
field_from_json(Obj,"avg",avg);
return true;
} catch(...) {
}
return false;
}
void SSIDTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"bssid",bssid);
field_to_json(Obj,"mode",mode);
field_to_json(Obj,"ssid",ssid);
field_to_json(Obj,"band",band);
field_to_json(Obj,"channel",channel);
field_to_json(Obj,"associations",associations);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_failed_pct",tx_failed_pct);
field_to_json(Obj,"tx_retries_pct",tx_retries_pct);
field_to_json(Obj,"tx_duration_pct",tx_duration_pct);
}
bool SSIDTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"bssid",bssid);
field_from_json(Obj,"mode",mode);
field_from_json(Obj,"ssid",ssid);
field_from_json(Obj,"band",band);
field_from_json(Obj,"channel",channel);
field_from_json(Obj,"associations",associations);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_failed_pct",tx_failed_pct);
field_from_json(Obj,"tx_retries_pct",tx_retries_pct);
field_from_json(Obj,"tx_duration_pct",tx_duration_pct);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"boardId",boardId);
field_to_json(Obj,"timestamp",timestamp);
field_to_json(Obj,"ap_data",ap_data);
field_to_json(Obj,"ssid_data",ssid_data);
field_to_json(Obj,"radio_data",radio_data);
field_to_json(Obj,"device_info",device_info);
field_to_json(Obj,"serialNumber",serialNumber);
}
bool DeviceTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"boardId",boardId);
field_from_json(Obj,"timestamp",timestamp);
field_from_json(Obj,"ap_data",ap_data);
field_from_json(Obj,"ssid_data",ssid_data);
field_from_json(Obj,"radio_data",radio_data);
field_from_json(Obj,"device_info",device_info);
field_from_json(Obj,"serialNumber",serialNumber);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePointAnalysis::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"noise",noise);
field_to_json(Obj,"temperature",temperature);
field_to_json(Obj,"active_pct",active_pct);
field_to_json(Obj,"busy_pct",busy_pct);
field_to_json(Obj,"receive_pct",receive_pct);
field_to_json(Obj,"transmit_pct",transmit_pct);
field_to_json(Obj,"tx_power",tx_power);
field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_to_json(Obj,"rx_packets_bw",rx_packets_bw);
field_to_json(Obj,"tx_packets_bw",tx_packets_bw);
field_to_json(Obj,"rx_errors_pct",rx_errors_pct);
field_to_json(Obj,"tx_errors_pct",tx_errors_pct);
}
bool DeviceTimePointAnalysis::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"noise",noise);
field_from_json(Obj,"temperature",temperature);
field_from_json(Obj,"active_pct",active_pct);
field_from_json(Obj,"busy_pct",busy_pct);
field_from_json(Obj,"receive_pct",receive_pct);
field_from_json(Obj,"transmit_pct",transmit_pct);
field_from_json(Obj,"tx_power",tx_power);
field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw);
field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw);
field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct);
field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct);
field_from_json(Obj,"rx_packets_bw",rx_packets_bw);
field_from_json(Obj,"tx_packets_bw",tx_packets_bw);
field_from_json(Obj,"rx_errors_pct",rx_errors_pct);
field_from_json(Obj,"tx_errors_pct",tx_errors_pct);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"points",points);
field_to_json(Obj,"stats",stats);
}
bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"points",points);
field_from_json(Obj,"stats",stats);
return true;
} catch(...) {
}
return false;
}
void DeviceTimePointStats::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"firstPoint",firstPoint);
field_to_json(Obj,"lastPoint",lastPoint);
field_to_json(Obj,"count",count);
}
bool DeviceTimePointStats::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"firstPoint",firstPoint);
field_from_json(Obj,"lastPoint",lastPoint);
field_from_json(Obj,"count",count);
return true;
} catch(...) {
}
return false;
}
void WifiClientRate::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"bitrate",bitrate);
field_to_json(Obj,"chwidth",chwidth);
field_to_json(Obj,"mcs",mcs);
field_to_json(Obj,"nss",nss);
field_to_json(Obj,"vht",vht);
}
bool WifiClientRate::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"bitrate",bitrate);
field_from_json(Obj,"chwidth",chwidth);
field_from_json(Obj,"mcs",mcs);
field_from_json(Obj,"nss",nss);
field_from_json(Obj,"vht",vht);
return true;
} catch(...) {
}
return false;
}
void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"timestamp",timestamp);
field_to_json(Obj,"station_id",station_id);
field_to_json(Obj,"bssid",bssid);
field_to_json(Obj,"ssid",ssid);
field_to_json(Obj,"rssi",rssi);
field_to_json(Obj,"rx_bitrate",rx_bitrate);
field_to_json(Obj,"rx_chwidth",rx_chwidth);
field_to_json(Obj,"rx_mcs",rx_mcs);
field_to_json(Obj,"rx_nss",rx_nss);
field_to_json(Obj,"rx_vht",rx_vht);
field_to_json(Obj,"tx_bitrate",tx_bitrate);
field_to_json(Obj,"tx_chwidth",tx_chwidth);
field_to_json(Obj,"tx_mcs",tx_mcs);
field_to_json(Obj,"tx_nss",tx_nss);
field_to_json(Obj,"tx_vht",tx_vht);
field_to_json(Obj,"rx_bytes",rx_bytes);
field_to_json(Obj,"tx_bytes",tx_bytes);
field_to_json(Obj,"rx_duration",rx_duration);
field_to_json(Obj,"tx_duration",tx_duration);
field_to_json(Obj,"rx_packets",rx_packets);
field_to_json(Obj,"tx_packets",tx_packets);
field_to_json(Obj,"ipv4",ipv4);
field_to_json(Obj,"ipv6",ipv6);
field_to_json(Obj,"channel_width",channel_width);
field_to_json(Obj,"noise",noise);
field_to_json(Obj,"tx_power",tx_power);
field_to_json(Obj,"channel",channel);
field_to_json(Obj,"active_ms",active_ms);
field_to_json(Obj,"busy_ms",busy_ms);
field_to_json(Obj,"receive_ms",receive_ms);
field_to_json(Obj,"mode",mode);
field_to_json(Obj,"ack_signal",ack_signal);
field_to_json(Obj,"ack_signal_avg",ack_signal_avg);
field_to_json(Obj,"connected",connected);
field_to_json(Obj,"inactive",inactive);
field_to_json(Obj,"tx_retries",tx_retries);
field_to_json(Obj,"venue_id",venue_id);
}
bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"timestamp",timestamp);
field_from_json(Obj,"station_id",station_id);
field_from_json(Obj,"bssid",bssid);
field_from_json(Obj,"ssid",ssid);
field_from_json(Obj,"rssi",rssi);
field_from_json(Obj,"rx_bitrate",rx_bitrate);
field_from_json(Obj,"rx_chwidth",rx_chwidth);
field_from_json(Obj,"rx_mcs",rx_mcs);
field_from_json(Obj,"rx_nss",rx_nss);
field_from_json(Obj,"rx_vht",rx_vht);
field_from_json(Obj,"tx_bitrate",tx_bitrate);
field_from_json(Obj,"tx_chwidth",tx_chwidth);
field_from_json(Obj,"tx_mcs",tx_mcs);
field_from_json(Obj,"tx_nss",tx_nss);
field_from_json(Obj,"tx_vht",tx_vht);
field_from_json(Obj,"rx_bytes",rx_bytes);
field_from_json(Obj,"tx_bytes",tx_bytes);
field_from_json(Obj,"rx_duration",rx_duration);
field_from_json(Obj,"tx_duration",tx_duration);
field_from_json(Obj,"rx_packets",rx_packets);
field_from_json(Obj,"tx_packets",tx_packets);
field_from_json(Obj,"ipv4",ipv4);
field_from_json(Obj,"ipv6",ipv6);
field_from_json(Obj,"channel_width",channel_width);
field_from_json(Obj,"noise",noise);
field_from_json(Obj,"tx_power",tx_power);
field_from_json(Obj,"channel",channel);
field_from_json(Obj,"active_ms",active_ms);
field_from_json(Obj,"busy_ms",busy_ms);
field_from_json(Obj,"receive_ms",receive_ms);
field_from_json(Obj,"mode",mode);
field_from_json(Obj,"ack_signal",ack_signal);
field_from_json(Obj,"ack_signal_avg",ack_signal_avg);
field_from_json(Obj,"connected",connected);
field_from_json(Obj,"inactive",inactive);
field_from_json(Obj,"tx_retries",tx_retries);
field_from_json(Obj,"venue_id",venue_id);
return true;
} catch(...) {
}
return false;
}
}

View File

@@ -1,422 +0,0 @@
//
// Created by stephane bourque on 2022-01-10.
//
#pragma once
#include "RESTAPI_ProvObjects.h"
#include <vector>
namespace OpenWifi {
namespace AnalyticsObjects {
struct Report {
uint64_t snapShot = 0;
void reset();
void to_json(Poco::JSON::Object &Obj) const;
};
struct VenueInfo {
OpenWifi::Types::UUID_t id;
std::string name;
std::string description;
uint64_t retention = 0;
uint64_t interval = 0;
bool monitorSubVenues = false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BoardInfo {
ProvObjects::ObjectInfo info;
std::vector<VenueInfo> venueList;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
inline bool operator<(const BoardInfo &bb) const {
return info.id < bb.info.id;
}
inline bool operator==(const BoardInfo &bb) const {
return info.id == bb.info.id;
}
};
struct DeviceInfo {
std::string boardId;
std::string type;
std::string serialNumber;
std::string deviceType;
uint64_t lastContact = 0 ;
uint64_t lastPing = 0;
uint64_t lastState = 0;
std::string lastFirmware;
uint64_t lastFirmwareUpdate = 0;
uint64_t lastConnection = 0;
uint64_t lastDisconnection = 0;
uint64_t pings = 0;
uint64_t states = 0;
bool connected = false;
std::string connectionIp;
uint64_t associations_2g = 0;
uint64_t associations_5g = 0;
uint64_t associations_6g = 0;
uint64_t health = 0;
uint64_t lastHealth = 0;
std::string locale;
uint64_t uptime = 0;
double memory = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceInfoList {
std::vector<DeviceInfo> devices;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum wifi_band {
band_2g = 0, band_5g = 1, band_6g = 2
};
struct TIDstat_entry {
uint64_t rx_msdu = 0,
tx_msdu = 0,
tx_msdu_failed = 0,
tx_msdu_retries = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct UE_rate {
uint64_t bitrate=0;
uint64_t mcs=0;
uint64_t nss=0;
bool ht=false;
bool sgi=false;
uint64_t chwidth=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AveragePoint {
double min = 0.0,
max = 0.0,
avg = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct UETimePoint {
std::string station;
int64_t rssi = 0;
uint64_t tx_bytes = 0,
rx_bytes = 0,
tx_duration = 0,
rx_packets = 0,
tx_packets = 0,
tx_retries = 0,
tx_failed = 0,
connected = 0,
inactive = 0;
double tx_bytes_bw = 0.0 ,
rx_bytes_bw = 0.0 ,
tx_packets_bw = 0.0 ,
rx_packets_bw = 0.0 ,
tx_failed_pct = 0.0 ,
tx_retries_pct = 0.0 ,
tx_duration_pct = 0.0;
uint64_t tx_bytes_delta = 0,
rx_bytes_delta = 0,
tx_duration_delta = 0,
rx_packets_delta = 0,
tx_packets_delta = 0,
tx_retries_delta = 0,
tx_failed_delta = 0;
UE_rate tx_rate,
rx_rate;
std::vector<TIDstat_entry> tidstats;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum SSID_MODES {
unknown = 0,
ap,
mesh,
sta,
wds_ap,
wds_sta,
wds_repeater
};
inline SSID_MODES SSID_Mode(const std::string &m) {
if (m == "ap")
return ap;
if (m == "sta")
return sta;
if (m == "mesh")
return mesh;
if (m == "wds-ap")
return wds_ap;
if (m == "wds-sta")
return wds_sta;
if (m == "wds-repeater")
return wds_repeater;
return unknown;
}
struct SSIDTimePoint {
std::string bssid,
mode,
ssid;
uint64_t band=0,
channel=0;
std::vector<UETimePoint> associations;
AveragePoint tx_bytes_bw,
rx_bytes_bw,
tx_packets_bw,
rx_packets_bw,
tx_failed_pct,
tx_retries_pct,
tx_duration_pct;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct APTimePoint {
uint64_t collisions = 0,
multicast = 0,
rx_bytes = 0,
rx_dropped = 0,
rx_errors = 0,
rx_packets = 0,
tx_bytes = 0,
tx_dropped = 0,
tx_errors = 0,
tx_packets = 0;
double tx_bytes_bw = 0.0 ,
rx_bytes_bw = 0.0 ,
rx_dropped_pct = 0.0,
tx_dropped_pct = 0.0,
rx_packets_bw = 0.0,
tx_packets_bw = 0.0,
rx_errors_pct = 0.0 ,
tx_errors_pct = 0.0;
uint64_t tx_bytes_delta = 0,
rx_bytes_delta = 0 ,
rx_dropped_delta = 0,
tx_dropped_delta = 0,
rx_packets_delta = 0,
tx_packets_delta = 0,
rx_errors_delta = 0,
tx_errors_delta = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadioTimePoint {
uint64_t band = 0,
channel_width = 0;
uint64_t active_ms = 0,
busy_ms = 0,
receive_ms = 0,
transmit_ms = 0,
tx_power = 0,
channel = 0;
int64_t temperature = 0,
noise = 0;
double active_pct = 0.0 ,
busy_pct = 0.0,
receive_pct = 0.0,
transmit_pct = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceTimePoint {
std::string id;
std::string boardId;
uint64_t timestamp = 0;
APTimePoint ap_data;
std::vector<SSIDTimePoint> ssid_data;
std::vector<RadioTimePoint> radio_data;
AnalyticsObjects::DeviceInfo device_info;
std::string serialNumber;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
inline bool operator<(const DeviceTimePoint &rhs) const {
if(timestamp < rhs.timestamp)
return true;
if(timestamp > rhs.timestamp)
return false;
if(device_info.serialNumber < rhs.device_info.serialNumber)
return true;
return false;
}
inline bool operator==(const DeviceTimePoint &rhs) const {
return timestamp==rhs.timestamp && device_info.serialNumber==rhs.device_info.serialNumber;
}
inline bool operator>(const DeviceTimePoint &rhs) const {
if(timestamp > rhs.timestamp)
return true;
if(timestamp < rhs.timestamp)
return false;
if(device_info.serialNumber > rhs.device_info.serialNumber)
return true;
return false;
}
};
struct DeviceTimePointAnalysis {
uint64_t timestamp;
AveragePoint noise;
AveragePoint temperature;
AveragePoint active_pct;
AveragePoint busy_pct;
AveragePoint receive_pct;
AveragePoint transmit_pct;
AveragePoint tx_power;
AveragePoint tx_bytes_bw;
AveragePoint rx_bytes_bw;
AveragePoint rx_dropped_pct;
AveragePoint tx_dropped_pct;
AveragePoint rx_packets_bw;
AveragePoint tx_packets_bw;
AveragePoint rx_errors_pct;
AveragePoint tx_errors_pct;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceTimePointList {
std::vector<DeviceTimePoint> points;
std::vector<DeviceTimePointAnalysis> stats;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BandwidthAnalysisEntry {
uint64_t timestamp = 0;
};
struct BandwidthAnalysis {
};
struct AverageValueSigned {
int64_t peak=0, avg=0, low=0;
};
struct AverageValueUnsigned {
uint64_t peak=0, avg=0, low=0;
};
struct RadioAnalysis {
uint64_t timestamp=0;
AverageValueSigned noise, temperature;
AverageValueUnsigned active_ms,
busy_ms,
transmit_ms,
receive_ms;
};
struct DeviceTimePointStats {
uint64_t firstPoint=0;
uint64_t lastPoint=0;
uint64_t count=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct WifiClientRate {
uint32_t bitrate=0;
uint32_t chwidth=0;
uint16_t mcs=0;
uint16_t nss=0;
bool vht=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct WifiClientHistory {
uint64_t timestamp=OpenWifi::Now();
std::string station_id;
std::string bssid;
std::string ssid;
int64_t rssi=0;
uint32_t rx_bitrate=0;
uint32_t rx_chwidth=0;
uint16_t rx_mcs=0;
uint16_t rx_nss=0;
bool rx_vht=false;
uint32_t tx_bitrate=0;
uint32_t tx_chwidth=0;
uint16_t tx_mcs=0;
uint16_t tx_nss=0;
bool tx_vht=false;
uint64_t rx_bytes=0;
uint64_t tx_bytes=0;
uint64_t rx_duration=0;
uint64_t tx_duration=0;
uint64_t rx_packets=0;
uint64_t tx_packets=0;
std::string ipv4;
std::string ipv6;
uint64_t channel_width=0;
int64_t noise=0;
uint64_t tx_power=0;
uint64_t channel=0;
uint64_t active_ms=0;
uint64_t busy_ms=0;
uint64_t receive_ms=0;
std::string mode;
int64_t ack_signal=0;
int64_t ack_signal_avg=0;
uint64_t connected=0;
uint64_t inactive=0;
uint64_t tx_retries=0;
std::string venue_id;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
}

View File

@@ -1,208 +0,0 @@
//
// Created by stephane bourque on 2021-12-07.
//
#include "RESTAPI_CertObjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::CertObjects {
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"type", type);
field_to_json(Obj,"status", status);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"devid", devid);
field_to_json(Obj,"cas", cas);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonName", commonName);
field_to_json(Obj,"certificateId", certificateId);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"revoked", revoked);
field_to_json(Obj,"revokeCount", revokeCount);
field_to_json(Obj,"synched", synched);
}
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"type", type);
field_from_json(Obj,"status", status);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"devid", devid);
field_from_json(Obj,"cas", cas);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonName", commonName);
field_from_json(Obj,"certificateId", certificateId);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"revoked", revoked);
field_from_json(Obj,"revokeCount", revokeCount);
field_from_json(Obj,"synched", synched);
return true;
} catch (...) {
}
return false;
}
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"defaultRedirector", defaultRedirector);
field_to_json(Obj,"apiKey", apiKey);
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_to_json(Obj,"organization", organization);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"suspended", suspended);
field_to_json(Obj,"deleted", deleted);
field_to_json(Obj,"notes", notes);
}
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"defaultRedirector", defaultRedirector);
field_from_json(Obj,"apiKey", apiKey);
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_from_json(Obj,"organization", organization);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"suspended", suspended);
field_from_json(Obj,"deleted", deleted);
field_from_json(Obj,"notes", notes);
return true;
} catch (...) {
}
return false;
}
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"jobHistory", jobHistory);
field_to_json(Obj,"notes", notes);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
field_to_json(Obj,"modified", modified);
}
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"jobHistory", jobHistory);
field_from_json(Obj,"notes", notes);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
field_from_json(Obj,"modified", modified);
return true;
} catch (...) {
}
return false;
}
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"completedNames", completedNames);
field_to_json(Obj,"errorNames", errorNames);
field_to_json(Obj,"status", status);
field_to_json(Obj,"command", command);
field_to_json(Obj,"parameters", parameters);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
}
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"completedNames", completedNames);
field_from_json(Obj,"errorNames", errorNames);
field_from_json(Obj,"status", status);
field_from_json(Obj,"command", command);
field_from_json(Obj,"parameters", parameters);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
return true;
} catch (...) {
}
return false;
}
void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "year", year);
field_to_json(Obj, "activeCerts", activeCerts);
field_to_json(Obj, "revokedCerts", revokedCerts);
}
void Dashboard::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"snapshot", snapshot);
field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts);
field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts);
field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization);
field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization);
field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors);
field_to_json(Obj,"deviceTypes", deviceTypes);
field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts);
field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear);
}
void Dashboard::reset() {
snapshot=0;
numberOfRevokedCerts = numberOfIssuedCerts = 0;
activeCertsPerOrganization.clear();
revokedCertsPerOrganization.clear();
numberOfRedirectors.clear();
deviceTypes.clear();
monthlyNumberOfCerts.clear();
monthlyNumberOfCertsPerOrgPerYear.clear();
}
}

View File

@@ -1,122 +0,0 @@
//
// Created by stephane bourque on 2021-12-07.
//
#pragma once
#include <string>
#include "framework/OpenWifiTypes.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi::CertObjects {
struct CertificateEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string type;
std::string status;
std::string certificate;
std::string key;
std::string devid;
std::string cas;
std::string manufacturer;
std::string model;
std::string redirector;
std::string commonName;
std::string certificateId;
OpenWifi::Types::UUID_t batch;
uint64_t created = 0;
uint64_t modified = 0;
uint64_t revoked = 0;
uint64_t revokeCount = 0;
uint64_t synched = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct EntityEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string defaultRedirector;
std::string apiKey;
std::string serverEnrollmentProfile;
std::string clientEnrollmentProfile;
std::string organization;
SecurityObjects::NoteInfoVec notes;
bool suspended=false;
bool deleted=false;
uint64_t created = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BatchEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string manufacturer;
std::string model;
std::string redirector;
std::vector<std::string> commonNames;
std::vector<std::string> jobHistory;
SecurityObjects::NoteInfoVec notes;
uint64_t submitted = 0 ;
uint64_t started = 0 ;
uint64_t completed = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct JobEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
OpenWifi::Types::UUID_t batch;
std::string command;
OpenWifi::Types::StringVec commonNames;
OpenWifi::Types::StringVec completedNames;
OpenWifi::Types::StringVec errorNames;
Types::StringPairVec parameters;
std::string status;
uint64_t submitted=0;
uint64_t started=0;
uint64_t completed=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DashBoardYearlyStats {
uint64_t year=0;
OpenWifi::Types::Counted3DMapSII activeCerts;
OpenWifi::Types::Counted3DMapSII revokedCerts;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
uint64_t snapshot=0;
uint64_t numberOfIssuedCerts=0;
uint64_t numberOfRevokedCerts=0;
OpenWifi::Types::CountedMap activeCertsPerOrganization;
OpenWifi::Types::CountedMap revokedCertsPerOrganization;
OpenWifi::Types::CountedMap numberOfRedirectors;
OpenWifi::Types::CountedMap deviceTypes;
OpenWifi::Types::CountedMap monthlyNumberOfCerts;
std::vector<DashBoardYearlyStats> monthlyNumberOfCertsPerOrgPerYear;
void to_json(Poco::JSON::Object &Obj) const;
void reset();
};
}

View File

@@ -233,10 +233,10 @@ namespace OpenWifi::FMSObjects {
UnknownFirmwares_.clear();
totalSecondsOld_.clear();
numberOfDevices = 0 ;
snapshot = OpenWifi::Now();
snapshot = std::time(nullptr);
}
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
bool DeviceReport::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
return true;
@@ -245,65 +245,4 @@ namespace OpenWifi::FMSObjects {
}
return false;
}
void DeviceInformation::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "serialNumber",serialNumber);
field_to_json(Obj, "history", history);
field_to_json(Obj, "currentFirmware", currentFirmware);
field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate);
field_to_json(Obj, "latestFirmware", latestFirmware);
field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate);
field_to_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable);
field_to_json(Obj, "latestFirmwareURI",latestFirmwareURI);
}
bool DeviceInformation::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber",serialNumber);
field_from_json(Obj, "history", history);
field_from_json(Obj, "currentFirmware", currentFirmware);
field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate);
field_from_json(Obj, "latestFirmware", latestFirmware);
field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate);
field_from_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable);
field_from_json(Obj, "latestFirmwareURI",latestFirmwareURI);
return true;
} catch(...) {
}
return false;
}
void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "serialNumber",serialNumber);
field_to_json(Obj, "revision", revision);
field_to_json(Obj, "upgraded", upgraded);
}
bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber",serialNumber);
field_from_json(Obj, "revision", revision);
field_from_json(Obj, "upgraded", upgraded);
return true;
} catch(...) {
}
return false;
}
void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "devices",devices);
}
bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "devices",devices);
return true;
} catch(...) {
}
return false;
}
}

View File

@@ -4,7 +4,9 @@
#include <string>
#pragma once
#ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H
#define UCENTRALFMS_RESTAPI_FMSOBJECTS_H
#include "RESTAPI_SecurityObjects.h"
#include "framework/OpenWifiTypes.h"
@@ -125,35 +127,7 @@ namespace OpenWifi::FMSObjects {
void reset();
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceInformation {
std::string serialNumber;
RevisionHistoryEntryList history;
std::string currentFirmware;
uint64_t currentFirmwareDate=0;
std::string latestFirmware;
uint64_t latestFirmwareDate=0;
bool latestFirmwareAvailable;
std::string latestFirmwareURI;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceCurrentInfo {
std::string serialNumber;
std::string revision;
uint64_t upgraded=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceCurrentInfoList {
std::vector<DeviceCurrentInfo> devices;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
#endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H

View File

@@ -12,7 +12,6 @@
#include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE
#include "DeviceRegistry.h"
#include "CapabilitiesCache.h"
#endif
#include "RESTAPI_GWobjects.h"
@@ -27,7 +26,7 @@ namespace OpenWifi::GWObjects {
void Device::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber);
#ifdef TIP_GATEWAY_SERVICE
field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible));
field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible));
#endif
field_to_json(Obj,"macAddress", MACAddress);
field_to_json(Obj,"manufacturer", Manufacturer);
@@ -45,10 +44,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"compatible", Compatible);
field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy);
field_to_json(Obj,"devicePassword", DevicePassword);
field_to_json(Obj,"subscriber", subscriber);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"locale", locale);
}
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -73,7 +68,7 @@ namespace OpenWifi::GWObjects {
#endif
}
bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool Device::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"serialNumber",SerialNumber);
field_from_json(Obj,"deviceType",DeviceType);
@@ -85,9 +80,6 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"location",Location);
field_from_json(Obj,"venue",Venue);
field_from_json(Obj,"compatible",Compatible);
field_from_json(Obj,"subscriber", subscriber);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"locale", locale);
return true;
} catch (const Poco::Exception &E) {
}
@@ -153,10 +145,9 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"custom", Custom);
field_to_json(Obj,"waitingForFile", WaitingForFile);
field_to_json(Obj,"attachFile", AttachDate);
field_to_json(Obj,"executionTime", executionTime);
}
bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"name",Name);
field_from_json(Obj,"configuration",Configuration);
@@ -175,7 +166,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"created", created);
}
bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"author",author);
@@ -188,6 +179,7 @@ namespace OpenWifi::GWObjects {
}
void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber);
field_to_json(Obj,"ipAddress", Address);
field_to_json(Obj,"txBytes", TX);
field_to_json(Obj,"rxBytes", RX);
@@ -198,15 +190,6 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"lastContact", LastContact);
field_to_json(Obj,"associations_2G", Associations_2G);
field_to_json(Obj,"associations_5G", Associations_5G);
field_to_json(Obj,"webSocketClients", webSocketClients);
field_to_json(Obj,"websocketPackets", websocketPackets);
field_to_json(Obj,"kafkaClients", kafkaClients);
field_to_json(Obj,"kafkaPackets", kafkaPackets);
field_to_json(Obj,"locale", locale);
field_to_json(Obj,"started", started);
field_to_json(Obj,"sessionId", sessionId);
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started);
switch(VerifiedCertificate) {
case NO_CERTIFICATE:
@@ -222,21 +205,6 @@ namespace OpenWifi::GWObjects {
}
}
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
field_to_json(Obj,"connectedDevices", connectedDevices );
}
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
field_from_json(Obj,"connectedDevices", connectedDevices );
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber);
field_to_json(Obj,"server", Server);
@@ -283,7 +251,7 @@ namespace OpenWifi::GWObjects {
lastContact.clear();
associations.clear();
numberOfDevices = 0 ;
snapshot = OpenWifi::Now();
snapshot = std::time(nullptr);
}
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
@@ -291,123 +259,5 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"capabilities", capabilities);
};
void ScriptRequest::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"timeout",timeout);
field_to_json(Obj,"type",type);
field_to_json(Obj,"script",script);
field_to_json(Obj,"scriptId",scriptId);
field_to_json(Obj,"when",when);
}
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"timeout",timeout);
field_from_json(Obj,"type",type);
field_from_json(Obj,"script",script);
field_from_json(Obj,"scriptId",scriptId);
field_from_json(Obj,"when",when);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"pools",pools);
}
bool RadiusProxyPoolList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"pools",pools);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RadiusProxyPool::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"name",name);
field_to_json(Obj,"description",description);
field_to_json(Obj,"authConfig",authConfig);
field_to_json(Obj,"acctConfig",acctConfig);
field_to_json(Obj,"coaConfig",coaConfig);
field_to_json(Obj,"useByDefault",useByDefault);
}
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"name",name);
field_from_json(Obj,"description",description);
field_from_json(Obj,"authConfig",authConfig);
field_from_json(Obj,"acctConfig",acctConfig);
field_from_json(Obj,"coaConfig",coaConfig);
field_from_json(Obj,"useByDefault",useByDefault);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"strategy",strategy);
field_to_json(Obj,"monitor",monitor);
field_to_json(Obj,"monitorMethod",monitorMethod);
field_to_json(Obj,"methodParameters",methodParameters);
field_to_json(Obj,"servers",servers);
}
bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"strategy",strategy);
field_from_json(Obj,"monitor",monitor);
field_from_json(Obj,"monitorMethod",monitorMethod);
field_from_json(Obj,"methodParameters",methodParameters);
field_from_json(Obj,"servers",servers);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RadiusProxyServerEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"name",name);
field_to_json(Obj,"ip",ip);
field_to_json(Obj,"port",port);
field_to_json(Obj,"weight",weight);
field_to_json(Obj,"secret",secret);
field_to_json(Obj,"certificate",certificate);
field_to_json(Obj,"radsec",radsec);
field_to_json(Obj,"radsecPort",radsecPort);
field_to_json(Obj,"radsecSecret",radsecSecret);
field_to_json(Obj,"radsecCacerts",radsecCacerts);
field_to_json(Obj,"radsecCert",radsecCert);
field_to_json(Obj,"radsecKey",radsecKey);
field_to_json(Obj,"radsecRealms",radsecRealms);
field_to_json(Obj,"ignore",ignore);
}
bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"name",name);
field_from_json(Obj,"ip",ip);
field_from_json(Obj,"port",port);
field_from_json(Obj,"weight",weight);
field_from_json(Obj,"secret",secret);
field_from_json(Obj,"certificate",certificate);
field_from_json(Obj,"radsec",radsec);
field_from_json(Obj,"radsecSecret",radsecSecret);
field_from_json(Obj,"radsecPort",radsecPort);
field_from_json(Obj,"radsecCacerts",radsecCacerts);
field_from_json(Obj,"radsecCert",radsecCert);
field_from_json(Obj,"radsecKey",radsecKey);
field_from_json(Obj,"radsecRealms",radsecRealms);
field_from_json(Obj,"ignore",ignore);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
}

View File

@@ -6,7 +6,8 @@
// Arilia Wireless Inc.
//
#pragma once
#ifndef UCENTRAL_RESTAPI_OBJECTS_H
#define UCENTRAL_RESTAPI_OBJECTS_H
#include "Poco/JSON/Object.h"
#include "RESTAPI_SecurityObjects.h"
@@ -22,6 +23,7 @@ namespace OpenWifi::GWObjects {
struct ConnectionState {
uint64_t MessageCount = 0 ;
std::string SerialNumber;
std::string Address;
uint64_t UUID = 0 ;
uint64_t PendingUUID = 0 ;
@@ -33,15 +35,6 @@ namespace OpenWifi::GWObjects {
std::string Firmware;
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
std::string Compatible;
uint64_t kafkaClients=0;
uint64_t webSocketClients=0;
uint64_t kafkaPackets=0;
uint64_t websocketPackets=0;
std::string locale;
uint64_t started=0;
uint64_t sessionId=0;
double connectionCompletionTime=0.0;
void to_json(Poco::JSON::Object &Obj) const;
};
@@ -57,52 +50,40 @@ namespace OpenWifi::GWObjects {
std::string Firmware;
std::string Compatible;
std::string FWUpdatePolicy;
uint64_t UUID = 0 ;
uint64_t CreationTimestamp = 0 ;
uint64_t LastConfigurationChange = 0 ;
uint64_t LastConfigurationDownload = 0 ;
uint64_t LastFWUpdate = 0 ;
uint64_t UUID;
uint64_t CreationTimestamp;
uint64_t LastConfigurationChange;
uint64_t LastConfigurationDownload;
uint64_t LastFWUpdate;
std::string Venue;
std::string DevicePassword;
std::string subscriber;
std::string entity;
uint64_t modified=0;
std::string locale;
void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
void Print() const;
};
struct DeviceConnectionStatistics {
std::uint64_t connectedDevices = 0;
std::uint64_t averageConnectionTime = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Statistics {
std::string SerialNumber;
uint64_t UUID = 0 ;
uint64_t UUID;
std::string Data;
uint64_t Recorded = 0;
uint64_t Recorded;
void to_json(Poco::JSON::Object &Obj) const;
};
struct HealthCheck {
std::string SerialNumber;
uint64_t UUID = 0 ;
uint64_t UUID;
std::string Data;
uint64_t Recorded = 0 ;
uint64_t Sanity = 0 ;
uint64_t Recorded;
uint64_t Sanity;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Capabilities {
std::string Capabilities;
uint64_t FirstUpdate = 0 ;
uint64_t LastUpdate = 0 ;
uint64_t FirstUpdate;
uint64_t LastUpdate;
void to_json(Poco::JSON::Object &Obj) const;
};
@@ -120,22 +101,22 @@ namespace OpenWifi::GWObjects {
std::string SerialNumber;
std::string Log;
std::string Data;
uint64_t Severity = 0 ;
uint64_t Recorded = 0 ;
uint64_t LogType = 0 ;
uint64_t UUID = 0 ;
uint64_t Severity;
uint64_t Recorded;
uint64_t LogType;
uint64_t UUID;
void to_json(Poco::JSON::Object &Obj) const;
};
struct DefaultConfiguration {
std::string Name;
std::string Configuration;
Types::StringVec Models;
std::string Models;
std::string Description;
uint64_t Created;
uint64_t LastModified;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct CommandDetails {
@@ -157,7 +138,6 @@ namespace OpenWifi::GWObjects {
uint64_t AttachDate = 0 ;
uint64_t AttachSize = 0 ;
std::string AttachType;
double executionTime = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
};
@@ -167,26 +147,26 @@ namespace OpenWifi::GWObjects {
std::string author;
uint64_t created;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct RttySessionDetails {
std::string SerialNumber;
std::string Server;
uint64_t Port = 0 ;
uint64_t Port;
std::string Token;
uint64_t TimeOut = 0 ;
uint64_t TimeOut;
std::string ConnectionId;
uint64_t Started = 0 ;
uint64_t Started;
std::string CommandUUID;
uint64_t ViewPort = 0 ;
uint64_t ViewPort;
std::string DevicePassword;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
uint64_t snapshot = 0 ;
uint64_t numberOfDevices = 0 ;
uint64_t snapshot;
uint64_t numberOfDevices;
Types::CountedMap commands;
Types::CountedMap upTimes;
Types::CountedMap memoryUsed;
@@ -210,65 +190,6 @@ namespace OpenWifi::GWObjects {
void to_json(Poco::JSON::Object &Obj) const;
};
struct ScriptRequest {
uint64_t timeout=30;
std::string serialNumber;
std::string type;
std::string script;
std::string scriptId;
uint64_t when=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadiusProxyServerEntry {
std::string name;
std::string ip;
uint16_t port=0;
uint64_t weight=0;
std::string secret;
std::string certificate;
bool radsec=false;
uint16_t radsecPort=2083;
std::string radsecSecret;
std::string radsecKey;
std::string radsecCert;
std::vector<std::string> radsecCacerts;
std::vector<std::string> radsecRealms;
bool ignore=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadiusProxyServerConfig {
std::string strategy;
bool monitor=false;
std::string monitorMethod;
std::vector<std::string> methodParameters;
std::vector<RadiusProxyServerEntry> servers;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadiusProxyPool {
std::string name;
std::string description;
RadiusProxyServerConfig authConfig;
RadiusProxyServerConfig acctConfig;
RadiusProxyServerConfig coaConfig;
bool useByDefault=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadiusProxyPoolList {
std::vector<RadiusProxyPool> pools;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
#endif //UCENTRAL_RESTAPI_OBJECTS_H

View File

@@ -1,110 +0,0 @@
//
// Created by stephane bourque on 2021-08-31.
//
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
using OpenWifi::RESTAPI_utils::EmbedDocument;
#include "RESTAPI_OWLSobjects.h"
// SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d
namespace OpenWifi::OWLSObjects {
void SimulationDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"name", name);
field_to_json(Obj,"gateway", gateway);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"macPrefix", macPrefix);
field_to_json(Obj,"deviceType", deviceType);
field_to_json(Obj,"devices", devices);
field_to_json(Obj,"healthCheckInterval", healthCheckInterval);
field_to_json(Obj,"stateInterval", stateInterval);
field_to_json(Obj,"minAssociations", minAssociations);
field_to_json(Obj,"maxAssociations", maxAssociations);
field_to_json(Obj,"minClients", minClients);
field_to_json(Obj,"maxClients", maxClients);
field_to_json(Obj,"simulationLength", simulationLength);
field_to_json(Obj,"threads", threads);
field_to_json(Obj,"clientInterval", clientInterval);
field_to_json(Obj,"keepAlive", keepAlive);
field_to_json(Obj,"reconnectInterval", reconnectInterval);
field_to_json(Obj,"concurrentDevices", concurrentDevices);
}
bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"name", name);
field_from_json(Obj,"gateway", gateway);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"macPrefix", macPrefix);
field_from_json(Obj,"deviceType", deviceType);
field_from_json(Obj,"devices", devices);
field_from_json(Obj,"healthCheckInterval", healthCheckInterval);
field_from_json(Obj,"stateInterval", stateInterval);
field_from_json(Obj,"minAssociations", minAssociations);
field_from_json(Obj,"maxAssociations", maxAssociations);
field_from_json(Obj,"minClients", minClients);
field_from_json(Obj,"maxClients", maxClients);
field_from_json(Obj,"simulationLength", simulationLength);
field_from_json(Obj,"threads", threads);
field_from_json(Obj,"clientInterval", clientInterval);
field_from_json(Obj,"keepAlive", keepAlive);
field_from_json(Obj,"reconnectInterval", reconnectInterval);
field_from_json(Obj,"concurrentDevices", concurrentDevices);
return true;
} catch(...) {
}
return false;
}
void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"list", list);
}
bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"list", list);
return true;
} catch(...) {
}
return false;
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"simulationId", simulationId);
field_to_json(Obj,"state", state);
field_to_json(Obj,"tx", tx);
field_to_json(Obj,"rx", rx);
field_to_json(Obj,"msgsTx", msgsTx);
field_to_json(Obj,"msgsRx", msgsRx);
field_to_json(Obj,"liveDevices", liveDevices);
field_to_json(Obj,"timeToFullDevices", timeToFullDevices);
field_to_json(Obj,"startTime", startTime);
field_to_json(Obj,"endTime", endTime);
field_to_json(Obj,"errorDevices", errorDevices);
field_to_json(Obj,"owner", owner);
}
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
}
bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
return true;
}
void Dashboard::reset() {
}
}

View File

@@ -1,77 +0,0 @@
//
// Created by stephane bourque on 2021-08-31.
//
#ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
#define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
#include <vector>
#include "Poco/JSON/Object.h"
namespace OpenWifi::OWLSObjects {
struct SimulationDetails {
std::string id;
std::string name;
std::string gateway;
std::string certificate;
std::string key;
std::string macPrefix;
std::string deviceType;
uint64_t devices = 5;
uint64_t healthCheckInterval = 60;
uint64_t stateInterval = 60 ;
uint64_t minAssociations = 1;
uint64_t maxAssociations = 3;
uint64_t minClients = 1 ;
uint64_t maxClients = 3;
uint64_t simulationLength = 60 * 60;
uint64_t threads = 16;
uint64_t clientInterval = 1;
uint64_t keepAlive = 300;
uint64_t reconnectInterval = 30 ;
uint64_t concurrentDevices = 5;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationDetailsList {
std::vector<SimulationDetails> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
int O;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void reset();
};
}
#endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H

File diff suppressed because it is too large Load Diff

View File

@@ -6,20 +6,15 @@
// Arilia Wireless Inc.
//
#pragma once
#ifndef OWPROV_RESTAPI_PROVOBJECTS_H
#define OWPROV_RESTAPI_PROVOBJECTS_H
#include <string>
#include "RESTAPI_SecurityObjects.h"
namespace OpenWifi::ProvObjects {
enum FIRMWARE_UPGRADE_RULES {
dont_upgrade,
upgrade_inherit,
upgrade_release_only,
upgrade_latest
};
struct ObjectInfo {
Types::UUID_t id;
std::string name;
@@ -33,13 +28,6 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SerialNumberList {
Types::UUIDvec_t serialNumbers;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ManagementPolicyEntry {
Types::UUIDvec_t users;
Types::UUIDvec_t resources;
@@ -55,22 +43,12 @@ namespace OpenWifi::ProvObjects {
std::vector<ManagementPolicyEntry> entries;
Types::StringVec inUse;
Types::UUID_t entity;
Types::UUID_t venue;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
struct DeviceRules {
std::string rcOnly{"inherit"};
std::string rrm{"inherit"};
std::string firmwareUpgrade{"inherit"};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Entity {
ObjectInfo info;
Types::UUID_t parent;
@@ -81,13 +59,8 @@ namespace OpenWifi::ProvObjects {
Types::UUID_t managementPolicy;
Types::UUIDvec_t deviceConfiguration;
Types::UUIDvec_t devices;
DeviceRules deviceRules;
std::string rrm;
Types::StringVec sourceIP;
Types::UUIDvec_t variables;
Types::UUIDvec_t managementPolicies;
Types::UUIDvec_t managementRoles;
Types::UUIDvec_t maps;
Types::UUIDvec_t configurations;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -114,16 +87,10 @@ namespace OpenWifi::ProvObjects {
DiGraph topology;
std::string design;
Types::UUIDvec_t deviceConfiguration;
Types::UUIDvec_t contacts;
std::string contact;
std::string location;
DeviceRules deviceRules;
std::string rrm;
Types::StringVec sourceIP;
Types::UUIDvec_t variables;
Types::UUIDvec_t configurations;
Types::UUIDvec_t maps;
Types::UUIDvec_t managementPolicies;
Types::UUIDvec_t managementRoles;
Types::UUIDvec_t boards;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -145,7 +112,6 @@ namespace OpenWifi::ProvObjects {
Types::UUIDvec_t users;
Types::StringVec inUse;
Types::UUID_t entity;
Types::UUID_t venue;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -209,51 +175,6 @@ namespace OpenWifi::ProvObjects {
};
typedef std::vector<Location> LocationVec;
struct OperatorLocation {
ObjectInfo info;
std::string type;
std::string buildingName;
Types::StringVec addressLines;
std::string city;
std::string state;
std::string postal;
std::string country;
Types::StringVec phones;
Types::StringVec mobiles;
std::string geoCode;
Types::UUID_t operatorId;
Types::UUID_t subscriberDeviceId;
Types::UUID_t managementPolicy;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<Location> LocationVec;
struct SubLocation {
std::string type;
std::string buildingName;
Types::StringVec addressLines;
std::string city;
std::string state;
std::string postal;
std::string country;
Types::StringVec phones;
Types::StringVec mobiles;
std::string geoCode;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct OperatorLocationList {
std::vector<OperatorLocation> locations;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum ContactType {
CT_SUBSCRIBER, CT_USER, CT_INSTALLER, CT_CSR, CT_MANAGER,
CT_BUSINESSOWNER, CT_TECHNICIAN, CT_CORPORATE, CT_UNKNOWN
@@ -317,55 +238,6 @@ namespace OpenWifi::ProvObjects {
};
typedef std::vector<Contact> ContactVec;
struct OperatorContact {
ObjectInfo info;
std::string type;
std::string title;
std::string salutation;
std::string firstname;
std::string lastname;
std::string initials;
std::string visual;
Types::StringVec mobiles;
Types::StringVec phones;
std::string primaryEmail;
std::string secondaryEmail;
std::string accessPIN;
Types::UUID_t operatorId;
Types::UUID_t subscriberDeviceId;
Types::UUID_t managementPolicy;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubContact {
std::string type;
std::string title;
std::string salutation;
std::string firstname;
std::string lastname;
std::string initials;
std::string visual;
Types::StringVec mobiles;
Types::StringVec phones;
std::string primaryEmail;
std::string secondaryEmail;
std::string accessPIN;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct OperatorContactList {
std::vector<OperatorContact> contacts;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<OperatorContact> OperatorContactVec;
struct DeviceConfigurationElement {
std::string name;
std::string description;
@@ -383,19 +255,16 @@ namespace OpenWifi::ProvObjects {
Types::StringVec deviceTypes;
DeviceConfigurationElementVec configuration;
Types::StringVec inUse;
Types::UUIDvec_t variables;
DeviceRules deviceRules;
bool subscriberOnly=false;
std::string venue;
std::string entity;
std::string subscriber;
Types::StringPairVec variables;
std::string rrm;
std::string firmwareUpgrade;
bool firmwareRCOnly=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<DeviceConfiguration> DeviceConfigurationVec;
struct InventoryTag {
ObjectInfo info;
std::string serialNumber;
@@ -408,36 +277,14 @@ namespace OpenWifi::ProvObjects {
std::string location;
std::string contact;
std::string deviceConfiguration;
DeviceRules deviceRules;
std::string rrm;
Types::UUID_t managementPolicy;
std::string state;
std::string devClass;
std::string locale;
std::string realMacAddress;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<InventoryTag> InventoryTagVec;
struct InventoryTagList {
InventoryTagVec taglist;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct InventoryConfigApplyResult {
std::string appliedConfiguration;
Types::StringVec errors;
Types::StringVec warnings;
uint64_t errorCode;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Report {
uint64_t snapShot=0;
Types::CountedMap tenants;
@@ -470,216 +317,8 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct UuidList {
Types::UUIDvec_t list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum ACLACCESS {
NONE = 0, READ=1, MODIFY=2, CREATE=3, DELETE=4
};
struct ObjectACL {
UuidList users;
UuidList roles;
uint64_t access = (uint64_t) NONE;
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{"private"};
ObjectACLList access;
Types::UUID_t managementPolicy;
std::string venue;
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);
};
enum SignupStatusCodes {
SignupCreated = 0 ,
SignupWaitingForEmail,
SignupWaitingForDevice,
SignupSuccess,
SignupFailure,
SignupCanceled,
SignupTimedOut
};
struct SignupEntry {
ObjectInfo info;
std::string email;
std::string userId;
std::string macAddress;
std::string serialNumber;
uint64_t submitted = 0 ;
uint64_t completed = 0 ;
std::string status;
uint64_t error=0;
uint64_t statusCode=0;
std::string deviceID;
std::string registrationId;
std::string operatorId;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Variable {
std::string type;
uint64_t weight=0;
std::string prefix;
std::string value;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct VariableList {
std::vector<Variable> variables;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct VariableBlock {
ObjectInfo info;
std::vector<Variable> variables;
std::string entity;
std::string venue;
std::string subscriber;
std::string inventory;
Types::UUIDvec_t configurations;
Types::UUID_t managementPolicy;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct VariableBlockList {
std::vector<VariableBlock> variableBlocks;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Operator {
ObjectInfo info;
Types::UUID_t managementPolicy;
Types::UUIDvec_t managementRoles;
DeviceRules deviceRules;
std::vector<Variable> variables;
bool defaultOperator=false;
Types::StringVec sourceIP;
std::string registrationId;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct OperatorList {
std::vector<Operator> operators;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct VenueDeviceList {
std::string id;
std::string name;
std::string description;
Types::UUIDvec_t devices;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ServiceClass {
ObjectInfo info;
Types::UUID_t operatorId;
Types::UUID_t managementPolicy;
double cost=0.0;
std::string currency;
std::string period;
std::string billingCode;
std::vector<Variable> variables;
bool defaultService=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ServiceClassList {
std::vector<ServiceClass> serviceClasses;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ConfigurationDetails {
DeviceConfigurationElementVec configuration;
std::string rrm{"inherit"};
std::string firmwareUpgrade{"inherit"};
std::string firmwareRCOnly{"inherit"};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubscriberDevice {
ObjectInfo info;
std::string serialNumber;
std::string deviceType;
Types::UUID_t operatorId;
Types::UUID_t subscriberId;
SubLocation location;
SubContact contact;
Types::UUID_t managementPolicy;
Types::UUID_t serviceClass;
std::string qrCode;
std::string geoCode;
DeviceRules deviceRules;
std::string state;
std::string locale;
std::string billingCode;
DeviceConfigurationElementVec configuration;
bool suspended=false;
std::string realMacAddress;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubscriberDeviceList {
std::vector<SubscriberDevice> subscriberDevices;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I);
};
#endif //OWPROV_RESTAPI_PROVOBJECTS_H

View File

@@ -54,8 +54,6 @@ namespace OpenWifi::SecurityObjects {
return ADMIN;
else if (!Poco::icompare(U,"subscriber"))
return SUBSCRIBER;
else if (!Poco::icompare(U,"partner"))
return PARTNER;
else if (!Poco::icompare(U,"csr"))
return CSR;
else if (!Poco::icompare(U, "system"))
@@ -74,7 +72,6 @@ namespace OpenWifi::SecurityObjects {
case ROOT: return "root";
case ADMIN: return "admin";
case SUBSCRIBER: return "subscriber";
case PARTNER: return "partner";
case CSR: return "csr";
case SYSTEM: return "system";
case INSTALLER: return "installer";
@@ -95,7 +92,6 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "PortalLogin", PortalLogin_);
return true;
} catch(...) {
std::cout << "Cannot parse: AclTemplate" << std::endl;
}
return false;
}
@@ -113,8 +109,6 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"userMustChangePassword",userMustChangePassword);
field_to_json(Obj,"errorCode", errorCode);
Obj.set("aclTemplate",AclTemplateObj);
field_to_json(Obj,"errorCode", errorCode);
field_to_json(Obj,"lastRefresh", lastRefresh_);
}
bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -131,10 +125,9 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "created", created_);
field_from_json(Obj, "username", username_);
field_from_json(Obj, "userMustChangePassword",userMustChangePassword);
field_from_json(Obj,"lastRefresh", lastRefresh_);
return true;
} catch (...) {
std::cout << "Cannot parse: WebToken" << std::endl;
}
return false;
}
@@ -145,14 +138,14 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"primary", primary);
}
bool MobilePhoneNumber::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"number",number);
field_from_json(Obj,"verified",verified);
field_from_json(Obj,"primary",primary);
return true;
} catch (...) {
std::cout << "Cannot parse: MobilePhoneNumber" << std::endl;
}
return false;
};
@@ -162,13 +155,13 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"method", method);
}
bool MfaAuthInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"enabled",enabled);
field_from_json(Obj,"method",method);
return true;
} catch (...) {
std::cout << "Cannot parse: MfaAuthInfo" << std::endl;
}
return false;
}
@@ -176,17 +169,15 @@ namespace OpenWifi::SecurityObjects {
void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "mobiles", mobiles);
field_to_json(Obj, "mfa", mfa);
field_to_json(Obj, "authenticatorSecret", authenticatorSecret);
}
bool UserLoginLoginExtensions::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"mobiles",mobiles);
field_from_json(Obj,"mfa",mfa);
field_from_json(Obj, "authenticatorSecret", authenticatorSecret);
return true;
} catch (...) {
std::cout << "Cannot parse: UserLoginLoginExtensions" << std::endl;
}
return false;
}
@@ -198,7 +189,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "method", method);
}
bool MFAChallengeRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"question",question);
@@ -206,7 +197,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"method",method);
return true;
} catch (...) {
std::cout << "Cannot parse: MFAChallengeRequest" << std::endl;
}
return false;
};
@@ -214,22 +205,23 @@ namespace OpenWifi::SecurityObjects {
void MFAChallengeResponse::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "uuid", uuid);
field_to_json(Obj, "answer", answer);
}
bool MFAChallengeResponse::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"answer",answer);
return true;
} catch (...) {
std::cout << "Cannot parse: MFAChallengeResponse" << std::endl;
}
return false;
}
void UserInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"Id",Id);
field_to_json(Obj,"name",name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"avatar", avatar);
@@ -259,13 +251,11 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"lastPasswords",lastPasswords);
field_to_json(Obj,"oauthType",oauthType);
field_to_json(Obj,"oauthUserInfo",oauthUserInfo);
field_to_json(Obj,"modified",modified);
field_to_json(Obj,"signingUp",signingUp);
};
bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"Id",Id);
field_from_json(Obj,"name",name);
field_from_json(Obj,"description",description);
field_from_json(Obj,"avatar",avatar);
@@ -275,8 +265,6 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"currentLoginURI",currentLoginURI);
field_from_json(Obj,"locale",locale);
field_from_json(Obj,"notes",notes);
field_from_json(Obj,"location", location);
field_from_json(Obj,"owner", owner);
field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString);
field_from_json(Obj,"securityPolicy",securityPolicy);
field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo);
@@ -295,29 +283,13 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"lastPasswords",lastPasswords);
field_from_json(Obj,"oauthType",oauthType);
field_from_json(Obj,"oauthUserInfo",oauthUserInfo);
field_from_json(Obj,"modified",modified);
field_from_json(Obj,"signingUp",signingUp);
return true;
} catch (const Poco::Exception &E) {
std::cout << "Cannot parse: UserInfo" << std::endl;
}
return false;
};
void UserInfoList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"users",users);
}
bool UserInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"users",users);
return true;
} catch (...) {
std::cout << "Cannot parse: InternalServiceInfo" << std::endl;
}
return false;
}
void InternalServiceInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"privateURI",privateURI);
field_to_json(Obj,"publicURI",publicURI);
@@ -331,7 +303,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"token",token);
return true;
} catch (...) {
std::cout << "Cannot parse: InternalServiceInfo" << std::endl;
}
return false;
};
@@ -349,7 +321,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "services", services);
return true;
} catch(...) {
std::cout << "Cannot parse: InternalSystemServices" << std::endl;
}
return false;
};
@@ -371,7 +343,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "authenticationType", authenticationType);
return true;
} catch (...) {
std::cout << "Cannot parse: SystemEndpoint" << std::endl;
}
return false;
};
@@ -385,7 +357,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "endpoints", endpoints);
return true;
} catch (...) {
std::cout << "Cannot parse: SystemEndpointList" << std::endl;
}
return false;
}
@@ -404,7 +376,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "userInfo", userinfo);
return true;
} catch(...) {
std::cout << "Cannot parse: UserInfoAndPolicy" << std::endl;
}
return false;
}
@@ -415,14 +387,13 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"note", note);
}
bool NoteInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"created",created);
field_from_json(Obj,"createdBy",createdBy);
field_from_json(Obj,"note",note);
return true;
} catch(...) {
std::cout << "Cannot parse: NoteInfo" << std::endl;
}
return false;
}
@@ -433,20 +404,20 @@ namespace OpenWifi::SecurityObjects {
SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
Notes.push_back(ii);
}
}
return true;
} catch(...) {
std::cout << "Cannot parse: MergeNotes" << std::endl;
}
return false;
}
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
for(auto const &i:NewNotes) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
ExistingNotes.push_back(ii);
}
return true;
@@ -457,13 +428,12 @@ namespace OpenWifi::SecurityObjects {
field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
}
bool ProfileAction::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"resource",resource);
field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
return true;
} catch(...) {
std::cout << "Cannot parse: ProfileAction" << std::endl;
}
return false;
}
@@ -477,7 +447,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"notes", notes);
}
bool SecurityProfile::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name);
@@ -485,9 +455,8 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"policy",policy);
field_from_json(Obj,"role",role);
field_from_json(Obj,"notes",notes);
return true;
} catch(...) {
std::cout << "Cannot parse: SecurityProfile" << std::endl;
}
return false;
}
@@ -496,128 +465,13 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "profiles", profiles);
}
bool SecurityProfileList::from_json(const Poco::JSON::Object::Ptr &Obj) {
bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) {
try {
field_from_json(Obj,"profiles",profiles);
return true;
} catch(...) {
std::cout << "Cannot parse: SecurityProfileList" << std::endl;
}
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);
field_to_json(Obj,"userAction",userAction);
}
bool ActionLink::from_json(const 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);
field_from_json(Obj,"userAction",userAction);
return true;
} catch(...) {
std::cout << "Cannot parse: ActionLink" << std::endl;
}
return false;
}
void Preferences::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"modified",modified);
field_to_json(Obj,"data",data);
}
bool Preferences::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"modified",modified);
field_from_json(Obj,"data",data);
return true;
} catch(...) {
std::cout << "Cannot parse: Preferences" << std::endl;
}
return false;
}
void SubMfaConfig::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"type",type);
field_to_json(Obj,"sms",sms);
field_to_json(Obj,"email",email);
}
bool SubMfaConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"type",type);
field_from_json(Obj,"sms",sms);
field_from_json(Obj,"email",email);
return true;
} catch(...) {
std::cout << "Cannot parse: SubMfaConfig" << std::endl;
}
return false;
}
void Token::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"token",token);
field_to_json(Obj,"refreshToken",refreshToken);
field_to_json(Obj,"tokenType",tokenType);
field_to_json(Obj,"userName",userName);
field_to_json(Obj,"created",created);
field_to_json(Obj,"expires",expires);
field_to_json(Obj,"idleTimeout",idleTimeout);
field_to_json(Obj,"revocationDate",revocationDate);
field_to_json(Obj,"lastRefresh", lastRefresh);
}
bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"token",token);
field_from_json(Obj,"refreshToken",refreshToken);
field_from_json(Obj,"tokenType",tokenType);
field_from_json(Obj,"userName",userName);
field_from_json(Obj,"created",created);
field_from_json(Obj,"expires",expires);
field_from_json(Obj,"idleTimeout",idleTimeout);
field_from_json(Obj,"revocationDate",revocationDate);
field_from_json(Obj,"lastRefresh", lastRefresh);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void LoginRecordInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"sessionId",sessionId);
field_to_json(Obj,"userId",userId);
field_to_json(Obj,"email",email);
field_to_json(Obj,"login",login);
field_to_json(Obj,"logout",logout);
}
}

View File

@@ -6,20 +6,13 @@
// Arilia Wireless Inc.
//
#pragma once
#ifndef UCENTRAL_RESTAPI_SECURITYOBJECTS_H
#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H
#include <string>
#include <type_traits>
#include "framework/OpenWifiTypes.h"
#include "Poco/JSON/Object.h"
#include "Poco/Data/LOB.h"
#include "Poco/Data/LOBStream.h"
#include "../framework/OpenWifiTypes.h"
namespace OpenWifi {
uint64_t Now();
namespace SecurityObjects {
typedef std::string USER_ID_TYPE;
namespace OpenWifi::SecurityObjects {
struct AclTemplate {
bool Read_ = true;
@@ -28,13 +21,8 @@ namespace OpenWifi {
bool Delete_ = true;
bool PortalLogin_ = true;
AclTemplate() noexcept = default;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
static_assert( std::is_nothrow_move_constructible_v<AclTemplate> );
bool from_json(const Poco::JSON::Object::Ptr &Obj); };
struct WebToken {
std::string access_token_;
@@ -48,63 +36,60 @@ namespace OpenWifi {
uint64_t idle_timeout_=0;
AclTemplate acl_template_;
uint64_t created_=0;
uint64_t lastRefresh_=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum USER_ROLE {
UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING, PARTNER
UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING
};
USER_ROLE UserTypeFromString(const std::string &U);
std::string UserTypeToString(USER_ROLE U);
struct NoteInfo {
uint64_t created=0; // = OpenWifi::Now();
uint64_t created = std::time(nullptr);
std::string createdBy;
std::string note;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
typedef std::vector<NoteInfo> NoteInfoVec;
struct MobilePhoneNumber {
std::string number;
bool verified = false;
bool primary = false;
bool verified;
bool primary;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct MfaAuthInfo {
bool enabled = false;
bool enabled;
std::string method;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct UserLoginLoginExtensions {
std::vector<MobilePhoneNumber> mobiles;
struct MfaAuthInfo mfa;
std::string authenticatorSecret;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct MFAChallengeRequest {
std::string uuid;
std::string question;
std::string method;
uint64_t created = OpenWifi::Now();
uint64_t created;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct MFAChallengeResponse {
@@ -112,11 +97,11 @@ namespace OpenWifi {
std::string answer;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
struct UserInfo {
std::string id;
std::string Id;
std::string name;
std::string description;
std::string avatar;
@@ -143,24 +128,15 @@ namespace OpenWifi {
std::string securityPolicy;
uint64_t securityPolicyChange = 0 ;
std::string currentPassword;
OpenWifi::Types::StringVec lastPasswords;
Types::StringVec lastPasswords;
std::string oauthType;
std::string oauthUserInfo;
uint64_t modified;
std::string signingUp;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<UserInfo> UserInfoVec;
struct UserInfoList {
std::vector<UserInfo> users;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
// bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes);
bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes);
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes);
@@ -224,7 +200,7 @@ namespace OpenWifi {
std::string resource;
ResourceAccessType access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
typedef std::vector<ProfileAction> ProfileActionVec;
@@ -236,93 +212,15 @@ namespace OpenWifi {
std::string role;
NoteInfoVec notes;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(Poco::JSON::Object::Ptr Obj);
};
typedef std::vector<SecurityProfile> SecurityProfileVec;
struct SecurityProfileList {
SecurityProfileVec profiles;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum LinkActions {
FORGOT_PASSWORD=1,
VERIFY_EMAIL,
SUB_FORGOT_PASSWORD,
SUB_VERIFY_EMAIL,
SUB_SIGNUP,
EMAIL_INVITATION
};
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=OpenWifi::Now();
uint64_t expires=0;
uint64_t completed=0;
uint64_t canceled=0;
bool userAction=true;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Preferences {
std::string id;
uint64_t modified;
Types::StringPairVec data;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubMfaConfig {
std::string id;
std::string type;
std::string sms;
std::string email;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Token {
std::string token;
std::string refreshToken;
std::string tokenType;
std::string userName;
uint64_t created=0;
uint64_t expires=0;
uint64_t idleTimeout=0;
uint64_t revocationDate=0;
uint64_t lastRefresh=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Avatar {
std::string id;
std::string type;
uint64_t created=0;
std::string name;
Poco::Data::BLOB avatar;
};
struct LoginRecordInfo {
std::string sessionId;
std::string userId;
std::string email;
uint64_t login=0;
uint64_t logout=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj);
};
}
}
#endif //UCENTRAL_RESTAPI_SECURITYOBJECTS_H

View File

@@ -1,603 +0,0 @@
//
// Created by stephane bourque on 2021-10-27.
//
#include "RESTAPI_SubObjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::SubObjects {
void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "enableLEDS", enableLEDS);
field_to_json(Obj, "type", type);
field_to_json(Obj, "subnet", subnet);
field_to_json(Obj, "subnetMask", subnetMask);
field_to_json(Obj, "startIP", startIP);
field_to_json(Obj, "endIP", endIP);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
field_to_json(Obj, "subnetV6", subnetV6);
field_to_json(Obj, "subnetMaskV6", subnetMaskV6);
field_to_json(Obj, "startIPV6", startIPV6);
field_to_json(Obj, "endIPV6", endIPV6);
}
bool HomeDeviceMode::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "enableLEDS", enableLEDS);
field_from_json(Obj, "type", type);
field_from_json(Obj, "subnet", subnet);
field_from_json(Obj, "subnetMask", subnetMask);
field_from_json(Obj, "startIP", startIP);
field_from_json(Obj, "endIP", endIP);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
field_from_json(Obj, "subnetV6", subnetV6);
field_from_json(Obj, "subnetMaskV6", subnetMaskV6);
field_from_json(Obj, "startIPV6", startIPV6);
field_from_json(Obj, "endIPV6", endIPV6);
return true;
} catch (...) {
}
return false;
}
void IPReservation::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "nickname", nickname);
field_to_json(Obj, "ipAddress", ipAddress);
field_to_json(Obj, "macAddress", macAddress);
}
bool IPReservation::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "nickname", nickname);
field_from_json(Obj, "ipAddress", ipAddress);
field_from_json(Obj, "macAddress", macAddress);
return true;
} catch (...) {
}
return false;
}
void IPReservationList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "reservations", reservations);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool IPReservationList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "reservations", reservations);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void DnsConfiguration::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "ISP", ISP);
field_to_json(Obj, "custom", custom);
field_to_json(Obj, "primary", primary);
field_to_json(Obj, "secondary", secondary);
field_to_json(Obj, "primaryV6", primaryV6);
field_to_json(Obj, "secondaryV6", secondaryV6);
}
bool DnsConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "ISP", ISP);
field_from_json(Obj, "custom", custom);
field_from_json(Obj, "primary", primary);
field_from_json(Obj, "secondary", secondary);
field_from_json(Obj, "primaryV6", primaryV6);
field_from_json(Obj, "secondaryV6", secondaryV6);
return true;
} catch (...) {
}
return false;
}
void InternetConnection::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "type", type);
field_to_json(Obj, "username", username);
field_to_json(Obj, "password", password);
field_to_json(Obj, "ipAddress", ipAddress);
field_to_json(Obj, "subnetMask", subnetMask);
field_to_json(Obj, "defaultGateway", defaultGateway);
field_to_json(Obj, "sendHostname", sendHostname);
field_to_json(Obj, "primaryDns", primaryDns);
field_to_json(Obj, "secondaryDns", secondaryDns);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
field_to_json(Obj, "ipV6Support", ipV6Support);
field_to_json(Obj, "ipAddressV6", ipAddressV6);
field_to_json(Obj, "subnetMaskV6", subnetMaskV6);
field_to_json(Obj, "defaultGatewayV6", defaultGatewayV6);
field_to_json(Obj, "primaryDnsV6", primaryDnsV6);
field_to_json(Obj, "secondaryDnsV6", secondaryDnsV6);
}
bool InternetConnection::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "type", type);
field_from_json(Obj, "username", username);
field_from_json(Obj, "password", password);
field_from_json(Obj, "ipAddress", ipAddress);
field_from_json(Obj, "subnetMask", subnetMask);
field_from_json(Obj, "defaultGateway", defaultGateway);
field_from_json(Obj, "sendHostname", sendHostname);
field_from_json(Obj, "primaryDns", primaryDns);
field_from_json(Obj, "secondaryDns", secondaryDns);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
field_from_json(Obj, "ipV6Support", ipV6Support);
field_from_json(Obj, "ipAddressV6", ipAddressV6);
field_from_json(Obj, "subnetMaskV6", subnetMaskV6);
field_from_json(Obj, "defaultGatewayV6", defaultGatewayV6);
field_from_json(Obj, "primaryDnsV6", primaryDnsV6);
field_from_json(Obj, "secondaryDnsV6", secondaryDnsV6);
return true;
} catch (...) {
}
return false;
}
void WifiNetwork::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "type", type);
field_to_json(Obj, "name", name);
field_to_json(Obj, "password", password);
field_to_json(Obj, "encryption", encryption);
field_to_json(Obj, "bands", bands);
}
bool WifiNetwork::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "type", type);
field_from_json(Obj, "name", name);
field_from_json(Obj, "password", password);
field_from_json(Obj, "encryption", encryption);
field_from_json(Obj, "bands", bands);
return true;
} catch (...) {
}
return false;
}
void WifiNetworkList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "wifiNetworks", wifiNetworks);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool WifiNetworkList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "wifiNetworks", wifiNetworks);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void AccessTime::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "day", day);
field_to_json(Obj, "rangeList", rangeList);
}
bool AccessTime::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "day", day);
field_from_json(Obj, "rangeList", rangeList);
return true;
} catch (...) {
}
return false;
}
void AccessTimes::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "schedule", schedule);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool AccessTimes::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "schedule", schedule);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "name", name);
field_to_json(Obj, "description", description);
field_to_json(Obj, "macAddress", macAddress);
field_to_json(Obj, "manufacturer", manufacturer);
field_to_json(Obj, "firstContact", firstContact);
field_to_json(Obj, "lastContact", lastContact);
field_to_json(Obj, "group", group);
field_to_json(Obj, "icon", icon);
field_to_json(Obj, "suspended", suspended);
field_to_json(Obj, "ip", ip);
field_to_json(Obj, "schedule", schedule);
}
bool SubscriberDevice::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", name);
field_from_json(Obj, "description", description);
field_from_json(Obj, "macAddress", macAddress);
field_from_json(Obj, "manufacturer", manufacturer);
field_from_json(Obj, "firstContact", firstContact);
field_from_json(Obj, "lastContact", lastContact);
field_from_json(Obj, "group", group);
field_from_json(Obj, "icon", icon);
field_from_json(Obj, "suspended", suspended);
field_from_json(Obj, "ip", ip);
field_from_json(Obj, "schedule", schedule);
return true;
} catch (...) {
}
return false;
}
void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "devices", devices);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "devices", devices);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void Association::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "name", name);
field_to_json(Obj, "ssid", ssid);
field_to_json(Obj, "macAddress", macAddress);
field_to_json(Obj, "rssi", rssi);
field_to_json(Obj, "power", power);
field_to_json(Obj, "ipv4", ipv4);
field_to_json(Obj, "ipv6", ipv6);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
field_to_json(Obj, "manufacturer", manufacturer);
}
bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", name);
field_from_json(Obj, "ssid", ssid);
field_from_json(Obj, "macAddress", macAddress);
field_from_json(Obj, "rssi", rssi);
field_from_json(Obj, "power", power);
field_from_json(Obj, "ipv4", ipv4);
field_from_json(Obj, "ipv6", ipv6);
field_from_json(Obj, "tx", tx);
field_from_json(Obj, "rx", rx);
field_from_json(Obj, "manufacturer", manufacturer);
return true;
} catch (...) {
}
return false;
}
void AssociationList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "associations", associations);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool AssociationList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "associations", associations);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void Client::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "macAddress", macAddress);
field_to_json(Obj, "speed", speed);
field_to_json(Obj, "mode", mode);
field_to_json(Obj, "ipv4", ipv4);
field_to_json(Obj, "ipv6", ipv6);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
field_to_json(Obj, "manufacturer", manufacturer);
}
bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "macAddress", macAddress);
field_from_json(Obj, "speed", speed);
field_from_json(Obj, "mode", mode);
field_from_json(Obj, "ipv4", ipv4);
field_from_json(Obj, "ipv6", ipv6);
field_from_json(Obj, "tx", tx);
field_from_json(Obj, "rx", rx);
field_from_json(Obj, "manufacturer", manufacturer);
return true;
} catch (...) {
}
return false;
}
void ClientList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "clients", clients);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool ClientList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "clients", clients);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void Location::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "buildingName", buildingName);
field_to_json(Obj, "addressLines", addressLines);
field_to_json(Obj, "city", city);
field_to_json(Obj, "state", state);
field_to_json(Obj, "postal", postal);
field_to_json(Obj, "country", country);
field_to_json(Obj, "phones", phones);
field_to_json(Obj, "mobiles", mobiles);
}
bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "buildingName", buildingName);
field_from_json(Obj, "addressLines", addressLines);
field_from_json(Obj, "city", city);
field_from_json(Obj, "state", state);
field_from_json(Obj, "postal", postal);
field_from_json(Obj, "country", country);
field_from_json(Obj, "phones", phones);
field_from_json(Obj, "mobiles", mobiles);
return true;
} catch (...) {
}
return false;
}
void RadioHE::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "multipleBSSID", multipleBSSID);
field_to_json(Obj, "ema", ema);
field_to_json(Obj, "bssColor", bssColor);
}
bool RadioHE::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "multipleBSSID", multipleBSSID);
field_from_json(Obj, "ema", ema);
field_from_json(Obj, "bssColor", bssColor);
return true;
} catch (...) {
}
return false;
}
void RadioRates::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "beacon", beacon);
field_to_json(Obj, "multicast", multicast);
}
bool RadioRates::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "beacon", beacon);
field_from_json(Obj, "multicast", multicast);
return true;
} catch (...) {
}
return false;
}
void RadioInformation::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "band", band);
field_to_json(Obj, "bandwidth", bandwidth);
field_to_json(Obj, "channel", channel);
field_to_json(Obj, "country", country);
field_to_json(Obj, "channelMode", channelMode);
field_to_json(Obj, "channelWidth", channelWidth);
field_to_json(Obj, "requireMode", requireMode);
field_to_json(Obj, "txpower", txpower);
field_to_json(Obj, "legacyRates", legacyRates);
field_to_json(Obj, "beaconInterval", beaconInterval);
field_to_json(Obj, "dtimPeriod", dtimPeriod);
field_to_json(Obj, "maximumClients", maximumClients);
field_to_json(Obj, "rates", rates);
field_to_json(Obj, "he", he);
field_to_json(Obj, "rawInfo", rawInfo);
field_to_json(Obj, "allowDFS", allowDFS);
field_to_json(Obj, "mimo", mimo);
}
bool RadioInformation::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "band", band);
field_from_json(Obj, "bandwidth", bandwidth);
field_from_json(Obj, "channel", channel);
field_from_json(Obj, "country", country);
field_from_json(Obj, "channelMode", channelMode);
field_from_json(Obj, "channelWidth", channelWidth);
field_from_json(Obj, "requireMode", requireMode);
field_from_json(Obj, "txpower", txpower);
field_from_json(Obj, "legacyRates", legacyRates);
field_from_json(Obj, "beaconInterval", beaconInterval);
field_from_json(Obj, "dtimPeriod", dtimPeriod);
field_from_json(Obj, "maximumClients", maximumClients);
field_from_json(Obj, "rates", rates);
field_from_json(Obj, "he", he);
field_from_json(Obj, "rawInfo", rawInfo);
field_from_json(Obj, "allowDFS", allowDFS);
field_from_json(Obj, "mimo", mimo);
return true;
} catch (...) {
}
return false;
}
void AccessPoint::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "macAddress", macAddress);
field_to_json(Obj, "serialNumber", serialNumber);
field_to_json(Obj, "name", name);
field_to_json(Obj, "deviceType", deviceType);
field_to_json(Obj, "subscriberDevices", subscriberDevices);
field_to_json(Obj, "ipReservations", ipReservations);
field_to_json(Obj, "address", address);
field_to_json(Obj, "wifiNetworks", wifiNetworks);
field_to_json(Obj, "internetConnection", internetConnection);
field_to_json(Obj, "deviceMode", deviceMode);
field_to_json(Obj, "dnsConfiguration", dnsConfiguration);
field_to_json(Obj, "radios", radios);
field_to_json(Obj, "automaticUpgrade", automaticUpgrade);
field_to_json(Obj, "configurationUUID", configurationUUID);
field_to_json(Obj, "currentFirmware", currentFirmware);
field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate);
field_to_json(Obj, "latestFirmware", latestFirmware);
field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate);
field_to_json(Obj, "newFirmwareAvailable", newFirmwareAvailable);
field_to_json(Obj, "latestFirmwareURI", latestFirmwareURI);
}
bool AccessPoint::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "macAddress", macAddress);
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "name", name);
field_from_json(Obj, "deviceType", deviceType);
field_from_json(Obj, "subscriberDevices", subscriberDevices);
field_from_json(Obj, "ipReservations", ipReservations);
field_from_json(Obj, "address", address);
field_from_json(Obj, "wifiNetworks", wifiNetworks);
field_from_json(Obj, "internetConnection", internetConnection);
field_from_json(Obj, "deviceMode", deviceMode);
field_from_json(Obj, "dnsConfiguration", dnsConfiguration);
field_from_json(Obj, "radios", radios);
field_from_json(Obj, "automaticUpgrade", automaticUpgrade);
field_from_json(Obj, "configurationUUID", configurationUUID);
field_from_json(Obj, "currentFirmware", currentFirmware);
field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate);
field_from_json(Obj, "latestFirmware", latestFirmware);
field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate);
field_from_json(Obj, "newFirmwareAvailable", newFirmwareAvailable);
field_from_json(Obj, "latestFirmwareURI", latestFirmwareURI);
return true;
} catch (...) {
}
return false;
}
void AccessPointList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "list", list);
}
bool AccessPointList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "list", list);
return true;
} catch (...) {
}
return false;
}
void SubscriberInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "userId", userId);
field_to_json(Obj, "firstName", firstName);
field_to_json(Obj, "initials", initials);
field_to_json(Obj, "lastName", lastName);
field_to_json(Obj, "phoneNumber", phoneNumber);
field_to_json(Obj, "secondaryEmail", secondaryEmail);
field_to_json(Obj, "accessPoints", accessPoints);
field_to_json(Obj, "serviceAddress", serviceAddress);
field_to_json(Obj, "billingAddress", billingAddress);
field_to_json(Obj, "created", created);
field_to_json(Obj, "modified", modified);
}
bool SubscriberInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "userId", userId);
field_from_json(Obj, "firstName", firstName);
field_from_json(Obj, "initials", initials);
field_from_json(Obj, "lastName", lastName);
field_from_json(Obj, "phoneNumber", phoneNumber);
field_from_json(Obj, "secondaryEmail", secondaryEmail);
field_from_json(Obj, "accessPoints", accessPoints);
field_from_json(Obj, "serviceAddress", serviceAddress);
field_from_json(Obj, "billingAddress", billingAddress);
field_from_json(Obj, "created", created);
field_from_json(Obj, "modified", modified);
return true;
} catch (...) {
}
return false;
}
void StatsEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "timestamp", timestamp);
field_to_json(Obj, "tx", tx);
field_to_json(Obj, "rx", rx);
}
bool StatsEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "timestamp", timestamp);
field_from_json(Obj, "tx", tx);
field_from_json(Obj, "rx", rx);
return true;
} catch (...) {
}
return false;
}
void StatsBlock::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "modified", modified);
field_to_json(Obj, "external", external);
field_to_json(Obj, "internal", internal);
}
bool StatsBlock::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "modified", modified);
field_from_json(Obj, "external", external);
field_from_json(Obj, "internal", internal);
return true;
} catch (...) {
}
return false;
}
}

View File

@@ -1,322 +0,0 @@
//
// Created by stephane bourque on 2021-10-27.
//
#ifndef OWSUB_RESTAPI_SUBOBJECTS_H
#define OWSUB_RESTAPI_SUBOBJECTS_H
#include <string>
#include "Poco/JSON/Object.h"
namespace OpenWifi::SubObjects {
struct HomeDeviceMode {
bool enableLEDS = true;
std::string type; // bridge, manual, automatic
std::string subnet;
std::string subnetMask;
std::string startIP;
std::string endIP;
uint64_t created = 0 ;
uint64_t modified = 0 ;
std::string subnetV6;
int subnetMaskV6=0;
std::string startIPV6;
std::string endIPV6;
std::string leaseTime;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct IPReservation {
std::string nickname;
std::string ipAddress;
std::string macAddress;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct IPReservationList {
std::string id;
std::vector<IPReservation> reservations;
uint64_t created = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DnsConfiguration {
bool ISP=false;
bool custom=false;
std::string primary;
std::string secondary;
std::string primaryV6;
std::string secondaryV6;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct InternetConnection {
std::string type; // automatic, pppoe, manual
std::string username;
std::string password;
std::string ipAddress;
std::string subnetMask;
std::string defaultGateway;
bool sendHostname = true;
std::string primaryDns;
std::string secondaryDns;
uint64_t created=0;
uint64_t modified=0;
bool ipV6Support=false;
std::string ipAddressV6;
int subnetMaskV6=0;
std::string defaultGatewayV6;
std::string primaryDnsV6;
std::string secondaryDnsV6;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct WifiNetwork {
std::string type; // main, guest
std::string name;
std::string password;
std::string encryption;
std::vector<std::string> bands;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct WifiNetworkList {
std::vector<WifiNetwork> wifiNetworks;
uint64_t created=0;
uint64_t modified=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AccessTime {
std::string day;
std::vector<std::string> rangeList;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AccessTimes {
std::vector<AccessTime> schedule;
uint64_t created=0;
uint64_t modified=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubscriberDevice {
std::string name;
std::string description;
std::string macAddress;
std::string manufacturer;
uint64_t firstContact=0;
uint64_t lastContact=0;
std::string group;
std::string icon;
bool suspended=false;
std::string ip;
std::vector<AccessTimes> schedule;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubscriberDeviceList {
std::vector<SubscriberDevice> devices;
uint64_t created=0;
uint64_t modified=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Association {
std::string name;
std::string ssid;
std::string macAddress;
int rssi=0;
int power=0;
std::string ipv4;
std::string ipv6;
uint64_t tx=0;
uint64_t rx=0;
std::string manufacturer;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AssociationList {
std::vector<Association> associations;
uint64_t created=0;
uint64_t modified=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Client {
std::string macAddress;
std::string speed;
std::string mode;
std::string ipv4;
std::string ipv6;
uint64_t tx=0;
uint64_t rx=0;
std::string manufacturer;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ClientList {
std::vector<Client> clients;
uint64_t created=0;
uint64_t modified=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Location {
std::string buildingName;
std::vector<std::string> addressLines;
std::string city;
std::string state;
std::string postal;
std::string country;
std::vector<std::string> phones;
std::vector<std::string> mobiles;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadioHE {
bool multipleBSSID = false;
bool ema = false;
uint64_t bssColor = 64;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadioRates {
uint64_t beacon = 6000;
uint64_t multicast = 24000;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RadioInformation {
std::string band;
uint64_t bandwidth;
uint64_t channel = 0 ;
std::string country;
std::string channelMode{"HE"};
uint64_t channelWidth = 80;
std::string requireMode;
uint64_t txpower=0;
bool legacyRates = false;
uint64_t beaconInterval = 100;
uint64_t dtimPeriod = 2;
uint64_t maximumClients = 64;
RadioRates rates;
RadioHE he;
bool allowDFS=false;
std::string mimo;
std::vector<std::string> rawInfo;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AccessPoint {
std::string id;
std::string macAddress;
std::string serialNumber;
std::string name;
std::string deviceType;
SubscriberDeviceList subscriberDevices;
IPReservationList ipReservations;
Location address;
WifiNetworkList wifiNetworks;
InternetConnection internetConnection;
HomeDeviceMode deviceMode;
DnsConfiguration dnsConfiguration;
std::vector<RadioInformation> radios;
bool automaticUpgrade = true;
std::string configurationUUID;
std::string currentFirmware;
uint64_t currentFirmwareDate;
std::string latestFirmware;
uint64_t latestFirmwareDate;
bool newFirmwareAvailable;
std::string latestFirmwareURI;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct AccessPointList {
std::vector<AccessPoint> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SubscriberInfo {
std::string id;
std::string userId;
std::string firstName;
std::string initials;
std::string lastName;
std::string phoneNumber;
std::string secondaryEmail;
AccessPointList accessPoints;
Location serviceAddress;
Location billingAddress;
uint64_t created = 0;
uint64_t modified = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct StatsEntry {
uint64_t timestamp=0;
uint64_t tx=0;
uint64_t rx=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct StatsBlock {
uint64_t modified=0;
std::vector<StatsEntry> external, internal;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
#endif //OWSUB_RESTAPI_SUBOBJECTS_H

View File

@@ -2,29 +2,28 @@
// Created by stephane bourque on 2021-10-09.
//
#include <aws/sns/SNSClient.h>
#include <aws/sns/model/PublishRequest.h>
#include <aws/sns/model/PublishResult.h>
#include "framework/MicroService.h"
#include <aws/sns/model/GetSMSAttributesRequest.h>
#include "MFAServer.h"
#include "SMS_provider_aws.h"
#include "SMS_provider_twilio.h"
#include "SMSSender.h"
#include "framework/MicroService.h"
namespace OpenWifi {
class SMSSender * SMSSender::instance_ = nullptr;
int SMSSender::Start() {
Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false);
if(Enabled_) {
Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws");
Provider_ = MicroService::instance().ConfigGetString("sms.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") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger());
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
}
Enabled_ = ProviderImpl_->Initialize();
}
return 0;
}
@@ -32,7 +31,7 @@ namespace OpenWifi {
}
void SMSSender::CleanCache() {
uint64_t Now=OpenWifi::Now();
uint64_t Now=std::time(nullptr);
for(auto i=begin(Cache_);i!=end(Cache_);) {
if((Now-i->Created)>300)
i = Cache_.erase(i);
@@ -43,10 +42,8 @@ namespace OpenWifi {
bool SMSSender::StartValidation(const std::string &Number, const std::string &UserName) {
std::lock_guard G(Mutex_);
if(!Enabled_)
return false;
CleanCache();
uint64_t Now=OpenWifi::Now();
uint64_t Now=std::time(nullptr);
auto Challenge = MFAServer::MakeChallenge();
Cache_.emplace_back(SMSValidationCacheEntry{.Number=Number, .Code=Challenge, .UserName=UserName, .Created=Now});
std::string Message = "Please enter the following code on your login screen: " + Challenge;
@@ -56,9 +53,6 @@ namespace OpenWifi {
bool SMSSender::IsNumberValid(const std::string &Number, const std::string &UserName) {
std::lock_guard G(Mutex_);
if(!Enabled_)
return false;
for(const auto &i:Cache_) {
if(i.Number==Number && i.UserName==UserName)
return i.Validated;
@@ -69,9 +63,6 @@ namespace OpenWifi {
bool SMSSender::CompleteValidation(const std::string &Number, const std::string &Code, const std::string &UserName) {
std::lock_guard G(Mutex_);
if(!Enabled_)
return false;
for(auto &i:Cache_) {
if(i.Code==Code && i.Number==Number && i.UserName==UserName) {
i.Validated=true;
@@ -83,7 +74,7 @@ namespace OpenWifi {
bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) {
if(!Enabled_) {
poco_information(Logger(),"SMS has not been enabled. Messages cannot be sent.");
Logger_.information("SMS has not been enabled. Messages cannot be sent.");
return false;
}
return ProviderImpl_->Send(PhoneNumber,Message);

View File

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

View File

@@ -17,7 +17,7 @@ namespace OpenWifi {
Region_ = MicroService::instance().ConfigGetString("smssender.aws.region","");
if(SecretKey_.empty() || AccessKey_.empty() || Region_.empty()) {
poco_debug(Logger(),"SMSSender is disabled. Please provide key, secret, and region.");
Logger_.debug("SMSSender is disabled. Please provide key, secret, and region.");
return false;
}
Running_=true;
@@ -43,7 +43,6 @@ namespace OpenWifi {
if(!Running_)
return false;
try {
Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
Aws::SNS::Model::PublishRequest psms_req;
psms_req.SetMessage(Message.c_str());
@@ -51,16 +50,11 @@ namespace OpenWifi {
auto psms_out = sns.Publish(psms_req);
if (psms_out.IsSuccess()) {
poco_debug(Logger(),fmt::format("SMS sent to {}",PhoneNumber));
Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber));
return true;
}
std::string ErrMsg{psms_out.GetError().GetMessage()};
poco_debug(Logger(),fmt::format("SMS NOT sent to {}: {}",PhoneNumber, ErrMsg));
return false;
} catch (...) {
}
poco_debug(Logger(),fmt::format("SMS NOT sent to {}: failure in SMS service",PhoneNumber));
Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
return false;
}

View File

@@ -21,7 +21,6 @@ namespace OpenWifi {
bool Stop() final ;
bool Send(const std::string &Number, const std::string &Message) final;
bool Running() final;
inline Poco::Logger & Logger() { return Logger_; }
private:
bool Running_=false;
Poco::Logger &Logger_;

View File

@@ -4,13 +4,12 @@
#include "SMS_provider_twilio.h"
#include "framework/MicroService.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/URI.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/HTTPResponse.h"
#include "framework/MicroService.h"
namespace OpenWifi {
bool SMS_provider_twilio::Initialize() {
@@ -19,7 +18,7 @@ namespace OpenWifi {
PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber","");
if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) {
poco_debug(Logger(),"SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
Logger_.debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
return false;
}
Running_=true;
@@ -55,7 +54,7 @@ namespace OpenWifi {
form.add("To",PhoneNumber);
form.add("From",PhoneNumber_);
form.add("Body", Message);
form.add("Body","This is from twillio");
form.prepareSubmit(req);
std::ostream& ostr = session.sendRequest(req);
@@ -65,12 +64,12 @@ namespace OpenWifi {
std::istream& rs = session.receiveResponse(res);
if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
poco_information(Logger(),fmt::format("Message sent to {}", PhoneNumber));
Logger_.information(Poco::format("Message sent to %s", PhoneNumber));
return true;
} else {
std::ostringstream os;
Poco::StreamCopier::copyStream(rs,os);
poco_information(Logger(),fmt::format("Message was not to {}: Error:{}", PhoneNumber, os.str()));
Logger_.information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str()));
return false;
}
}

Some files were not shown because too many files have changed in this diff Show More