Compare commits
198 Commits
WIFI-10942
...
WIFI-13597
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46b9524903 | ||
|
|
8d04cbc059 | ||
|
|
073856d385 | ||
|
|
c782981ca7 | ||
|
|
ca3691e665 | ||
|
|
be2ffc86ec | ||
|
|
75ebc0771c | ||
|
|
d050635a99 | ||
|
|
e3592b5fe6 | ||
|
|
9eec54effb | ||
|
|
6a7ae342dc | ||
|
|
5b3205823e | ||
|
|
db45a01bce | ||
|
|
d2f70ec82d | ||
|
|
2b01453970 | ||
|
|
68ccc4da93 | ||
|
|
1b4a58c95c | ||
|
|
bd20abacdf | ||
|
|
f0ca087d48 | ||
|
|
21bf1ff148 | ||
|
|
66c010dd28 | ||
|
|
0fb18e8a32 | ||
|
|
da21df49ce | ||
|
|
54d6565411 | ||
|
|
5052a818ff | ||
|
|
5e1f3e0e31 | ||
|
|
c0740a9760 | ||
|
|
88ebeead8c | ||
|
|
41c155c332 | ||
|
|
aaf6c933b5 | ||
|
|
5e58f7ef37 | ||
|
|
9fdd0019c1 | ||
|
|
f94e4b3aed | ||
|
|
b2b183f95c | ||
|
|
2cfa5040dc | ||
|
|
3112e2ad36 | ||
|
|
0e45f3700b | ||
|
|
78d9e508fc | ||
|
|
81ff75f1cc | ||
|
|
ab276bb474 | ||
|
|
2a8f09cb46 | ||
|
|
239dcffc98 | ||
|
|
5fb32934fa | ||
|
|
38010d4628 | ||
|
|
669f7f3433 | ||
|
|
3576d5516f | ||
|
|
0781f15bae | ||
|
|
e87f4d6476 | ||
|
|
dd7d5e8ab6 | ||
|
|
776ecabf81 | ||
|
|
5c6814852e | ||
|
|
90c700702e | ||
|
|
7c3ae1b5b9 | ||
|
|
15c2f6a4fc | ||
|
|
9d5855bc6e | ||
|
|
b7d72474da | ||
|
|
33650f5cea | ||
|
|
e8955454f7 | ||
|
|
6e0cf66008 | ||
|
|
6d305636a0 | ||
|
|
958b3337a8 | ||
|
|
3c7fa2ce9e | ||
|
|
b6a941197a | ||
|
|
338ac586de | ||
|
|
69262ee213 | ||
|
|
a592534621 | ||
|
|
c7e41c6671 | ||
|
|
17cecb3a3a | ||
|
|
64432c2fcd | ||
|
|
b8e98abfbd | ||
|
|
da507cb55c | ||
|
|
bdf8f642f9 | ||
|
|
d6a7ff14e4 | ||
|
|
3f3c48b17d | ||
|
|
878de17cd6 | ||
|
|
c1babcff00 | ||
|
|
41ec3b3495 | ||
|
|
daa264c984 | ||
|
|
17f95a64ad | ||
|
|
8fff2ced69 | ||
|
|
4bbc4154eb | ||
|
|
ffb7dd890e | ||
|
|
ce1818c93c | ||
|
|
acdb617d35 | ||
|
|
b0f1ecbbe4 | ||
|
|
040c782f3b | ||
|
|
2f39ead739 | ||
|
|
6312c7b1d8 | ||
|
|
0417162858 | ||
|
|
75b2b30b67 | ||
|
|
abc06d7953 | ||
|
|
7993e7d345 | ||
|
|
be4549fabb | ||
|
|
92c141e511 | ||
|
|
296713e853 | ||
|
|
d6dee68880 | ||
|
|
aaffa145ad | ||
|
|
c8e894bf79 | ||
|
|
766a608e1b | ||
|
|
333316d7a9 | ||
|
|
6527b45f2f | ||
|
|
76ef41aefe | ||
|
|
7e988c5780 | ||
|
|
2080027d7c | ||
|
|
b8a14e95d8 | ||
|
|
8966888e6b | ||
|
|
0ad79b8076 | ||
|
|
f650a6fde4 | ||
|
|
a6b7057c9b | ||
|
|
6a1fa01235 | ||
|
|
f554e73b91 | ||
|
|
2316dca6ce | ||
|
|
2395423832 | ||
|
|
43363e6854 | ||
|
|
2ab3d6a53d | ||
|
|
561fc84958 | ||
|
|
afbe50b65d | ||
|
|
15b5551cd8 | ||
|
|
717ab7451f | ||
|
|
8afba9650b | ||
|
|
155d6ba319 | ||
|
|
66f4742ca5 | ||
|
|
ad1bc551db | ||
|
|
9926b551f5 | ||
|
|
1dfd7969ea | ||
|
|
a62e34fdf8 | ||
|
|
45deeaea88 | ||
|
|
c5aadffe1d | ||
|
|
d10883b60d | ||
|
|
d38db8e05b | ||
|
|
8ea43f455c | ||
|
|
f653083548 | ||
|
|
66c50b27bf | ||
|
|
351dd650fa | ||
|
|
8550675c04 | ||
|
|
76864c21d7 | ||
|
|
696ee32ef3 | ||
|
|
780d6654fb | ||
|
|
b195763518 | ||
|
|
6543f44eab | ||
|
|
9b5aa5dd5d | ||
|
|
3062424816 | ||
|
|
41bd759d03 | ||
|
|
a27cd109e8 | ||
|
|
ec03bc6710 | ||
|
|
f00de63289 | ||
|
|
becd374124 | ||
|
|
89256bb900 | ||
|
|
a1634770bc | ||
|
|
6db6e51ef3 | ||
|
|
1ada42bdcb | ||
|
|
6bbcca57ae | ||
|
|
447ab2a705 | ||
|
|
ae251f9d35 | ||
|
|
729b1e6708 | ||
|
|
514bb3e622 | ||
|
|
087265b8b7 | ||
|
|
ccd5498f19 | ||
|
|
1688f5a39d | ||
|
|
1b185515ce | ||
|
|
3c45f07cee | ||
|
|
a493c9190e | ||
|
|
fda8afd90c | ||
|
|
a18cb37671 | ||
|
|
2c85a691bb | ||
|
|
e8800782b4 | ||
|
|
d0e818805a | ||
|
|
02ad85ca73 | ||
|
|
0ca578e9ec | ||
|
|
d351522441 | ||
|
|
401419e060 | ||
|
|
a8b0b46b1a | ||
|
|
d4fe199b0d | ||
|
|
52bbf884f9 | ||
|
|
e398d3cf4b | ||
|
|
f53cc82df1 | ||
|
|
3f9edc80e0 | ||
|
|
6ae42fe206 | ||
|
|
4539bfb53b | ||
|
|
dc57a94416 | ||
|
|
6025b7a74e | ||
|
|
3fcf6114c0 | ||
|
|
de0c1423af | ||
|
|
f4984247d2 | ||
|
|
e0b80a2640 | ||
|
|
f2c36882be | ||
|
|
3a1e4d66b4 | ||
|
|
6ea62c12c5 | ||
|
|
517b46d275 | ||
|
|
2503cb842e | ||
|
|
2878e2aa25 | ||
|
|
3b7e6da952 | ||
|
|
06267690fc | ||
|
|
db751e31a3 | ||
|
|
49b8664dc0 | ||
|
|
26e54f8433 | ||
|
|
a4ebfdc2e9 | ||
|
|
4b1fbf055f |
178
.clang-format
Normal file
@@ -0,0 +1,178 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Always
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
||||
10
.github/workflows/ci.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
DOCKER_REGISTRY_USERNAME: ucentral
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
@@ -58,11 +58,11 @@ jobs:
|
||||
- name: Get base branch name and set as output
|
||||
id: get_base_branch
|
||||
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')
|
||||
echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
|
||||
echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
- docker
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
|
||||
2
.github/workflows/enforce-jira-issue-key.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
|
||||
38
.github/workflows/openapi-pages.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Update OpenAPI docs on GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'openapi/**'
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
docsgen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Generate static HTML page with docs from OpenAPI definition
|
||||
run: |
|
||||
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openpapi/owsec.yaml -g html2 --skip-validate-spec -o /local/
|
||||
|
||||
- name: Update OpenAPI docs
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
||||
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
|
||||
git config --global credential.helper store
|
||||
git config --global user.email "tip-automation@telecominfraproject.com"
|
||||
git config --global user.name "TIP Automation User"
|
||||
git pull
|
||||
git checkout gh-pages || git checkout -b gh-pages
|
||||
mv index.html docs/index.html
|
||||
git add docs
|
||||
git commit -m'Update OpenAPI docs for GitHub pages'
|
||||
git push --set-upstream origin gh-pages
|
||||
2
.github/workflows/release.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
HELM_REPO_USERNAME: ucentral
|
||||
steps:
|
||||
- name: Checkout uCentral assembly chart repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: wlan-cloud-ucentralsec
|
||||
|
||||
|
||||
21
.idea/.gitignore
generated
vendored
@@ -1,21 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
/certs/
|
||||
/logs/
|
||||
*.csr
|
||||
*.db
|
||||
/docker-compose/certs/
|
||||
/docker-compose/*-data/data/
|
||||
/docker-compose/*-data/uploads/
|
||||
/docker-compose/.env
|
||||
/docker-compose/.env_*
|
||||
/cmake-build/
|
||||
*.pem
|
||||
result.json
|
||||
token.json
|
||||
197
BUILDING.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Building from source
|
||||
|
||||
In order to build OWSEC, you will need to install its dependencies, which includes the following:
|
||||
- cmake
|
||||
- boost
|
||||
- POCO 1.10.1 or later
|
||||
- a C++17 compiler
|
||||
- openssl
|
||||
- libpq-dev (PortgreSQL development libraries)
|
||||
- mysql-client (MySQL client)
|
||||
- librdkafka
|
||||
- cppkafka
|
||||
|
||||
The build is done in 2 parts. The first part is to build a local copy of the framework tailored to your environment. This
|
||||
framework is called [Poco](https://github.com/pocoproject/poco). The version used in this project has a couple of fixes
|
||||
from the master copy needed for cmake. Please use the version of this [Poco fix](https://github.com/Telecominfraproject/wlan-cloud-lib-poco). Building
|
||||
Poco may take several minutes depending on the platform you are building on.
|
||||
|
||||
## Ubuntu
|
||||
These instructions have proven to work on Ubuntu 20.4.
|
||||
```bash
|
||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev \
|
||||
libpq-dev libaprutil1-dev apache2-dev libboost-all-dev \
|
||||
librdkafka-dev default-libmysqlclient-dev \
|
||||
nlohmann-json-dev
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
|
||||
cd valijson
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/fmtlib/fmt --branch 9.0.0 /fmtlib
|
||||
cd fmtlib
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
|
||||
cd wlan-cloud-ucentralsec
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make -j 8
|
||||
cd ../..
|
||||
```
|
||||
|
||||
## Fedora
|
||||
The following instructions have proven to work on Fedora 33
|
||||
```bash
|
||||
sudo yum install cmake g++ openssl-devel mysql-devel mysql apr-util-devel boost boost-devel \
|
||||
yaml-cpp-devel lua-devel
|
||||
sudo dnf install postgresql.x86_64 librdkafka-devel
|
||||
sudo dnf install postgresql-devel json-devel
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
|
||||
cd cppkafka
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
|
||||
cd valijson
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
|
||||
cd wlan-cloud-ucentralsec
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
make
|
||||
cd ../..
|
||||
```
|
||||
|
||||
## macOS Build
|
||||
The following instructions have proven to work on macOS Big Sur. You need to install [Homebrew](https://brew.sh/). You must also have installed [XCode for OS X](https://www.freecodecamp.org/news/how-to-download-and-install-xcode/).
|
||||
```bash
|
||||
brew install openssl \
|
||||
cmake \
|
||||
libpq \
|
||||
mysql-client \
|
||||
apr \
|
||||
apr-util \
|
||||
boost \
|
||||
yaml-cpp \
|
||||
postgresql \
|
||||
librdkafka \
|
||||
nlohmann-json \
|
||||
fmt
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
pushd poco
|
||||
mkdir cmake-build
|
||||
push cmake-build
|
||||
cmake -DOPENSSL_ROOT_DIR=</path/to/openssl> -DENABLE_NETSSL=1 -DENABLE_JWT=1 -DENABLE_CRYPTO=1 ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch tip-v1 cppkafka
|
||||
pushd cppkafka
|
||||
mkdir cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch tip-v1 valijson
|
||||
pushd valijson
|
||||
mkdir cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
popd
|
||||
popd
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
|
||||
pushd wlan-cloud-ucentralsec
|
||||
mkdir cmake-build
|
||||
pushd cmake-build
|
||||
cmake ..
|
||||
make -j
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
## Raspberry
|
||||
The build on a rPI takes a while. You can shorten that build time and requirements by disabling all the larger database
|
||||
support. You can build with only SQLite support by not installing the packages for PostgreSQL, and MySQL by
|
||||
adding -DSMALL_BUILD=1 on the cmake build line.
|
||||
|
||||
```bash
|
||||
sudo apt install git cmake g++ libssl-dev libaprutil1-dev apache2-dev \
|
||||
libboost-all-dev libyaml-cpp-dev
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco
|
||||
cd poco
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
sudo cmake --build . --target install
|
||||
cd ../..
|
||||
|
||||
git clone https://github.com/Telecominfraproject/wlan-cloud-ucentralsec
|
||||
cd wlan-cloud-ucentralsec
|
||||
mkdir cmake-build
|
||||
cd cmake-build
|
||||
cmake -DSMALL_BUILD=1 ..
|
||||
make
|
||||
cd ../..
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owsec VERSION 2.7.0)
|
||||
project(owsec VERSION 3.1.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -32,17 +32,17 @@ endif()
|
||||
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||
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}")
|
||||
message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
|
||||
endif()
|
||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||
endif()
|
||||
|
||||
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
|
||||
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT -DBOOST_NO_CXX98_FUNCTION_BASE=1)
|
||||
|
||||
set(BUILD_SHARED_LIBS 1)
|
||||
|
||||
@@ -75,18 +75,63 @@ add_executable( owsec
|
||||
src/framework/CountryCodes.h
|
||||
src/framework/KafkaTopics.h
|
||||
src/framework/MicroService.h
|
||||
src/framework/OpenWifiTypes.h
|
||||
src/framework/orm.h
|
||||
src/framework/StorageClass.h
|
||||
src/framework/ow_constants.h
|
||||
src/framework/WebSocketClientNotifications.h
|
||||
src/framework/MicroServiceErrorHandler.h
|
||||
src/framework/UI_WebSocketClientServer.cpp
|
||||
src/framework/UI_WebSocketClientServer.h
|
||||
src/framework/UI_WebSocketClientNotifications.cpp
|
||||
src/framework/UI_WebSocketClientNotifications.h
|
||||
src/framework/utils.h
|
||||
src/framework/utils.cpp
|
||||
src/framework/AppServiceRegistry.h
|
||||
src/framework/SubSystemServer.cpp
|
||||
src/framework/SubSystemServer.h
|
||||
src/framework/RESTAPI_utils.h
|
||||
src/framework/AuthClient.cpp
|
||||
src/framework/AuthClient.h
|
||||
src/framework/MicroServiceNames.h
|
||||
src/framework/MicroServiceFuncs.h
|
||||
src/framework/OpenAPIRequests.cpp
|
||||
src/framework/OpenAPIRequests.h
|
||||
src/framework/MicroServiceFuncs.cpp
|
||||
src/framework/ALBserver.cpp
|
||||
src/framework/ALBserver.h
|
||||
src/framework/KafkaManager.cpp
|
||||
src/framework/KafkaManager.h
|
||||
src/framework/RESTAPI_RateLimiter.h
|
||||
src/framework/WebSocketLogger.h
|
||||
src/framework/RESTAPI_GenericServerAccounting.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/framework/CIDR.h
|
||||
src/framework/RESTAPI_Handler.cpp
|
||||
src/framework/RESTAPI_Handler.h
|
||||
src/framework/RESTAPI_ExtServer.h
|
||||
src/framework/RESTAPI_ExtServer.cpp
|
||||
src/framework/RESTAPI_IntServer.cpp
|
||||
src/framework/RESTAPI_IntServer.h
|
||||
src/framework/RESTAPI_SystemCommand.h
|
||||
src/framework/RESTAPI_WebSocketServer.h
|
||||
src/framework/EventBusManager.cpp
|
||||
src/framework/EventBusManager.h
|
||||
src/framework/RESTAPI_PartHandler.h
|
||||
src/framework/MicroService.cpp
|
||||
src/framework/MicroServiceExtra.h
|
||||
src/framework/default_device_types.h
|
||||
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
|
||||
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
|
||||
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
|
||||
src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
|
||||
src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
|
||||
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
|
||||
src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
|
||||
src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.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/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_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
|
||||
src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
|
||||
@@ -118,14 +163,19 @@ add_executable( owsec
|
||||
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/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.h src/RESTAPI/RESTAPI_apiKey_handler.cpp src/RESTAPI/RESTAPI_apiKey_handler.h src/storage/orm_apikeys.cpp src/storage/orm_apikeys.h src/RESTAPI/RESTAPI_validate_apikey.cpp src/RESTAPI/RESTAPI_validate_apikey.h src/RESTAPI/RESTAPI_systemSecret_handler.cpp src/RESTAPI/RESTAPI_systemSecret_handler.h src/SecretStore.cpp src/SecretStore.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owsec PUBLIC
|
||||
@@ -135,8 +185,9 @@ if(NOT SMALL_BUILD)
|
||||
CppKafka::cppkafka
|
||||
${AWSSDK_LINK_LIBRARIES}
|
||||
fmt::fmt
|
||||
resolv
|
||||
)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(owsec PUBLIC PocoJSON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
270
CONFIGURATION.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# OWSEC Configuration
|
||||
Here is the list of parameters you can configure in the `owsec.properties` file.
|
||||
|
||||
## OWSEC Specific Parameters
|
||||
### OWSEC Login
|
||||
```properties
|
||||
authentication.default.password: 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf
|
||||
authentication.default.username: tip@ucentral.com
|
||||
authentication.enabled: true
|
||||
```
|
||||
|
||||
```properties
|
||||
authentication.token.ageing = 30 * 24 * 60 * 60
|
||||
authentication.oldpasswords = 5
|
||||
openwifi.document.policy.access = /wwwassets/access_policy.html
|
||||
openwifi.document.policy.password = /wwwassets/password_policy.html
|
||||
authentication.validation.expression =
|
||||
subscriber.validation.expression =
|
||||
subscriber.policy.access = /wwwassets/access_policy.html
|
||||
subscriber.policy.password = /wwwassets/password_policy.html
|
||||
```
|
||||
|
||||
### Mail template variables
|
||||
```properties
|
||||
helper.user.email = charles.bourque@arilia.com
|
||||
helper.sub.email = charles.bourque@arilia.com
|
||||
helper.user.global.email = info@arilia.com
|
||||
helper.sub.global.email = info@arilia.com
|
||||
helper.user.site = https://ucentral.dpaas.arilia.com
|
||||
helper.sub.site = https://ucentral.dpaas.arilia.com
|
||||
helper.user.login = https://ucentral.dpaas.arilia.com
|
||||
helper.sub.login = https://ucentral.dpaas.arilia.com
|
||||
helper.user.signature = Arilia Wireless Inc.
|
||||
helper.sub.signature = Arilia Wireless Inc.
|
||||
```
|
||||
|
||||
### Google authenticator
|
||||
```properties
|
||||
totp.issuer: Arilia
|
||||
```
|
||||
|
||||
### Mailer
|
||||
```properties
|
||||
mailer.enabled: true
|
||||
mailer.hostname: email-smtp.us-west-2.amazonaws.com
|
||||
mailer.loginmethod: login
|
||||
mailer.password: ***********************************************
|
||||
mailer.port: 587
|
||||
mailer.sender: no-reply@arilia.com
|
||||
mailer.templates: $OWSEC_ROOT/templates
|
||||
mailer.username: AKIATXEXGKF3QZN543VS
|
||||
```
|
||||
|
||||
### Built-in web server
|
||||
```properties
|
||||
openwifi.avatar.maxsize: 2000000
|
||||
openwifi.document.policy.access: /wwwassets/access_policy.html
|
||||
openwifi.document.policy.password: /wwwassets/password_policy.html
|
||||
```
|
||||
|
||||
### SMS Sender
|
||||
```properties
|
||||
smssender.aws.accesskey: ***********************
|
||||
smssender.aws.region: us-west-2
|
||||
smssender.aws.secretkey: ******************************************+X
|
||||
smssender.enabled: true
|
||||
smssender.provider: aws
|
||||
```
|
||||
|
||||
```properties
|
||||
smssender.provider = twilio
|
||||
smssender.twilio.sid = ***********************
|
||||
smssender.twilio.token = **********************
|
||||
smssender.twilio.phonenumber = +18888888888
|
||||
```
|
||||
|
||||
## Generic OpenWiFi SDK parameters
|
||||
### REST API External parameters
|
||||
These are the parameters required for the configuration of the external facing REST API server
|
||||
```properties
|
||||
openwifi.restapi.host.0.backlog = 100
|
||||
openwifi.restapi.host.0.security = relaxed
|
||||
openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
|
||||
openwifi.restapi.host.0.address = *
|
||||
openwifi.restapi.host.0.port = 16001
|
||||
openwifi.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
|
||||
openwifi.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.restapi.host.0.key.password = mypassword
|
||||
```
|
||||
|
||||
#### openwifi.restapi.host.0.backlog
|
||||
This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
|
||||
#### openwifi.restapi.host.0.rootca
|
||||
This is the root file of your own certificate CA in `pem` format.
|
||||
#### openwifi.restapi.host.0.cert
|
||||
This is your own server certificate in `pem` format..
|
||||
#### openwifi.restapi.host.0.key
|
||||
This is the private key associated with your own certificate in `pem` format.
|
||||
#### openwifi.restapi.host.0.address
|
||||
Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
|
||||
#### openwifi.restapi.host.0.port
|
||||
The port on which the REST API server is listening. By default, this is 16002.
|
||||
#### openwifi.restapi.host.0.security
|
||||
Leave this as `relaxed` for now for devices.
|
||||
#### openwifi.restapi.host.0.key.password
|
||||
If you key file uses a password, please enter it here.
|
||||
|
||||
### REST API Intra microservice parameters
|
||||
The following parameters describe the configuration for the inter-microservice HTTP server. You may use the same certificate/key
|
||||
you are using for your extenral server or another certificate.
|
||||
```properties
|
||||
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
|
||||
openwifi.internal.restapi.host.0.address = *
|
||||
openwifi.internal.restapi.host.0.port = 17001
|
||||
openwifi.internal.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
|
||||
openwifi.internal.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.internal.restapi.host.0.key.password = mypassword
|
||||
```
|
||||
|
||||
#### openwifi.internal.host.0.backlog
|
||||
This is the number of concurrent REST API calls that maybe be kept in the backlog for processing. That's a good rule of thumb. Never go above 500.
|
||||
#### openwifi.internal.host.0.rootca
|
||||
This is the root file of your own certificate CA in `pem` format.
|
||||
#### openwifi.internal.host.0.cert
|
||||
This is your own server certificate in `pem` format..
|
||||
#### openwifi.internal.host.0.key
|
||||
This is the private key associated with your own certificate in `pem` format.
|
||||
#### openwifi.internal.host.0.address
|
||||
Leve this a `*` in the case you want to bind to all interfaces on your gateway host or select the address of a single interface.
|
||||
#### openwifi.internal.host.0.port
|
||||
The port on which the REST API server is listening. By default, this is 17002.
|
||||
#### openwifi.internal.host.0.security
|
||||
Leave this as `relaxed` for now for devices.
|
||||
#### openwifi.internal.host.0.key.password
|
||||
If you key file uses a password, please enter it here.
|
||||
|
||||
### Microservice information
|
||||
These are different Microservie parameters. Following is a brief explanation.
|
||||
```properties
|
||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.service.key.password = mypassword
|
||||
openwifi.system.data = $OWSEC_ROOT/data
|
||||
openwifi.system.uri.private = https://localhost:17004
|
||||
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
|
||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
openwifi.security.restapi.disable = false
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralfms
|
||||
openwifi.autoprovisioning = true
|
||||
```
|
||||
#### openwifi.service.key
|
||||
From time to time, the microservice must encrypt information. This is the key it should use. You may use the
|
||||
same keey as you RESTAPI or your server.
|
||||
#### openwifi.service.key.password
|
||||
The password for the `openwifi.service.key`
|
||||
#### openwifi.system.data
|
||||
The location of system data. This path must exist.
|
||||
#### openwifi.system.uri.private
|
||||
The URI to reach the controller on the internal port.
|
||||
#### openwifi.system.uri.public
|
||||
The URI to reach the controller from the outside world.
|
||||
#### openwifi.system.uri.ui
|
||||
The URI of the UI to manage this service
|
||||
#### openwifi.security.restapi.disable
|
||||
This allows to disable security for internal and external API calls. This should only be used if the controller
|
||||
sits behind an application load balancer that will actually do TLS. Setting this to `true` disables security.
|
||||
#### openwifi.system.commandchannel
|
||||
The UNIX socket command channel used by this service.
|
||||
#### openwifi.autoprovisioning
|
||||
Allow unknown devices to be provisioned by the system.
|
||||
|
||||
### ALB Support
|
||||
In order to support an application load balancer health check verification, your need to provide the following parameters.
|
||||
```properties
|
||||
alb.enable = true
|
||||
alb.port = 16101
|
||||
```
|
||||
|
||||
### Kafka
|
||||
The controller use Kafka, like all the other microservices. You must configure the kafka section in order for the
|
||||
system to work.
|
||||
```properties
|
||||
openwifi.kafka.group.id = security
|
||||
openwifi.kafka.client.id = security1
|
||||
openwifi.kafka.enable = true
|
||||
openwifi.kafka.brokerlist = my_Kafka.example.com:9092
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
```
|
||||
|
||||
### openwifi.kafka.group.id
|
||||
The group ID is a single word that should identify the type of service tuning. In the case `security`
|
||||
### openwifi.kafka.client.id
|
||||
The client ID is a single service within that group ID. Each participant must have a unique client ID.
|
||||
### openwifi.kafka.enable
|
||||
Kafka should always be enabled.
|
||||
### openwifi.kafka.brokerlist
|
||||
The list of servers where your Kafka server is running. Comma separated.
|
||||
### openwifi.kafka.auto.commit
|
||||
Auto commit flag in Kafka. Leave as `false`.
|
||||
### openwifi.kafka.queue.buffering.max.ms
|
||||
Kafka buffering. Leave as `50`.
|
||||
### Kafka security
|
||||
If you intend to use SSL, you should look into Kafka Connect and specify the certificates below.
|
||||
```properties
|
||||
penwifi.kafka.ssl.ca.location =
|
||||
openwifi.kafka.ssl.certificate.location =
|
||||
openwifi.kafka.ssl.key.location =
|
||||
openwifi.kafka.ssl.key.password =
|
||||
```
|
||||
|
||||
### DB Type
|
||||
The controller supports 3 types of Database. SQLite should only be used for sites with less than 100 APs or for testing in the lab.
|
||||
In order to select which database to use, you must set the `storage.type` value to sqlite, postgresql, or mysql.
|
||||
|
||||
```properties
|
||||
storage.type = sqlite
|
||||
#storage.type = postgresql
|
||||
#storage.type = mysql
|
||||
```
|
||||
|
||||
### Storage SQLite parameters
|
||||
Additional parameters to set for SQLite. The only important one is `storage.type.sqlite.db` which is the database name on disk.
|
||||
```properties
|
||||
storage.type.sqlite.db = security.db
|
||||
storage.type.sqlite.idletime = 120
|
||||
storage.type.sqlite.maxsessions = 128
|
||||
```
|
||||
|
||||
### Storage Postgres
|
||||
Additional parameters to set if you select Postgres for your database. You must specify `host`, `username`, `password`,
|
||||
`database`, and `port`.
|
||||
```properties
|
||||
storage.type.postgresql.maxsessions = 64
|
||||
storage.type.postgresql.idletime = 60
|
||||
storage.type.postgresql.host = localhost
|
||||
storage.type.postgresql.username = security
|
||||
storage.type.postgresql.password = security
|
||||
storage.type.postgresql.database = security
|
||||
storage.type.postgresql.port = 5432
|
||||
storage.type.postgresql.connectiontimeout = 60
|
||||
```
|
||||
|
||||
### Storage MySQL/MariaDB
|
||||
Additional parameters to set if you select mysql for your database. You must specify `host`, `username`, `password`,
|
||||
`database`, and `port`.
|
||||
```properties
|
||||
storage.type.mysql.maxsessions = 64
|
||||
storage.type.mysql.idletime = 60
|
||||
storage.type.mysql.host = localhost
|
||||
storage.type.postgresql.username = security
|
||||
storage.type.postgresql.password = security
|
||||
storage.type.postgresql.database = security
|
||||
storage.type.mysql.port = 3306
|
||||
storage.type.mysql.connectiontimeout = 60
|
||||
```
|
||||
|
||||
### Logging Parameters
|
||||
The microservice provides extensive logging. If you would like to keep logging on disk, set the `logging.type = file`. If you only want
|
||||
console logging, `set logging.type = console`. When selecting file, `logging.path` must exist. `logging.level` sets the
|
||||
basic logging level for the entire controller. `logging.websocket` disables WebSocket logging.
|
||||
|
||||
```properties
|
||||
logging.type = file
|
||||
logging.path = $OWSEC_ROOT/logs
|
||||
logging.level = information
|
||||
logging.asynch = true
|
||||
logging.websocket = false
|
||||
```
|
||||
38
CONTRIBUTING.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Version of C++
|
||||
This project is based on the C++17 standard and compiles as-is on most platforms
|
||||
using either clang or g++. Do not use C++21 or C++23 features for now. Some core
|
||||
libraries used in this project do not support C++21 or C++23 yet.
|
||||
|
||||
## Variable Naming
|
||||
Naming of pretty much anything uses Pascal naming. Longer explicit names using casing.
|
||||
Member variable naming adds a `_` at the end of the vars. Try to
|
||||
keep this standard going. Sometimes you must override a base class function and then of course
|
||||
you need to follow the base class.
|
||||
|
||||
## This is a cmake project
|
||||
This is a cmake project, and you need to adhere to the cmake rules. If you need
|
||||
to add a package to the CMakeList, you need to ensure that the package is available
|
||||
on all required platforms and compiles. Remember that this project runs on Linux, OS X,
|
||||
and the Raspberry PI.
|
||||
|
||||
## Licensed packages
|
||||
When adding a package, you must also state the licensing for the package. MIT, BSD, Apache licenses
|
||||
are acceptable. No commercial licenses are allowed.
|
||||
|
||||
## clang formatting
|
||||
Please format your code using the included `.clang-format` file included in the project.
|
||||
|
||||
```bash
|
||||
clang-format -i --style=<project root>/.clang-format myfile.cpp
|
||||
```
|
||||
|
||||
## Pull Requests
|
||||
All submissions, including submissions by project members, require review. We
|
||||
accept GitHub pull requests. Please create a branch with the Jira name for addressing the issue you are fixing or the
|
||||
feature you are implementing.
|
||||
Create a pull-request from the branch into master.
|
||||
91
Dockerfile
@@ -1,24 +1,22 @@
|
||||
ARG DEBIAN_VERSION=11.4-slim
|
||||
ARG POCO_VERSION=poco-tip-v1
|
||||
ARG FMTLIB_VERSION=9.0.0
|
||||
ARG DEBIAN_VERSION=11.5-slim
|
||||
ARG POCO_VERSION=poco-tip-v2
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||
ARG AWS_SDK_VERSION=1.9.315
|
||||
ARG VALIJASON_VERSION=tip-v1
|
||||
|
||||
FROM debian:$DEBIAN_VERSION AS build-base
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
make cmake g++ git \
|
||||
make cmake g++ git curl zip unzip pkg-config \
|
||||
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
||||
librdkafka-dev libboost-all-dev libssl-dev \
|
||||
zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev
|
||||
zlib1g-dev ca-certificates libcurl4-openssl-dev libfmt-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
|
||||
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -27,26 +25,12 @@ 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
|
||||
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -55,62 +39,44 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
FROM build-base AS valijson-build
|
||||
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
ARG VALIJASON_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
|
||||
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-valijson/git/refs/tags/${VALIJASON_VERSION} version.json
|
||||
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-valijson --branch ${VALIJASON_VERSION} /valijson
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
WORKDIR /valijson
|
||||
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
|
||||
|
||||
WORKDIR /aws-sdk-cpp
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake .. -DBUILD_ONLY="sns;s3" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \
|
||||
-DAUTORUN_UNIT_TESTS=OFF
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS owsec-build
|
||||
|
||||
ADD CMakeLists.txt build /owsec/
|
||||
ADD overlays /owsec/overlays
|
||||
ADD cmake /owsec/cmake
|
||||
ADD src /owsec/src
|
||||
ADD .git /owsec/.git
|
||||
ARG VCPKG_VERSION=2022.11.14
|
||||
RUN git clone --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg && \
|
||||
./vcpkg/bootstrap-vcpkg.sh && \
|
||||
mkdir /vcpkg/custom-triplets && \
|
||||
cp /vcpkg/triplets/x64-linux.cmake /vcpkg/custom-triplets/x64-linux.cmake && \
|
||||
sed -i 's/set(VCPKG_LIBRARY.*/set(VCPKG_LIBRARY_LINKAGE dynamic)/g' /vcpkg/custom-triplets/x64-linux.cmake && \
|
||||
./vcpkg/vcpkg install aws-sdk-cpp[sns]:x64-linux json-schema-validator:x64-linux --overlay-triplets=/vcpkg/custom-triplets --overlay-ports=/owsec/overlays
|
||||
|
||||
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 -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM debian:$DEBIAN_VERSION
|
||||
@@ -127,7 +93,7 @@ RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
||||
libmariadb-dev-compat libpq5 unixodbc
|
||||
libmariadb-dev-compat libpq5 postgresql-client libfmt7
|
||||
|
||||
COPY readiness_check /readiness_check
|
||||
COPY test_scripts/curl/cli /cli
|
||||
@@ -141,11 +107,10 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
||||
|
||||
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 --from=owsec-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
|
||||
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=valijson-build /usr/local/include /usr/local/include
|
||||
|
||||
RUN ldconfig
|
||||
|
||||
|
||||
306
README.md
@@ -1,66 +1,100 @@
|
||||
# ucentralsec
|
||||
<p align="center">
|
||||
<img src="images/project/logo.svg" width="200"/>
|
||||
</p>
|
||||
|
||||
uCentralSec is the Authentication & Resource Policy Access service for the uCentral system. In order to use the uCentral system
|
||||
you must have at least 1 uCentralSec. uCentralSec is the first point of contact for the entire architecture. We strongly recommend using Docker
|
||||
to deploy all the uCentral services. If you would like to develop and play with the source, please do.
|
||||
# OpenWiFi Security (OWSEC)
|
||||
|
||||
## What is it?
|
||||
The OWSEC is a service for the TIP OpenWiFi CloudSDK (OWSDK).
|
||||
OWSEC is the Authentication and Resource Policy Access service for the TIP
|
||||
OpenWiFi Cloud SDK (OWSDK). OWSEC,
|
||||
like all other OWSDK microservices, is defined using an OpenAPI definition and uses the ucentral communication
|
||||
protocol to interact with Access Points. To use the OWSUB, you either need to [build it](#building) or use the
|
||||
[Docker version](#docker).
|
||||
|
||||
## Building
|
||||
To build the microservice from source, please follow the instructions in [here](./BUILDING.md)
|
||||
|
||||
## Docker
|
||||
To use the CLoudSDK deployment please follow [here](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy)
|
||||
|
||||
## OpenAPI
|
||||
Like all other uCentral services, uCentralSec is defined through an OpenAPI. You can use this API to build your own applications or integration modules
|
||||
into your own systems. If all you need it to access the uCentralGW for example (the service that manages the APs), you will need to:
|
||||
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
|
||||
Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openapi/owsec.yaml)) to get interactive docs page.
|
||||
|
||||
## Usage
|
||||
Like all other OWSDK services, OWSEC is defined through an OpenAPI. You can use this API to build your own
|
||||
applications or integration modules into your own systems. If all you need it to access the OWGW for
|
||||
example (the service that manages the APs), you will need to:
|
||||
- get a token (`/oauth2`)
|
||||
- find the endpoints on the system (`/systemEndpoints`)
|
||||
- choose one to manage (pick an endpoint that matches what you are trying to do by looking at its `type`. For the gateway, type = ucentrtalgw)
|
||||
- make your calls (use the PublicEndPoint of the corresponding entry to make your calls, do not forget to add `/api/v1` as the root os the call)
|
||||
- choose a microservice to manage (pick an endpoint that matches what you are trying to do by looking at its
|
||||
`type`. For the Cloud SDK Controller, type = owgw)
|
||||
- make your calls (use the PublicEndPoint of the corresponding entry to make your calls,
|
||||
do not forget to add `/api/v1` as the root os the call)
|
||||
|
||||
The CLI for the [uCentralGW](https://github.com/telecominfraproject/wlan-cloud-ucentralgw/blob/main/test_scripts/curl/cli) has a very good example of this.
|
||||
Look for the `setgateway` function.
|
||||
The CLI for the [OWGW](https://github.com/telecominfraproject/wlan-cloud-ucentralsec/blob/main/test_scripts/curl/cli) has
|
||||
a very good example of this. Look for the `setgateway` function.
|
||||
|
||||
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
|
||||
|
||||
Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://validator.swagger.io/validator?url=https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openpapi/owsec.yaml)) to get interactive docs page.
|
||||
|
||||
#### Expected directory layout
|
||||
From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories.
|
||||
```bash
|
||||
mkdir certs
|
||||
mkdir certs/cas
|
||||
mkdir logs
|
||||
mkdir uploads
|
||||
```
|
||||
You should now have the following:
|
||||
```text
|
||||
--+-- certs
|
||||
| +--- cas
|
||||
+-- cmake
|
||||
+-- cmake-build
|
||||
+-- logs
|
||||
+-- src
|
||||
+-- test_scripts
|
||||
+-- openapi
|
||||
+-- uploads
|
||||
+-- owsec.properties
|
||||
```
|
||||
|
||||
### Certificate
|
||||
The OWSEC uses a certificate to provide security for the REST API Certificate to secure the Northbound API.
|
||||
|
||||
#### The `certs` directory
|
||||
For all deployments, you will need the following `certs` directory, populated with the proper files.
|
||||
|
||||
```text
|
||||
certs ---+--- restapi-ca.pem
|
||||
+--- restapi-cert.pem
|
||||
+--- restapi-key.pem
|
||||
```
|
||||
|
||||
## Firewall Considerations
|
||||
The entire uCentral systems uses several MicroServices. In order for the whole system to work, you should provide the following port
|
||||
access:
|
||||
| Port | Description | Configurable |
|
||||
|:------|:-------------------------------------------|:------------:|
|
||||
| 16001 | Default port from the devices to the OWSEC | yes |
|
||||
|
||||
- Security
|
||||
- Properties file: owsec.properties
|
||||
- Ports
|
||||
- Public: 16001
|
||||
- Private: 17001
|
||||
- ALB: 16101
|
||||
### Environment variables
|
||||
The following environment variables should be set from the root directory of the service. They tell the OWGW process where to find
|
||||
the configuration and the root directory.
|
||||
```bash
|
||||
export OWGW_ROOT=`pwd`
|
||||
export OWGW_CONFIG=`pwd`
|
||||
```
|
||||
You can run the shell script `set_env.sh` from the microservice root.
|
||||
|
||||
- Gateway:
|
||||
- Properties file: owgw.properties
|
||||
- Ports
|
||||
- Public: 16002
|
||||
- Private: 17002
|
||||
- ALB: 16102
|
||||
|
||||
- Firmware:
|
||||
- Properties file: owfms.properties
|
||||
- Ports
|
||||
- Public: 16004
|
||||
- Private: 17004
|
||||
- ALB: 16104
|
||||
|
||||
- Provisioning:
|
||||
- Properties file: owprov.properties
|
||||
- Ports
|
||||
- Public: 16004
|
||||
- Private: 17004
|
||||
- ALB: 16104
|
||||
|
||||
## Security Configuration
|
||||
The service relies on a properties configuration file called `owsec.properties`. In this file, you should configure several entries. Many values are optional
|
||||
and you can rely on the defaults. Here are some values of note:
|
||||
|
||||
### `authentication.default.password`
|
||||
Set the hash of the default username and password. Please look below on how to do this.
|
||||
|
||||
### `authentication.default.username`
|
||||
Set the default username to use to login.
|
||||
### OWSEC Service Configuration
|
||||
The configuration is kept in a file called `owsec.properties`. To understand the content of this file,
|
||||
please look [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/CONFIGURATION.md)
|
||||
|
||||
### Default username and password
|
||||
The default username and password are set in `owsec.properties` file. The following entries manage the username and password
|
||||
```text
|
||||
```properties
|
||||
authentication.default.username = tip@ucentral.com
|
||||
authentication.default.password = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
```
|
||||
@@ -75,36 +109,17 @@ echo -n "weLoveWifiroot@system.com" | shasum -a 256
|
||||
b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c -
|
||||
```
|
||||
Then you need to modify your properties file like this
|
||||
```text
|
||||
```properties
|
||||
authentication.default.username = root@system.com
|
||||
authentication.default.password = b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c
|
||||
```
|
||||
Remember, when you login, use `root@system.com` with the password `weLoveWifi`, not this monster digit sequence.
|
||||
|
||||
#### Is this safe?
|
||||
Is this safe to show the hash in a text file? Let me put it this way, if you can find a way to break this encryption, you
|
||||
would have control over the entire internet. It's incredibly safe. If you love math, you can find a lot of videos explaining
|
||||
how hashes work and why they are safe.
|
||||
|
||||
### `authentication.validation.expression`
|
||||
This is a regular expression (regex) to verify the incoming password. You can find many examples on the internet on how to create these expressions. I suggest
|
||||
that using Google is your friend. Someone has figured out what you want to do already. Click [here](https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a)
|
||||
to get a sample. The default is
|
||||
|
||||
```
|
||||
^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$
|
||||
```
|
||||
|
||||
### `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:
|
||||
|
||||
```
|
||||
```bash
|
||||
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'
|
||||
@@ -115,7 +130,7 @@ test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD
|
||||
|
||||
CLI is also included in Docker image if you want to run it this way:
|
||||
|
||||
```
|
||||
```bash
|
||||
export OWSEC=openwifi.wlan.local:16001
|
||||
#export FLAGS="-k"
|
||||
export OWSEC_DEFAULT_USERNAME=root@system.com
|
||||
@@ -132,136 +147,25 @@ docker run --rm -ti \
|
||||
/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.
|
||||
It is very important that you not use spaces in your OrgName.
|
||||
## Kafka topics
|
||||
Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md)
|
||||
|
||||
```
|
||||
openwifi.kafka.group.id = security
|
||||
openwifi.kafka.client.id = security1
|
||||
openwifi.kafka.enable = true
|
||||
openwifi.kafka.brokerlist = my.kafkaserver.arilia.com:9092
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
```
|
||||
## Contributions
|
||||
We need more contributors. Should you wish to contribute,
|
||||
please follow the [contributions](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONTRIBUTING.md) document.
|
||||
|
||||
#### `openwifi.kafka.brokerlist`
|
||||
This is the list of your kafka brokers. This is a comma separated list. You should use IP addresses or FQDNs and the relevant ports, usually 9092 is the
|
||||
default.
|
||||
## Pull Requests
|
||||
Please create a branch with the Jira addressing the issue you are fixing or the feature you are implementing.
|
||||
Create a pull-request from the branch into master.
|
||||
|
||||
#### `openwifi.kafka.group.id`
|
||||
Every service on the Kafka bux must have a unique value (at least in our case). This should be a string. We suggest using a name corresponding to the
|
||||
function provided. In this case, security.
|
||||
|
||||
### Certificates
|
||||
Of course we need certificates. In our case, we already have existing certificates we have. You should find out how your file name correspond
|
||||
to our names. We suggest reusing the same names we use so it is easier to use our default configuration files. We suggest using proper certificates
|
||||
for the publicly visible interfaces. For private interfaces, self-signed certificates are OK. We will not describe how to use/create private certificates
|
||||
here.
|
||||
|
||||
#### The public interface
|
||||
Here are the parameters for the public interface. The important files are:
|
||||
- `restapi-ca.pem` : the CA of your certificate
|
||||
- `restapi-cert.pem` : the certificate for the public interface
|
||||
- `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.
|
||||
|
||||
```
|
||||
openwifi.restapi.host.0.backlog = 100
|
||||
openwifi.restapi.host.0.security = relaxed
|
||||
openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
|
||||
openwifi.restapi.host.0.address = *
|
||||
openwifi.restapi.host.0.port = 16001
|
||||
openwifi.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
|
||||
openwifi.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.restapi.host.0.key.password = mypassword
|
||||
```
|
||||
|
||||
#### The private interface
|
||||
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.
|
||||
|
||||
```
|
||||
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
|
||||
openwifi.internal.restapi.host.0.address = *
|
||||
openwifi.internal.restapi.host.0.port = 17001
|
||||
openwifi.internal.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
|
||||
openwifi.internal.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.internal.restapi.host.0.key.password = mypassword
|
||||
```
|
||||
|
||||
### Other important values
|
||||
Here are other important values you must set.
|
||||
|
||||
|
||||
```
|
||||
openwifi.system.data = $OWSEC_ROOT/data
|
||||
openwifi.system.uri.private = https://localhost:17001
|
||||
openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001
|
||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
|
||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
openwifi.service.key.password = mypassword
|
||||
```
|
||||
#### `openwifi.system.data`
|
||||
The location of some important data files including the user name database.
|
||||
|
||||
#### `openwifi.system.uri.private`
|
||||
This is the FQDN used internally between services.
|
||||
|
||||
#### `openwifi.system.uri.public`
|
||||
This is the FQDN used externally serving the OpenAPI interface.
|
||||
|
||||
### Sending SMS for Multifactor Aithentication
|
||||
`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
|
||||
For SNS you must create an IAM ID that has sns:sendmessage rights.
|
||||
|
||||
```
|
||||
smssender.enabled = true
|
||||
smssender.provider = aws
|
||||
smssender.aws.secretkey = ***************************************
|
||||
smssender.aws.accesskey = ***************************************
|
||||
smssender.aws.region = **************
|
||||
```
|
||||
|
||||
#### Twilio
|
||||
For Twilio, you must provide the following
|
||||
|
||||
```
|
||||
smssender.enabled = true
|
||||
smssender.provider = twilio
|
||||
smssender.twilio.sid = ***********************
|
||||
smssender.twilio.token = **********************
|
||||
smssender.twilio.phonenumber = +18888888888
|
||||
```
|
||||
|
||||
### `owsec` Messaging Configuration
|
||||
`owsec` nay require to send e-mails. In order to do so, you must configure an email sender. We have run tests
|
||||
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
|
||||
mailer.hostname = smtp.gmail.com
|
||||
mailer.username = ************************
|
||||
mailer.password = ************************
|
||||
mailer.sender = OpenWIFI
|
||||
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.
|
||||
## Additional OWSDK Microservices
|
||||
Here is a list of additional OWSDK microservices
|
||||
| Name | Description | Link | OpenAPI |
|
||||
| :--- | :--- | :---: | :---: |
|
||||
| OWSEC | Security Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml) |
|
||||
| OWGW | Controller Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/openapi/owgw.yaml) |
|
||||
| OWFMS | Firmware Management Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms/blob/main/openapi/owfms.yaml) |
|
||||
| OWPROV | Provisioning Service | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov) | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/owprov.yaml) |
|
||||
| OWANALYTICS | Analytics Service | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics) | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics/blob/main/openapi/owanalytics.yaml) |
|
||||
| OWSUB | Subscriber Service | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal) | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal/blob/main/openapi/userportal.yaml) |
|
||||
|
||||
@@ -60,6 +60,16 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owsec"} \
|
||||
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owsec"} \
|
||||
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
|
||||
USER_HELPER_EMAIL=${USER_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
|
||||
SUB_HELPER_EMAIL=${SUB_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
|
||||
GLOBAL_USER_HELPER_EMAIL=${GLOBAL_USER_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
|
||||
GLOBAL_SUB_HELPER_EMAIL=${GLOBAL_SUB_HELPER_EMAIL:-"openwifi@telecominfraproject.com"} \
|
||||
USER_HELPER_SITE=${USER_HELPER_SITE:-"https://openwifi.telecominfraproject.com"} \
|
||||
SUB_HELPER_SITE=${SUB_HELPER_SITE:-"https://openwifi.telecominfraproject.com"} \
|
||||
USER_SYSTEM_LOGIN=${USER_SYSTEM_LOGIN:-"https://openwifi.telecominfraproject.com"} \
|
||||
SUB_SYSTEM_LOGIN=${SUB_SYSTEM_LOGIN:-"https://openwifi.telecominfraproject.com"} \
|
||||
USER_SIGNATURE=${USER_SIGNATURE:-"Telecom Infra Project"} \
|
||||
SUB_SIGNATURE=${SUB_SIGNATURE:-"Telecom Infra Project"} \
|
||||
envsubst < /owsec.properties.tmpl > $OWSEC_CONFIG/owsec.properties
|
||||
fi
|
||||
|
||||
|
||||
BIN
images/device_types/cig_wf160d.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
images/device_types/cig_wf188.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
images/device_types/cig_wf188n.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
images/device_types/cig_wf194c.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
images/device_types/cig_wf194c4.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
images/device_types/cig_wf808.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
images/device_types/cig_wf809.png
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
images/device_types/edgecore_eap101.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
images/device_types/edgecore_eap102.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
images/device_types/edgecore_ecs4100-12ph.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
images/device_types/edgecore_ecw5211.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
images/device_types/edgecore_ecw5410.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
images/device_types/edgecore_oap100.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
images/device_types/edgecore_spw2ac1200-lan-poe.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
images/device_types/edgecore_spw2ac1200.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
images/device_types/edgecore_ssw2ac2600.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
images/device_types/hfcl_ion4.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
images/device_types/hfcl_ion4.yml.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
images/device_types/indio_um-305ac.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
images/device_types/linksys_e8450-ubi.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
images/device_types/linksys_ea6350-v4.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
images/device_types/linksys_ea6350.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
images/device_types/linksys_ea8300.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
images/device_types/tp-link_ec420-g1.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
images/device_types/tplink_ec420.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
images/device_types/tplink_ex227.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
images/device_types/tplink_ex228.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
images/device_types/tplink_ex447.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
images/device_types/wallys_dr40x9.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
images/device_types/wallys_dr6018.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
images/device_types/wallys_dr6018_v4.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
165
images/project/logo.svg
Normal file
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 141.5 185.6" style="enable-background:new 0 0 141.5 185.6;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#414141;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
.st2{fill:#FED206;}
|
||||
.st3{fill:#EB6F53;}
|
||||
.st4{fill:#3BA9B6;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M120.7,183.9H21.5c-10.8,0-19.5-8.7-19.5-19.5V20.5c0-10.8,8.7-19.5,19.5-19.5h99.2
|
||||
c10.8,0,19.5,8.7,19.5,19.5v143.9C140.2,175.2,131.5,183.9,120.7,183.9z"/>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st1" d="M46.3,166.2v-3.4h-1.2v-0.6h3.1v0.6H47v3.4H46.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M49,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H49z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M52.6,166.2v-4h0.7v3.4h1.8v0.6H52.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M55.7,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H55.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M59.1,164.2c0-1.2,0.9-2.1,2.1-2.1c0.8,0,1.3,0.4,1.6,0.9l-0.6,0.3c-0.2-0.3-0.6-0.6-1-0.6
|
||||
c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.4,0,0.8-0.3,1-0.6l0.6,0.3c-0.3,0.5-0.8,0.9-1.6,0.9
|
||||
C60,166.3,59.1,165.5,59.1,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M63.2,164.2c0-1.2,0.8-2.1,2-2.1c1.2,0,2,0.9,2,2.1c0,1.2-0.8,2.1-2,2.1C64,166.3,63.2,165.4,63.2,164.2z
|
||||
M66.5,164.2c0-0.8-0.5-1.4-1.3-1.4c-0.8,0-1.3,0.6-1.3,1.4c0,0.8,0.5,1.4,1.3,1.4C66,165.7,66.5,165,66.5,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M71.3,166.2v-3.1l-1.2,3.1h-0.3l-1.2-3.1v3.1h-0.7v-4h1l1.1,2.7l1.1-2.7h1v4H71.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M75.7,166.2v-4h0.7v4H75.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M80.4,166.2l-2.1-2.8v2.8h-0.7v-4h0.7l2,2.8v-2.8h0.7v4H80.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M82.3,166.2v-4H85v0.6h-2v1h2v0.6h-2v1.7H82.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M87.9,166.2l-0.9-1.5h-0.7v1.5h-0.7v-4h1.7c0.8,0,1.3,0.5,1.3,1.2c0,0.7-0.5,1.1-0.9,1.2l1,1.6H87.9z
|
||||
M88,163.5c0-0.4-0.3-0.6-0.7-0.6h-1v1.3h1C87.7,164.1,88,163.9,88,163.5z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M92.4,166.2l-0.3-0.8h-1.8l-0.3,0.8h-0.8l1.6-4h0.9l1.6,4H92.4z M91.2,162.9l-0.7,1.9h1.4L91.2,162.9z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M95.8,166.2v-4h1.5c0.8,0,1.2,0.5,1.2,1.2c0,0.6-0.4,1.2-1.2,1.2h-1.2v1.7H95.8z M98.2,163.4
|
||||
c0-0.5-0.3-0.9-0.9-0.9h-1.1v1.7h1.1C97.8,164.3,98.2,163.9,98.2,163.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M101.5,166.2l-1.1-1.6h-0.9v1.6h-0.3v-4h1.5c0.7,0,1.2,0.4,1.2,1.2c0,0.7-0.5,1.1-1.1,1.1l1.2,1.7H101.5z
|
||||
M101.6,163.4c0-0.5-0.4-0.9-0.9-0.9h-1.1v1.7h1.1C101.2,164.3,101.6,163.9,101.6,163.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M102.8,164.2c0-1.2,0.8-2.1,1.9-2.1c1.2,0,1.9,0.9,1.9,2.1c0,1.2-0.8,2.1-1.9,2.1
|
||||
C103.6,166.3,102.8,165.4,102.8,164.2z M106.3,164.2c0-1-0.6-1.7-1.6-1.7c-1,0-1.6,0.7-1.6,1.7c0,1,0.6,1.7,1.6,1.7
|
||||
C105.7,166,106.3,165.2,106.3,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M106.9,165.8l0.2-0.3c0.2,0.2,0.4,0.4,0.8,0.4c0.5,0,0.9-0.4,0.9-0.9v-2.8h0.3v2.8c0,0.8-0.5,1.2-1.2,1.2
|
||||
C107.5,166.3,107.2,166.1,106.9,165.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M110.4,166.2v-4h2.5v0.3h-2.2v1.5h2.1v0.3h-2.1v1.6h2.2v0.3H110.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M113.5,164.2c0-1.2,0.9-2.1,2-2.1c0.6,0,1.1,0.3,1.5,0.7l-0.3,0.2c-0.3-0.3-0.7-0.6-1.2-0.6
|
||||
c-0.9,0-1.7,0.7-1.7,1.7c0,1,0.7,1.7,1.7,1.7c0.5,0,0.9-0.2,1.2-0.6l0.3,0.2c-0.4,0.4-0.8,0.7-1.5,0.7
|
||||
C114.4,166.3,113.5,165.5,113.5,164.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M118.7,166.2v-3.7h-1.3v-0.3h2.9v0.3H119v3.7H118.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st1" points="26.3,163.8 31.6,158.5 36.9,163.8 37.7,163.8 31.6,157.6 25.5,163.8 "/>
|
||||
<polygon class="st1" points="36.9,164.7 31.6,170 26.3,164.7 25.5,164.7 31.6,170.8 37.7,164.7 "/>
|
||||
<polygon class="st1" points="31,163.8 36.3,158.5 41.6,163.8 42.5,163.8 36.3,157.6 30.2,163.8 "/>
|
||||
<polygon class="st1" points="41.6,164.7 36.3,170 31,164.7 30.2,164.7 36.3,170.8 42.5,164.7 "/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M33.2,100.7c-4.6,0-8.3,3.7-8.3,8.3s3.7,8.3,8.3,8.3s8.3-3.7,8.3-8.3S37.8,100.7,33.2,100.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st2" d="M33.2,35.2c40.7,0,73.8,33.1,73.8,73.8c0,0.7,0,1.4,0,2.1c0,1.7,0.6,3.3,1.7,4.6c1.2,1.2,2.8,1.9,4.5,2
|
||||
l0.2,0c3.5,0,6.3-2.7,6.4-6.2c0-0.8,0-1.7,0-2.5c0-47.7-38.8-86.6-86.6-86.6c-0.8,0-1.7,0-2.5,0c-1.7,0-3.3,0.8-4.5,2
|
||||
c-1.2,1.2-1.8,2.9-1.7,4.6c0.1,3.5,3,6.3,6.6,6.2C31.8,35.2,32.5,35.2,33.2,35.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st3" d="M33.2,60.5c26.7,0,48.5,21.7,48.5,48.5c0,0.6,0,1.3,0,2c-0.1,1.7,0.5,3.3,1.7,4.6c1.2,1.3,2.7,2,4.4,2.1
|
||||
c1.7,0.1,3.3-0.5,4.6-1.7c1.2-1.2,2-2.7,2-4.4c0-0.9,0.1-1.8,0.1-2.6c0-33.8-27.5-61.2-61.2-61.2c-0.8,0-1.6,0-2.6,0.1
|
||||
c-1.7,0.1-3.3,0.8-4.4,2.1c-1.2,1.3-1.8,2.9-1.7,4.6s0.8,3.3,2.1,4.4c1.3,1.2,2.9,1.8,4.6,1.7C31.9,60.5,32.6,60.5,33.2,60.5z"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st4" d="M33.2,86.7c12.3,0,22.3,10,22.3,22.3c0,0.5,0,1.1-0.1,1.8c-0.3,3.5,2.3,6.6,5.8,6.9
|
||||
c3.5,0.3,6.6-2.3,6.9-5.8c0.1-1,0.1-1.9,0.1-2.8c0-19.3-15.7-35.1-35.1-35.1c-0.9,0-1.8,0-2.8,0.1c-1.7,0.1-3.2,0.9-4.3,2.2
|
||||
c-1.1,1.3-1.6,2.9-1.5,4.6c0.1,1.7,0.9,3.2,2.2,4.3c1.3,1.1,2.9,1.6,4.6,1.5C32.1,86.7,32.7,86.7,33.2,86.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st1" d="M35.8,130.4c1.1,0.6,2.1,1.5,2.7,2.6c0.7,1.1,1,2.3,1,3.7s-0.3,2.6-1,3.7c-0.7,1.1-1.6,2-2.7,2.6
|
||||
c-1.1,0.6-2.4,1-3.8,1s-2.7-0.3-3.8-1c-1.1-0.6-2.1-1.5-2.7-2.6c-0.7-1.1-1-2.3-1-3.7c0-1.3,0.3-2.6,1-3.7c0.7-1.1,1.6-2,2.7-2.6
|
||||
c1.1-0.6,2.4-0.9,3.8-0.9C33.4,129.5,34.7,129.8,35.8,130.4z M29.9,132.9c-0.7,0.4-1.2,0.9-1.6,1.6s-0.6,1.4-0.6,2.2
|
||||
c0,0.8,0.2,1.6,0.6,2.3c0.4,0.7,0.9,1.2,1.6,1.6c0.7,0.4,1.4,0.6,2.1,0.6c0.8,0,1.5-0.2,2.1-0.6c0.6-0.4,1.2-0.9,1.5-1.6
|
||||
c0.4-0.7,0.6-1.4,0.6-2.3c0-0.8-0.2-1.6-0.6-2.2s-0.9-1.2-1.5-1.6c-0.6-0.4-1.4-0.6-2.1-0.6C31.3,132.3,30.6,132.5,29.9,132.9z"/>
|
||||
<path class="st1" d="M50.6,133.6c0.8,0.5,1.4,1.1,1.8,2c0.4,0.8,0.6,1.8,0.6,2.9c0,1.1-0.2,2-0.6,2.8c-0.4,0.8-1,1.5-1.8,1.9
|
||||
c-0.8,0.5-1.6,0.7-2.6,0.7c-0.7,0-1.4-0.1-2-0.4s-1.1-0.7-1.5-1.2v5.4h-3.1V133h3.1v1.6c0.4-0.5,0.9-1,1.4-1.2s1.2-0.4,2-0.4
|
||||
C48.9,132.9,49.8,133.1,50.6,133.6z M49.1,140.5c0.5-0.6,0.7-1.3,0.7-2.2c0-0.9-0.2-1.6-0.7-2.1c-0.5-0.6-1.1-0.8-1.9-0.8
|
||||
s-1.4,0.3-1.9,0.8c-0.5,0.6-0.8,1.3-0.8,2.1c0,0.9,0.2,1.6,0.8,2.2s1.1,0.8,1.9,0.8S48.6,141,49.1,140.5z"/>
|
||||
<path class="st1" d="M63.4,134.4c0.9,1,1.4,2.4,1.4,4.2c0,0.3,0,0.6,0,0.7H57c0.2,0.7,0.5,1.2,1,1.6c0.5,0.4,1.1,0.6,1.8,0.6
|
||||
c0.5,0,1-0.1,1.5-0.3s0.9-0.5,1.3-0.9l1.6,1.6c-0.5,0.6-1.2,1.1-2,1.4c-0.8,0.3-1.6,0.5-2.6,0.5c-1.1,0-2.1-0.2-3-0.7
|
||||
s-1.5-1.1-2-1.9c-0.5-0.8-0.7-1.8-0.7-2.9c0-1.1,0.2-2.1,0.7-2.9s1.1-1.5,2-1.9c0.8-0.5,1.8-0.7,2.9-0.7
|
||||
C61.2,132.9,62.5,133.4,63.4,134.4z M61.8,137.5c0-0.7-0.3-1.3-0.7-1.7s-1-0.6-1.7-0.6c-0.7,0-1.2,0.2-1.7,0.6
|
||||
c-0.4,0.4-0.7,1-0.9,1.7H61.8z"/>
|
||||
<path class="st1" d="M76.2,134c0.7,0.7,1.1,1.7,1.1,3v6.8h-3.1v-5.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.5-0.6
|
||||
c-0.8,0-1.4,0.3-1.8,0.8c-0.4,0.5-0.7,1.2-0.7,2v5.3h-3.1V133h3.1v1.9c0.7-1.3,2-2,3.7-2C74.6,132.8,75.5,133.2,76.2,134z"/>
|
||||
<path class="st1" d="M96,129.7h3.3l-4.7,14h-3.3l-2.9-10.1l-3,10.1h-3.2l-4.7-14h3.4l3,10.7l3-10.7H90l3.1,10.7L96,129.7z"/>
|
||||
<path class="st1" d="M103.3,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
|
||||
c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C102.6,128.2,103,128.3,103.3,128.7z M100.6,133h3.1
|
||||
v10.8h-3.1V133z"/>
|
||||
<path class="st1" d="M106.5,129.7h10.1l0,2.6h-6.9v3.4h6.3v2.6h-6.3v5.3h-3.2V129.7z"/>
|
||||
<path class="st1" d="M120.9,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
|
||||
c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C120.1,128.2,120.5,128.3,120.9,128.7z M118.1,133h3.1
|
||||
v10.8h-3.1V133z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
@@ -17,6 +17,7 @@ servers:
|
||||
security:
|
||||
- bearerAuth: []
|
||||
- ApiKeyAuth: []
|
||||
- ApiToken: []
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
@@ -28,6 +29,10 @@ components:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
ApiToken:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-TOKEN
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
@@ -66,7 +71,8 @@ components:
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
- 14 # CANNOT REFRESH TOKEN
|
||||
- 14 # CANNOT_REFRESH_TOKEN
|
||||
- 15 # ACCOUNT_SUSPENDED
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
@@ -164,18 +170,61 @@ components:
|
||||
aclTemplate:
|
||||
$ref: '#/components/schemas/AclTemplate'
|
||||
|
||||
ApiKeyCreationRequest:
|
||||
ApiKeyAccessRight:
|
||||
type: object
|
||||
properties:
|
||||
service:
|
||||
type: string
|
||||
access:
|
||||
type: string
|
||||
enum:
|
||||
- read
|
||||
- modify
|
||||
- create
|
||||
- delete
|
||||
- noaccess
|
||||
|
||||
ApiKeyAccessRightList:
|
||||
type: object
|
||||
properties:
|
||||
acls:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ApiKeyAccessRight'
|
||||
|
||||
ApiKeyEntry:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
userUuid:
|
||||
type: string
|
||||
format: uuid
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
apiKey:
|
||||
type: string
|
||||
salt:
|
||||
type: string
|
||||
expiresOn:
|
||||
type: integer
|
||||
format: int64
|
||||
lastUse:
|
||||
type: integer
|
||||
format: int64
|
||||
rights:
|
||||
$ref: '#/components/schemas/AclTemplate'
|
||||
$ref: '#/components/schemas/ApiKeyAccessRightList'
|
||||
|
||||
ApiKeyEntryList:
|
||||
type: object
|
||||
properties:
|
||||
apiKeys:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ApiKeyEntry'
|
||||
|
||||
ApiKeyCreationAnswer:
|
||||
type: object
|
||||
@@ -194,7 +243,7 @@ components:
|
||||
apiKey:
|
||||
type: string
|
||||
rights:
|
||||
$ref: '#/components/schemas/AclTemplate'
|
||||
$ref: '#/components/schemas/ApiKeyAccessRightList'
|
||||
|
||||
AclTemplate:
|
||||
type: object
|
||||
@@ -444,6 +493,16 @@ components:
|
||||
sms:
|
||||
type: string
|
||||
|
||||
ExtraSystemConfiguration:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
parameterName:
|
||||
type: string
|
||||
parameterValue:
|
||||
type: string
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
@@ -506,12 +565,6 @@ components:
|
||||
- $ref: '#/components/schemas/StringList'
|
||||
- $ref: '#/components/schemas/TagValuePairList'
|
||||
|
||||
SystemCommandResults:
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/StringList'
|
||||
- $ref: '#/components/schemas/TagValuePairList'
|
||||
|
||||
SystemInfoResults:
|
||||
type: object
|
||||
properties:
|
||||
@@ -540,6 +593,33 @@ components:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
SystemResources:
|
||||
type: object
|
||||
properties:
|
||||
numberOfFileDescriptors:
|
||||
type: integer
|
||||
format: int64
|
||||
currRealMem:
|
||||
type: integer
|
||||
format: int64
|
||||
peakRealMem:
|
||||
type: integer
|
||||
format: int64
|
||||
currVirtMem:
|
||||
type: integer
|
||||
format: int64
|
||||
peakVirtMem:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
SystemCommandResults:
|
||||
type: object
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemResources'
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
- $ref: '#/components/schemas/StringList'
|
||||
- $ref: '#/components/schemas/TagValuePairList'
|
||||
|
||||
ProfileAction:
|
||||
type: object
|
||||
properties:
|
||||
@@ -704,6 +784,23 @@ components:
|
||||
value:
|
||||
type: string
|
||||
|
||||
SystemSecretEntry:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
|
||||
SystemSecretEntryList:
|
||||
type: object
|
||||
properties:
|
||||
secrets:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/SystemSecretEntry'
|
||||
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## End of uCentral system wide values
|
||||
@@ -894,7 +991,7 @@ paths:
|
||||
/systemEndpoints:
|
||||
get:
|
||||
tags:
|
||||
- Authentication
|
||||
- System Commands
|
||||
summary: Retrieve the system layout.
|
||||
operationId: getSystemInfo
|
||||
responses:
|
||||
@@ -1034,6 +1131,12 @@ paths:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
- in: query
|
||||
description: When used, signifies the the id is actually the email address of the user, and not its uuid
|
||||
name: byEmail
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
@@ -1150,6 +1253,12 @@ paths:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
- in: query
|
||||
description: When used, signifies the the id is actually the email address of the user, and not its uuid
|
||||
name: byEmail
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
@@ -1348,7 +1457,7 @@ paths:
|
||||
/email:
|
||||
post:
|
||||
tags:
|
||||
- Email
|
||||
- Messaging
|
||||
summary: Send test email with the system.
|
||||
operationId: Send a test email
|
||||
requestBody:
|
||||
@@ -1379,7 +1488,7 @@ paths:
|
||||
/sms:
|
||||
post:
|
||||
tags:
|
||||
- Email
|
||||
- Messaging
|
||||
summary: Send test email with the system.
|
||||
operationId: Send a test SMS
|
||||
parameters:
|
||||
@@ -1634,7 +1743,103 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
/apiKey/{uuid}:
|
||||
get:
|
||||
tags:
|
||||
- API Tokens
|
||||
summary: Retrieve all the APIKeys for a given user UUID
|
||||
operationId: getApiKeyList
|
||||
parameters:
|
||||
- in: path
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ApiKeyEntryList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
delete:
|
||||
tags:
|
||||
- API Tokens
|
||||
summary: Retrieve all the APIKeys for a given user UUID
|
||||
operationId: deleteApiKey
|
||||
parameters:
|
||||
- in: path
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
- in: query
|
||||
name: keyUuid
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
post:
|
||||
tags:
|
||||
- API Tokens
|
||||
summary: Retrieve all the APIKeys for a given user UUID
|
||||
operationId: createApiKey
|
||||
parameters:
|
||||
- in: path
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiKeyEntry'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ApiKeyEntry'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
put:
|
||||
tags:
|
||||
- API Tokens
|
||||
summary: Retrieve all the APIKeys for a given user UUID
|
||||
operationId: modifyApiKey
|
||||
parameters:
|
||||
- in: path
|
||||
name: uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
- in: query
|
||||
name: name
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiKeyEntry'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ApiKeyEntry'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
@@ -1677,19 +1882,6 @@ paths:
|
||||
#########################################################################################
|
||||
## The following calls are restricted to the private system side APIs
|
||||
#########################################################################################
|
||||
/systemServices:
|
||||
get:
|
||||
tags:
|
||||
- Security
|
||||
summary: Retrieve the basic system information. This information is used between services only.
|
||||
operationId: getSystemServices
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/InternalSystemServices'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/validateToken:
|
||||
get:
|
||||
@@ -1732,6 +1924,26 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/validateApiKey:
|
||||
get:
|
||||
tags:
|
||||
- Security
|
||||
summary: Allows an application to validate an API Key.
|
||||
operationId: validateApiKey
|
||||
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:
|
||||
@@ -1776,21 +1988,167 @@ paths:
|
||||
type: string
|
||||
enum:
|
||||
- info
|
||||
- extraConfiguration
|
||||
- resources
|
||||
required: true
|
||||
|
||||
responses:
|
||||
200:
|
||||
description: Successful command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
$ref: '#/components/schemas/SystemCommandResults'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/systemSecret/{secret}:
|
||||
get:
|
||||
tags:
|
||||
- System Secrets
|
||||
description: Retrieve a specific secret
|
||||
operationId: getSecret
|
||||
parameters:
|
||||
- in: path
|
||||
name: secret
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: all
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: dictionary
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: Successfull retrieval
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- type: object
|
||||
properties:
|
||||
knownKeys:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
helper:
|
||||
type: string
|
||||
- $ref: '#/components/schemas/SystemSecretEntry'
|
||||
- $ref: '#/components/schemas/SystemSecretEntryList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- System Secrets
|
||||
description: Modify a specific secret
|
||||
operationId: modifySecret
|
||||
parameters:
|
||||
- in: path
|
||||
name: secret
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: value
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/SystemSecretEntry'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
description: Remove a specific secret
|
||||
operationId: deleteSecret
|
||||
parameters:
|
||||
- in: path
|
||||
name: secret
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/systemConfiguration:
|
||||
get:
|
||||
tags:
|
||||
- SystemConfiguration
|
||||
summary: Retrieve system configuration items
|
||||
operationId: getSystemConfiguration
|
||||
parameters:
|
||||
- in: query
|
||||
description: Which parameters you want to retrieve
|
||||
name: entries
|
||||
schema:
|
||||
type: string
|
||||
example:
|
||||
- element1
|
||||
- element1,element2,element3
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: List of configuration elements
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ExtraSystemConfiguration'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- SystemConfiguration
|
||||
summary: Set some or all system configuration
|
||||
operationId: setSystemConfiguration
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ExtraSystemConfiguration'
|
||||
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/ExtraSystemConfiguration'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- SystemConfiguration
|
||||
summary: Delete all additional system configuration
|
||||
operationId: deleteSystemConfiguration
|
||||
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
|
||||
1
overlays/curl/portfile.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
||||
4
overlays/curl/vcpkg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "curl",
|
||||
"version-string": "7.74.0-1.3+deb11u3"
|
||||
}
|
||||
1
overlays/openssl/portfile.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
||||
4
overlays/openssl/vcpkg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "openssl",
|
||||
"version-string": "1.1.1n-0+deb11u3"
|
||||
}
|
||||
1
overlays/zlib/portfile.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
||||
4
overlays/zlib/vcpkg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "zlib",
|
||||
"version-string": "1:1.2.11.dfsg-2+deb11u2"
|
||||
}
|
||||
@@ -34,8 +34,8 @@ authentication.default.username = tip@ucentral.com
|
||||
authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf
|
||||
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.system.uri.public = https://main.server.com:16001
|
||||
openwifi.system.uri.ui = https://ucentral-ui.main.server.com
|
||||
openwifi.security.restapi.disable = false
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
|
||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||
@@ -64,9 +64,19 @@ mailer.loginmethod = login
|
||||
mailer.port = 587
|
||||
mailer.templates = $OWSEC_ROOT/templates
|
||||
|
||||
helper.user.email = openwifi@telecominfraproject.com
|
||||
helper.sub.email = openwifi@telecominfraproject.com
|
||||
helper.user.global.email = openwifi@telecominfraproject.com
|
||||
helper.sub.global.email = openwifi@telecominfraproject.com
|
||||
helper.user.site = https://openwifi.telecominfraproject.com
|
||||
helper.sub.site = https://openwifi.telecominfraproject.com
|
||||
helper.user.login = https://openwifi.telecominfraproject.com
|
||||
helper.sub.login = https://openwifi.telecominfraproject.com
|
||||
helper.user.signature = Telecom Infra Project
|
||||
helper.sub.signature = Telecom Infra Project
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
# Generic information for all micro-services
|
||||
#############################
|
||||
#
|
||||
# NLB Support
|
||||
@@ -80,7 +90,7 @@ alb.port = 16101
|
||||
openwifi.kafka.group.id = security
|
||||
openwifi.kafka.client.id = security1
|
||||
openwifi.kafka.enable = true
|
||||
openwifi.kafka.brokerlist = a1.arilia.com:9092
|
||||
openwifi.kafka.brokerlist = kafka:9092
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
openwifi.kafka.ssl.ca.location =
|
||||
@@ -110,18 +120,18 @@ storage.type.sqlite.maxsessions = 128
|
||||
storage.type.postgresql.maxsessions = 64
|
||||
storage.type.postgresql.idletime = 60
|
||||
storage.type.postgresql.host = localhost
|
||||
storage.type.postgresql.username = stephb
|
||||
storage.type.postgresql.password = snoopy99
|
||||
storage.type.postgresql.database = ucentral
|
||||
storage.type.postgresql.username = owsec
|
||||
storage.type.postgresql.password = owsec
|
||||
storage.type.postgresql.database = owsec
|
||||
storage.type.postgresql.port = 5432
|
||||
storage.type.postgresql.connectiontimeout = 60
|
||||
|
||||
storage.type.mysql.maxsessions = 64
|
||||
storage.type.mysql.idletime = 60
|
||||
storage.type.mysql.host = localhost
|
||||
storage.type.mysql.username = stephb
|
||||
storage.type.mysql.password = snoopy99
|
||||
storage.type.mysql.database = ucentral
|
||||
storage.type.mysql.username = owsec
|
||||
storage.type.mysql.password = owsec
|
||||
storage.type.mysql.database = owsec
|
||||
storage.type.mysql.port = 3306
|
||||
storage.type.mysql.connectiontimeout = 60
|
||||
|
||||
|
||||
@@ -64,6 +64,16 @@ mailer.loginmethod = login
|
||||
mailer.port = ${MAILER_PORT}
|
||||
mailer.templates = ${MAILER_TEMPLATES}
|
||||
|
||||
helper.user.email = ${USER_HELPER_EMAIL}
|
||||
helper.sub.email = ${SUB_HELPER_EMAIL}
|
||||
helper.user.global.email = ${GLOBAL_USER_HELPER_EMAIL}
|
||||
helper.sub.global.email = ${GLOBAL_SUB_HELPER_EMAIL}
|
||||
helper.user.site = ${USER_HELPER_SITE}
|
||||
helper.sub.site = ${SUB_HELPER_SITE}
|
||||
helper.user.login = ${USER_SYSTEM_LOGIN}
|
||||
helper.sub.login = ${SUB_SYSTEM_LOGIN}
|
||||
helper.user.signature = ${USER_SIGNATURE}
|
||||
helper.sub.signature = ${SUB_SIGNATURE}
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
|
||||
@@ -9,82 +9,124 @@
|
||||
|
||||
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
|
||||
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) {
|
||||
*/
|
||||
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;
|
||||
switch (Op) {
|
||||
case DELETE: {
|
||||
// can a user delete themselves - yes - only if not root. We do not want a system
|
||||
// to end up rootless
|
||||
if (User.id == Target.id) {
|
||||
return User.userRole != SecurityObjects::ROOT;
|
||||
}
|
||||
// Root can delete anyone
|
||||
switch (User.userRole) {
|
||||
case SecurityObjects::ROOT:
|
||||
return true;
|
||||
case SecurityObjects::ADMIN:
|
||||
return Target.userRole != SecurityObjects::ROOT &&
|
||||
Target.userRole != SecurityObjects::PARTNER;
|
||||
case SecurityObjects::SUBSCRIBER:
|
||||
return User.id == Target.id;
|
||||
case SecurityObjects::CSR:
|
||||
return false;
|
||||
case SecurityObjects::SYSTEM:
|
||||
return Target.userRole != SecurityObjects::ROOT &&
|
||||
Target.userRole != SecurityObjects::PARTNER;
|
||||
case SecurityObjects::INSTALLER:
|
||||
return User.id == Target.id;
|
||||
case SecurityObjects::NOC:
|
||||
return Target.userRole == SecurityObjects::NOC;
|
||||
case SecurityObjects::ACCOUNTING:
|
||||
return Target.userRole == SecurityObjects::ACCOUNTING;
|
||||
case SecurityObjects::PARTNER:
|
||||
return Target.userRole != SecurityObjects::ROOT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
// rule 1
|
||||
if(User.id == Target.id && Op==DELETE)
|
||||
return false;
|
||||
case READ: {
|
||||
return User.userRole == SecurityObjects::ROOT ||
|
||||
User.userRole == SecurityObjects::ADMIN ||
|
||||
User.userRole == SecurityObjects::PARTNER;
|
||||
} break;
|
||||
|
||||
// rule 2
|
||||
if(User.userRole==SecurityObjects::ROOT)
|
||||
return true;
|
||||
case CREATE: {
|
||||
switch (User.userRole) {
|
||||
case SecurityObjects::ROOT:
|
||||
return true;
|
||||
case SecurityObjects::ADMIN:
|
||||
return Target.userRole != SecurityObjects::ROOT &&
|
||||
Target.userRole != SecurityObjects::PARTNER;
|
||||
case SecurityObjects::SUBSCRIBER:
|
||||
return false;
|
||||
case SecurityObjects::CSR:
|
||||
return Target.userRole == SecurityObjects::CSR;
|
||||
case SecurityObjects::SYSTEM:
|
||||
return Target.userRole != SecurityObjects::ROOT &&
|
||||
Target.userRole != SecurityObjects::PARTNER;
|
||||
case SecurityObjects::INSTALLER:
|
||||
return Target.userRole == SecurityObjects::INSTALLER;
|
||||
case SecurityObjects::NOC:
|
||||
return Target.userRole == SecurityObjects::NOC;
|
||||
case SecurityObjects::ACCOUNTING:
|
||||
return Target.userRole == SecurityObjects::ACCOUNTING;
|
||||
case SecurityObjects::PARTNER:
|
||||
return Target.userRole != SecurityObjects::ROOT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
// rule 3
|
||||
if(User.id == Target.id)
|
||||
return true;
|
||||
case MODIFY: {
|
||||
switch (User.userRole) {
|
||||
case SecurityObjects::ROOT:
|
||||
return true;
|
||||
case SecurityObjects::ADMIN:
|
||||
return Target.userRole != SecurityObjects::ROOT &&
|
||||
Target.userRole != SecurityObjects::PARTNER;
|
||||
case SecurityObjects::SUBSCRIBER:
|
||||
return User.id == Target.id;
|
||||
case SecurityObjects::CSR:
|
||||
return Target.userRole == SecurityObjects::CSR;
|
||||
case SecurityObjects::SYSTEM:
|
||||
return Target.userRole != SecurityObjects::ROOT &&
|
||||
Target.userRole != SecurityObjects::PARTNER;
|
||||
case SecurityObjects::INSTALLER:
|
||||
return Target.userRole == SecurityObjects::INSTALLER;
|
||||
case SecurityObjects::NOC:
|
||||
return Target.userRole == SecurityObjects::NOC;
|
||||
case SecurityObjects::ACCOUNTING:
|
||||
return Target.userRole == SecurityObjects::ACCOUNTING;
|
||||
case SecurityObjects::PARTNER:
|
||||
return Target.userRole != SecurityObjects::ROOT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// rule 4
|
||||
if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
|
||||
return false;
|
||||
private:
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //OWSEC_ACLPROCESSOR_H
|
||||
#endif // OWSEC_ACLPROCESSOR_H
|
||||
|
||||
@@ -3,124 +3,142 @@
|
||||
//
|
||||
|
||||
#include "ActionLinkManager.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "MessagingTemplates.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "StorageService.h"
|
||||
#include "fmt/format.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int ActionLinkManager::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
if(!Running_)
|
||||
Thr_.start(*this);
|
||||
return 0;
|
||||
}
|
||||
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::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");
|
||||
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);
|
||||
}
|
||||
Poco::Thread::trySleep(10000);
|
||||
|
||||
if(Links.empty())
|
||||
continue;
|
||||
while (Running_) {
|
||||
Poco::Thread::trySleep(2000);
|
||||
if (!Running_)
|
||||
break;
|
||||
std::vector<SecurityObjects::ActionLink> Links;
|
||||
{
|
||||
std::lock_guard G(Mutex_);
|
||||
StorageService()->ActionLinksDB().GetActions(Links);
|
||||
}
|
||||
|
||||
for(auto &i:Links) {
|
||||
if(!Running_)
|
||||
break;
|
||||
if (Links.empty())
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
for (auto &i : Links) {
|
||||
if (!Running_)
|
||||
break;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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::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::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::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::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_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_FORGOT_PASSWORD: {
|
||||
if (AuthService()->SendEmailToSubUser(i.id, UInfo.email,
|
||||
MessagingTemplates::SUB_FORGOT_PASSWORD,"")) {
|
||||
poco_information(
|
||||
Logger(),
|
||||
fmt::format("Send subscriber password reset 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;
|
||||
case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
|
||||
if (AuthService()->SendEmailToSubUser(
|
||||
i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION,"")) {
|
||||
poco_information(
|
||||
Logger(), fmt::format("Send subscriber email verification link to {}",
|
||||
UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
|
||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp, ":");
|
||||
if (AuthService()->SendEmailToSubUser(
|
||||
i.id, UInfo.email, MessagingTemplates::SUB_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -2,35 +2,29 @@
|
||||
// Created by stephane bourque on 2021-11-08.
|
||||
//
|
||||
|
||||
#ifndef OWSEC_ACTIONLINKMANAGER_H
|
||||
#define OWSEC_ACTIONLINKMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
static ActionLinkManager *instance() {
|
||||
static auto instance_ = new ActionLinkManager;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
static ActionLinkManager * instance() {
|
||||
static auto instance_ = new ActionLinkManager;
|
||||
return instance_;
|
||||
}
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
void run() final;
|
||||
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
void run() final;
|
||||
private:
|
||||
Poco::Thread Thr_;
|
||||
std::atomic_bool Running_ = false;
|
||||
|
||||
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
|
||||
ActionLinkManager() noexcept
|
||||
: SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server") {}
|
||||
};
|
||||
inline ActionLinkManager *ActionLinkManager() { return ActionLinkManager::instance(); }
|
||||
} // namespace OpenWifi
|
||||
|
||||
1438
src/AuthService.cpp
@@ -6,163 +6,229 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRAL_UAUTHSERVICE_H
|
||||
#define UCENTRAL_UAUTHSERVICE_H
|
||||
#pragma once
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "Poco/Crypto/DigestEngine.h"
|
||||
#include "Poco/ExpireLRUCache.h"
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JWT/Signer.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/JWT/Signer.h"
|
||||
#include "Poco/SHA2Engine.h"
|
||||
#include "Poco/Crypto/DigestEngine.h"
|
||||
#include "Poco/HMACEngine.h"
|
||||
#include "Poco/ExpireLRUCache.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "MessagingTemplates.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi{
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string AUTHENTICATION_SYSTEM{"SYSTEM"};
|
||||
static const std::string AUTHENTICATION_SYSTEM{"SYSTEM"};
|
||||
|
||||
class AuthService : public SubSystemServer {
|
||||
public:
|
||||
class AuthService : public SubSystemServer {
|
||||
public:
|
||||
enum ACCESS_TYPE { USERNAME, SERVER, CUSTOM };
|
||||
|
||||
enum ACCESS_TYPE {
|
||||
USERNAME,
|
||||
SERVER,
|
||||
CUSTOM
|
||||
};
|
||||
static ACCESS_TYPE IntToAccessType(int C);
|
||||
static int AccessTypeToInt(ACCESS_TYPE T);
|
||||
|
||||
static ACCESS_TYPE IntToAccessType(int C);
|
||||
static int AccessTypeToInt(ACCESS_TYPE T);
|
||||
static auto instance() {
|
||||
static auto instance_ = new AuthService;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new AuthService;
|
||||
return instance_;
|
||||
}
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
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]] bool IsAuthorized(const std::string &SessionToken,
|
||||
SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||
std::uint64_t TID, bool &Expired);
|
||||
|
||||
[[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 );
|
||||
void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
[[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]] UNAUTHORIZED_REASON Authorize(std::string &UserName,
|
||||
const std::string &Password,
|
||||
const std::string &NewPassword,
|
||||
SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||
bool &Expired);
|
||||
void CreateToken(const std::string &UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
[[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);
|
||||
[[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 RemoveTokenSystemWide(const std::string &token);
|
||||
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);
|
||||
|
||||
bool ValidatePassword(const std::string &pwd);
|
||||
bool ValidateSubPassword(const std::string &pwd);
|
||||
void RemoveTokenSystemWide(const std::string &token);
|
||||
|
||||
[[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]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
|
||||
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
|
||||
bool ValidatePassword(const std::string &pwd);
|
||||
bool ValidateSubPassword(const std::string &pwd);
|
||||
|
||||
[[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 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]] std::string GenerateTokenJWT(const std::string &UserName, ACCESS_TYPE Type);
|
||||
[[nodiscard]] std::string GenerateTokenHMAC(const std::string &UserName, ACCESS_TYPE Type);
|
||||
|
||||
[[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 IsValidApiKey(const std::string &ApiKey,
|
||||
SecurityObjects::WebToken &WebToken,
|
||||
SecurityObjects::UserInfo &UserInfo, bool &Expired,
|
||||
std::uint64_t &expiresOn, bool &Suspended);
|
||||
[[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 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]] bool UpdatePassword(const std::string &Admin, const std::string &UserName,
|
||||
const std::string &OldPassword,
|
||||
const std::string &NewPassword);
|
||||
[[nodiscard]] std::string ResetPassword(const std::string &Admin,
|
||||
const std::string &UserName);
|
||||
|
||||
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
|
||||
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
|
||||
[[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 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]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
|
||||
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
|
||||
|
||||
[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code);
|
||||
[[nodiscard]] bool SendEmailToUser(const std::string &LinkId, std::string &Email,
|
||||
MessagingTemplates::EMAIL_REASON Reason);
|
||||
[[nodiscard]] bool SendEmailToSubUser(const std::string &LinkId, std::string &Email,
|
||||
MessagingTemplates::EMAIL_REASON Reason,
|
||||
const std::string &OperatorName);
|
||||
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
|
||||
bool DeleteUserFromCache(const std::string &UserName);
|
||||
bool DeleteSubUserFromCache(const std::string &UserName);
|
||||
void RevokeToken(std::string & Token);
|
||||
void RevokeSubToken(std::string & Token);
|
||||
[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||
const std::string &code);
|
||||
|
||||
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
|
||||
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
|
||||
}
|
||||
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 GetLogoAssetFileName() {
|
||||
return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
|
||||
}
|
||||
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
|
||||
return MicroServicePublicEndPoint() + "/wwwassets/logo.png";
|
||||
}
|
||||
|
||||
inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
|
||||
inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
|
||||
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
|
||||
return MicroServiceWWWAssetsDir() + "/logo.png";
|
||||
}
|
||||
|
||||
inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
|
||||
inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; }
|
||||
[[nodiscard]] static inline const std::string GetSubLogoAssetURI() {
|
||||
return MicroServicePublicEndPoint() + "/wwwassets/sub_logo.png";
|
||||
}
|
||||
|
||||
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);
|
||||
[[nodiscard]] static inline const std::string GetSubLogoAssetFileName() {
|
||||
return MicroServiceWWWAssetsDir() + "/sub_logo.png";
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::SHA2Engine SHA2_;
|
||||
inline const std::string &GetPasswordPolicy() const { return PasswordPolicy_; }
|
||||
inline const std::string &GetAccessPolicy() const { return AccessPolicy_; }
|
||||
|
||||
std::string AccessPolicy_;
|
||||
std::string PasswordPolicy_;
|
||||
std::string SubAccessPolicy_;
|
||||
std::string SubPasswordPolicy_;
|
||||
std::string PasswordValidationStr_;
|
||||
std::string SubPasswordValidationStr_;
|
||||
std::regex PasswordValidation_;
|
||||
std::regex SubPasswordValidation_;
|
||||
inline const std::string &GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
|
||||
inline const std::string &GetSubAccessPolicy() const { return SubAccessPolicy_; }
|
||||
|
||||
uint64_t TokenAging_ = 15 * 24 * 60 * 60;
|
||||
uint64_t HowManyOldPassword_=5;
|
||||
uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ;
|
||||
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);
|
||||
|
||||
class SHA256Engine : public Poco::Crypto::DigestEngine
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
BLOCK_SIZE = 64,
|
||||
DIGEST_SIZE = 32
|
||||
};
|
||||
[[nodiscard]] inline auto HelperEmail() const { return HelperEmail_; };
|
||||
[[nodiscard]] inline auto SubHelperEmail() const { return SubHelperEmail_; };
|
||||
[[nodiscard]] inline auto GlobalHelperEmail() const { return GlobalHelperEmail_; };
|
||||
[[nodiscard]] inline auto GlobalSubHelperEmail() const { return GlobalSubHelperEmail_; };
|
||||
[[nodiscard]] inline auto HelperSite() const { return HelperSite_; };
|
||||
[[nodiscard]] inline auto SubHelperSite() const { return SubHelperSite_; };
|
||||
[[nodiscard]] inline auto SystemLoginSite() const { return SystemLoginSite_; };
|
||||
[[nodiscard]] inline auto SubSystemLoginSite() const { return SubSystemLoginSite_; };
|
||||
[[nodiscard]] inline auto UserSignature() const { return UserSignature_; };
|
||||
[[nodiscard]] inline auto SubSignature() const { return SubSignature_; };
|
||||
|
||||
SHA256Engine()
|
||||
: DigestEngine("SHA256")
|
||||
{
|
||||
}
|
||||
private:
|
||||
Poco::SHA2Engine SHA2_;
|
||||
|
||||
};
|
||||
std::string AccessPolicy_;
|
||||
std::string PasswordPolicy_;
|
||||
std::string SubAccessPolicy_;
|
||||
std::string SubPasswordPolicy_;
|
||||
std::string PasswordValidationStr_;
|
||||
std::string SubPasswordValidationStr_;
|
||||
std::regex PasswordValidation_;
|
||||
std::regex SubPasswordValidation_;
|
||||
|
||||
Poco::HMACEngine<SHA256Engine> HMAC_{"tipopenwifi"};
|
||||
uint64_t TokenAging_ = 15 * 24 * 60 * 60;
|
||||
uint64_t HowManyOldPassword_ = 5;
|
||||
uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60;
|
||||
|
||||
AuthService() noexcept:
|
||||
SubSystemServer("Authentication", "AUTH-SVR", "authentication")
|
||||
{
|
||||
}
|
||||
};
|
||||
std::string HelperEmail_;
|
||||
std::string SubHelperEmail_;
|
||||
std::string GlobalHelperEmail_;
|
||||
std::string GlobalSubHelperEmail_;
|
||||
std::string HelperSite_;
|
||||
std::string SubHelperSite_;
|
||||
std::string SystemLoginSite_;
|
||||
std::string SubSystemLoginSite_;
|
||||
std::string UserSignature_;
|
||||
std::string SubSignature_;
|
||||
|
||||
inline auto AuthService() { return AuthService::instance(); }
|
||||
class SHA256Engine : public Poco::Crypto::DigestEngine {
|
||||
public:
|
||||
enum { BLOCK_SIZE = 64, DIGEST_SIZE = 32 };
|
||||
|
||||
[[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 );
|
||||
}
|
||||
SHA256Engine() : DigestEngine("SHA256") {}
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
Poco::HMACEngine<SHA256Engine> HMAC_{"tipopenwifi"};
|
||||
|
||||
#endif //UCENTRAL_UAUTHSERVICE_H
|
||||
AuthService() noexcept : SubSystemServer("Authentication", "AUTH-SVR", "authentication") {}
|
||||
};
|
||||
|
||||
inline auto 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);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -10,73 +10,70 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
#include "Poco/Environment.h"
|
||||
|
||||
#include "Daemon.h"
|
||||
|
||||
#include <aws/core/Aws.h>
|
||||
#include <aws/s3/model/AccessControlPolicy.h>
|
||||
|
||||
#include "StorageService.h"
|
||||
#include "SMTPMailerService.h"
|
||||
#include "ActionLinkManager.h"
|
||||
#include "AuthService.h"
|
||||
#include "SMSSender.h"
|
||||
#include "ActionLinkManager.h"
|
||||
#include "SMTPMailerService.h"
|
||||
#include "StorageService.h"
|
||||
#include "TotpCache.h"
|
||||
#include "framework/RESTAPI_RateLimiter.h"
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
#include <SecretStore.h>
|
||||
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance_ = nullptr;
|
||||
class Daemon *Daemon::instance_ = nullptr;
|
||||
|
||||
class Daemon *Daemon::instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new Daemon(vDAEMON_PROPERTIES_FILENAME,
|
||||
vDAEMON_ROOT_ENV_VAR,
|
||||
vDAEMON_CONFIG_ENV_VAR,
|
||||
vDAEMON_APP_NAME,
|
||||
vDAEMON_BUS_TIMER,
|
||||
SubSystemVec{
|
||||
StorageService(),
|
||||
SMSSender(),
|
||||
ActionLinkManager(),
|
||||
SMTPMailerService(),
|
||||
RESTAPI_RateLimiter(),
|
||||
TotpCache(),
|
||||
AuthService()
|
||||
});
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
class Daemon *Daemon::instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ =
|
||||
new Daemon(vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR,
|
||||
vDAEMON_CONFIG_ENV_VAR, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
|
||||
SubSystemVec{StorageService(), SMSSender(), AuthService(), ActionLinkManager(),
|
||||
SMTPMailerService(), RESTAPI_RateLimiter(), TotpCache(),
|
||||
UI_WebSocketClientServer(), SecretStore()});
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||
AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
|
||||
}
|
||||
}
|
||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||
AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
|
||||
}
|
||||
|
||||
void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
Daemon()->PostInitialization(self);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
try {
|
||||
SSL_library_init();
|
||||
Aws::SDKOptions AwsOptions;
|
||||
AwsOptions.memoryManagementOptions.memoryManager = nullptr;
|
||||
AwsOptions.cryptoOptions.initAndCleanupOpenSSL = false;
|
||||
AwsOptions.httpOptions.initAndCleanupCurl = true;
|
||||
try {
|
||||
SSL_library_init();
|
||||
Aws::SDKOptions AwsOptions;
|
||||
AwsOptions.memoryManagementOptions.memoryManager = nullptr;
|
||||
AwsOptions.cryptoOptions.initAndCleanupOpenSSL = false;
|
||||
AwsOptions.httpOptions.initAndCleanupCurl = true;
|
||||
|
||||
Aws::InitAPI(AwsOptions);
|
||||
Aws::InitAPI(AwsOptions);
|
||||
|
||||
int ExitCode=0;
|
||||
{
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
ExitCode = App->run(argc, argv);
|
||||
}
|
||||
ShutdownAPI(AwsOptions);
|
||||
return ExitCode;
|
||||
} catch (Poco::Exception &exc) {
|
||||
std::cout << exc.displayText() << std::endl;
|
||||
return Poco::Util::Application::EXIT_SOFTWARE;
|
||||
}
|
||||
int ExitCode = 0;
|
||||
{
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
ExitCode = App->run(argc, argv);
|
||||
}
|
||||
ShutdownAPI(AwsOptions);
|
||||
return ExitCode;
|
||||
} catch (Poco::Exception &exc) {
|
||||
std::cout << exc.displayText() << std::endl;
|
||||
return Poco::Util::Application::EXIT_SOFTWARE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// end of namespace
|
||||
|
||||
69
src/Daemon.h
@@ -2,57 +2,50 @@
|
||||
// Created by stephane bourque on 2021-06-10.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_DAEMON_H
|
||||
#define UCENTRALSEC_DAEMON_H
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/MicroServiceNames.h"
|
||||
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
#include "Poco/Crypto/CipherFactory.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/UUIDGenerator.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Util/ServerApplication.h"
|
||||
#include "Poco/Util/Option.h"
|
||||
#include "Poco/Util/OptionSet.h"
|
||||
#include "Poco/UUIDGenerator.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Crypto/RSAKey.h"
|
||||
#include "Poco/Crypto/CipherFactory.h"
|
||||
#include "Poco/Crypto/Cipher.h"
|
||||
|
||||
#include "Poco/Util/ServerApplication.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;
|
||||
[[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;
|
||||
|
||||
class Daemon : public MicroService {
|
||||
public:
|
||||
explicit Daemon(const std::string & PropFile,
|
||||
const std::string & RootEnv,
|
||||
const std::string & ConfigEnv,
|
||||
const std::string & AppName,
|
||||
uint64_t BusTimer,
|
||||
const SubSystemVec & SubSystems) :
|
||||
MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
|
||||
class Daemon : public MicroService {
|
||||
public:
|
||||
explicit Daemon(const std::string &PropFile, const std::string &RootEnv,
|
||||
const std::string &ConfigEnv, const std::string &AppName, uint64_t BusTimer,
|
||||
const SubSystemVec &SubSystems)
|
||||
: MicroService(PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems){};
|
||||
|
||||
void PostInitialization(Poco::Util::Application &self);
|
||||
static Daemon *instance();
|
||||
inline const std::string & AssetDir() { return AssetDir_; }
|
||||
private:
|
||||
static Daemon *instance_;
|
||||
std::string AssetDir_;
|
||||
};
|
||||
void PostInitialization(Poco::Util::Application &self);
|
||||
static Daemon *instance();
|
||||
inline const std::string &AssetDir() { return AssetDir_; }
|
||||
|
||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||
inline void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
Daemon()->PostInitialization(self);
|
||||
}
|
||||
}
|
||||
private:
|
||||
static Daemon *instance_;
|
||||
std::string AssetDir_;
|
||||
};
|
||||
|
||||
#endif //UCENTRALSEC_DAEMON_H
|
||||
inline Daemon *Daemon() { return Daemon::instance(); }
|
||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -2,114 +2,125 @@
|
||||
// Created by stephane bourque on 2021-10-11.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "MFAServer.h"
|
||||
#include "AuthService.h"
|
||||
#include "SMSSender.h"
|
||||
#include "SMTPMailerService.h"
|
||||
#include "AuthService.h"
|
||||
#include "TotpCache.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int MFAServer::Start() {
|
||||
return 0;
|
||||
}
|
||||
int MFAServer::Start() { return 0; }
|
||||
|
||||
void MFAServer::Stop() {
|
||||
}
|
||||
void MFAServer::Stop() {}
|
||||
|
||||
bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &ChallengeStart) {
|
||||
std::lock_guard G(Mutex_);
|
||||
bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||
Poco::JSON::Object &ChallengeStart) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
CleanCache();
|
||||
CleanCache();
|
||||
|
||||
if(!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
|
||||
return false;
|
||||
if (!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
|
||||
return false;
|
||||
|
||||
std::string Challenge = MakeChallenge();
|
||||
std::string uuid = MicroService::CreateUUID();
|
||||
uint64_t Created = OpenWifi::Now();
|
||||
std::string Challenge = MakeChallenge();
|
||||
std::string uuid = MicroServiceCreateUUID();
|
||||
uint64_t Created = Utils::Now();
|
||||
|
||||
ChallengeStart.set("uuid",uuid);
|
||||
ChallengeStart.set("created", Created);
|
||||
ChallengeStart.set("question", "mfa challenge");
|
||||
ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
|
||||
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 };
|
||||
return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
|
||||
}
|
||||
Cache_[uuid] = MFACacheEntry{.UInfo = UInfo,
|
||||
.Answer = Challenge,
|
||||
.Created = Created,
|
||||
.Method = UInfo.userinfo.userTypeProprietaryInfo.mfa.method};
|
||||
return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
|
||||
}
|
||||
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MFAServer::ResendCode(const std::string &uuid) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto Hint = Cache_.find(uuid);
|
||||
if(Hint==Cache_.end())
|
||||
return false;
|
||||
return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
|
||||
}
|
||||
bool MFAServer::ResendCode(const std::string &uuid) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto Hint = Cache_.find(uuid);
|
||||
if (Hint == Cache_.end())
|
||||
return false;
|
||||
return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
|
||||
}
|
||||
|
||||
bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) {
|
||||
std::lock_guard G(Mutex_);
|
||||
bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
|
||||
SecurityObjects::UserInfoAndPolicy &UInfo) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
|
||||
return false;
|
||||
if (!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
|
||||
return false;
|
||||
|
||||
auto uuid = ChallengeResponse->get("uuid").toString();
|
||||
auto Hint = Cache_.find(uuid);
|
||||
if(Hint == end(Cache_)) {
|
||||
return false;
|
||||
}
|
||||
auto uuid = ChallengeResponse->get("uuid").toString();
|
||||
auto Hint = Cache_.find(uuid);
|
||||
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) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UInfo = Hint->second.UInfo;
|
||||
Cache_.erase(Hint);
|
||||
return true;
|
||||
}
|
||||
UInfo = Hint->second.UInfo;
|
||||
Cache_.erase(Hint);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MFAServer::MethodEnabled(const std::string &Method) {
|
||||
if(Method==MFAMETHODS::SMS)
|
||||
return SMSSender()->Enabled();
|
||||
bool MFAServer::MethodEnabled(const std::string &Method) {
|
||||
if (Method == MFAMETHODS::SMS)
|
||||
return SMSSender()->Enabled();
|
||||
|
||||
if(Method==MFAMETHODS::EMAIL)
|
||||
return SMTPMailerService()->Enabled();
|
||||
if (Method == MFAMETHODS::EMAIL)
|
||||
return SMTPMailerService()->Enabled();
|
||||
|
||||
if(Method==MFAMETHODS::AUTHENTICATOR)
|
||||
return true;
|
||||
if (Method == MFAMETHODS::AUTHENTICATOR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MFAServer::CleanCache() {
|
||||
// it is assumed that you have locked Cache_ at this point.
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
for(auto i=begin(Cache_);i!=end(Cache_);) {
|
||||
if((Now-i->second.Created)>300) {
|
||||
i = Cache_.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void MFAServer::CleanCache() {
|
||||
// it is assumed that you have locked Cache_ at this point.
|
||||
uint64_t Now = Utils::Now();
|
||||
for (auto i = begin(Cache_); i != end(Cache_);) {
|
||||
if ((Now - i->second.Created) > 300) {
|
||||
i = Cache_.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,61 +4,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "fmt/format.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();
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
} // namespace MFAMETHODS
|
||||
|
||||
struct MFACacheEntry {
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
std::string Answer;
|
||||
uint64_t Created;
|
||||
std::string Method;
|
||||
};
|
||||
struct MFACacheEntry {
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
std::string Answer;
|
||||
uint64_t Created;
|
||||
std::string Method;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, MFACacheEntry> MFAChallengeCache;
|
||||
|
||||
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;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
class MFAServer : public SubSystemServer{
|
||||
public:
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
static auto instance() {
|
||||
static auto 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 ResendCode(const std::string &uuid);
|
||||
static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||
const std::string &Method, const std::string &Challenge);
|
||||
|
||||
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 ResendCode(const std::string &uuid);
|
||||
static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
|
||||
static inline std::string MakeChallenge() {
|
||||
return fmt::format("{0:06}", MicroServiceRandom(1, 999999));
|
||||
}
|
||||
|
||||
static inline std::string MakeChallenge() {
|
||||
return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) );
|
||||
}
|
||||
private:
|
||||
MFAChallengeCache Cache_;
|
||||
MFAServer() noexcept : SubSystemServer("MFServer", "MFA-SVR", "mfa") {}
|
||||
|
||||
private:
|
||||
MFAChallengeCache Cache_;
|
||||
MFAServer() noexcept:
|
||||
SubSystemServer("MFServer", "MFA-SVR", "mfa")
|
||||
{
|
||||
}
|
||||
|
||||
void CleanCache();
|
||||
};
|
||||
|
||||
inline auto MFAServer() { return MFAServer::instance(); }
|
||||
}
|
||||
void CleanCache();
|
||||
};
|
||||
|
||||
inline auto MFAServer() { return MFAServer::instance(); }
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-07-25.
|
||||
//
|
||||
|
||||
#include "MessagingTemplates.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
} // OpenWifi
|
||||
@@ -9,67 +9,104 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class MessagingTemplates {
|
||||
public:
|
||||
static MessagingTemplates & instance() {
|
||||
static auto instance = new MessagingTemplates;
|
||||
return *instance;
|
||||
}
|
||||
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
|
||||
};
|
||||
enum EMAIL_REASON {
|
||||
FORGOT_PASSWORD = 0,
|
||||
EMAIL_VERIFICATION,
|
||||
SUB_SIGNUP_VERIFICATION,
|
||||
EMAIL_INVITATION,
|
||||
VERIFICATION_CODE,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_EMAIL_VERIFICATION,
|
||||
SUB_VERIFICATION_CODE,
|
||||
CERTIFICATE_TRANSFER_NOTIFICATION,
|
||||
CERTIFICATE_TRANSFER_AUTHORIZATION,
|
||||
CERTIFICATE_DISPUTE_SUCCESS,
|
||||
CERTIFICATE_DISPUTE_REJECTED,
|
||||
CERTIFICATE_TRANSFER_CANCELED,
|
||||
CERTIFICATE_TRANSFER_ACCEPTED,
|
||||
CERTIFICATE_TRANSFER_REJECTED
|
||||
};
|
||||
|
||||
static std::string AddOperator(const std::string & filename, const std::string &OperatorName) {
|
||||
if(OperatorName.empty())
|
||||
return "/" + filename;
|
||||
return "/" + OperatorName + "/" + filename;
|
||||
}
|
||||
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 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 SUB_SIGNUP_VERIFICATION:
|
||||
return AddOperator(EmailTemplateNames[SUB_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);
|
||||
case CERTIFICATE_TRANSFER_NOTIFICATION:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_NOTIFICATION],
|
||||
OperatorName);
|
||||
case CERTIFICATE_TRANSFER_AUTHORIZATION:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_AUTHORIZATION],
|
||||
OperatorName);
|
||||
case CERTIFICATE_DISPUTE_SUCCESS:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_DISPUTE_SUCCESS], OperatorName);
|
||||
case CERTIFICATE_DISPUTE_REJECTED:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_DISPUTE_REJECTED], OperatorName);
|
||||
case CERTIFICATE_TRANSFER_CANCELED:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_CANCELED], OperatorName);
|
||||
case CERTIFICATE_TRANSFER_ACCEPTED:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_ACCEPTED], OperatorName);
|
||||
case CERTIFICATE_TRANSFER_REJECTED:
|
||||
return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_REJECTED], OperatorName);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string Logo(const std::string &OperatorName = "" ) {
|
||||
return AddOperator("logo.jpg", OperatorName);
|
||||
}
|
||||
static std::string Logo(const std::string &OperatorName = "") {
|
||||
return AddOperator("logo.png", OperatorName);
|
||||
}
|
||||
|
||||
static std::string SubLogo(const std::string &OperatorName = "" ) {
|
||||
return AddOperator("sub_logo.jpg", OperatorName);
|
||||
}
|
||||
static std::string SubLogo(const std::string &OperatorName = "") {
|
||||
return AddOperator("sub_logo.png", 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"
|
||||
};
|
||||
};
|
||||
private:
|
||||
inline const static std::vector<std::string> EmailTemplateNames = {
|
||||
"password_reset",
|
||||
"email_verification",
|
||||
"sub_signup_verification",
|
||||
"email_invitation",
|
||||
"verification_code",
|
||||
"sub_password_reset",
|
||||
"sub_email_verification",
|
||||
"sub_verification_code",
|
||||
"certificate_transfer_notification",
|
||||
"certificate_transfer_authorization",
|
||||
"certificate_dispute_success",
|
||||
"certificate_dispute_rejected",
|
||||
"certificate_transfer_canceled",
|
||||
"certificate_transfer_accepted",
|
||||
"certificate_transfer_rejected"};
|
||||
};
|
||||
|
||||
inline MessagingTemplates & MessagingTemplates() { return MessagingTemplates::instance(); }
|
||||
|
||||
} // OpenWifi
|
||||
inline MessagingTemplates &MessagingTemplates() { return MessagingTemplates::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -7,281 +7,350 @@
|
||||
|
||||
#include "RESTAPI_action_links.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenAPIRequests.h"
|
||||
#include "framework/RESTAPI_PartHandler.h"
|
||||
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_action_links::DoGet() {
|
||||
#if defined(TIP_CERT_SERVICE)
|
||||
bool ProcessExternalActionLinks(RESTAPIHandler &handler, const std::string &Id,
|
||||
const std::string &Action);
|
||||
#endif
|
||||
|
||||
auto Action = GetParameter("action","");
|
||||
auto Id = GetParameter("id","");
|
||||
void RESTAPI_action_links::DoGet() {
|
||||
|
||||
SecurityObjects::ActionLink Link;
|
||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
|
||||
return DoReturnA404();
|
||||
auto Action = GetParameter("action", "");
|
||||
auto Id = GetParameter("id", "");
|
||||
|
||||
if(Action=="password_reset")
|
||||
return RequestResetPassword(Link);
|
||||
else if(Action=="sub_password_reset")
|
||||
return RequestSubResetPassword(Link);
|
||||
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);
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
#if defined(TIP_CERT_SERVICE)
|
||||
if (!OpenWifi::ProcessExternalActionLinks(*this, Id, Action)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
void RESTAPI_action_links::DoPost() {
|
||||
auto Action = GetParameter("action","");
|
||||
SecurityObjects::ActionLink Link;
|
||||
if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link))
|
||||
return DoReturnA404();
|
||||
|
||||
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();
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
if (Action == "password_reset")
|
||||
return RequestResetPassword(Link);
|
||||
else if (Action == "sub_password_reset")
|
||||
return RequestResetPassword(Link);
|
||||
else if (Action == "email_verification")
|
||||
return DoEmailVerification(Link);
|
||||
else if (Action == "sub_email_verification")
|
||||
return DoEmailVerification(Link);
|
||||
else if (Action == "signup_verification")
|
||||
return DoNewSubVerification(Link);
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
|
||||
Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId));
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Link.id},
|
||||
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
|
||||
SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
void RESTAPI_action_links::DoPost() {
|
||||
auto Action = GetParameter("action", "");
|
||||
|
||||
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);
|
||||
}
|
||||
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();
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::CompleteResetPassword() {
|
||||
// form has been posted...
|
||||
RESTAPI_PartHandler PartHandler;
|
||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||
if (!Form.empty()) {
|
||||
void RESTAPI_action_links::AddGlobalVars(Types::StringPairVec &Vars) {
|
||||
Vars.push_back(std::make_pair("USER_HELPER_EMAIL", AuthService()->HelperEmail()));
|
||||
Vars.push_back(std::make_pair("SUB_HELPER_EMAIL", AuthService()->SubHelperEmail()));
|
||||
Vars.push_back(
|
||||
std::make_pair("GLOBAL_USER_HELPER_EMAIL", AuthService()->GlobalHelperEmail()));
|
||||
Vars.push_back(
|
||||
std::make_pair("GLOBAL_SUB_HELPER_EMAIL", AuthService()->GlobalSubHelperEmail()));
|
||||
Vars.push_back(std::make_pair("USER_HELPER_SITE", AuthService()->HelperSite()));
|
||||
Vars.push_back(std::make_pair("SUB_HELPER_SITE", AuthService()->SubHelperSite()));
|
||||
Vars.push_back(std::make_pair("USER_SYSTEM_LOGIN", AuthService()->SystemLoginSite()));
|
||||
Vars.push_back(std::make_pair("SUB_SYSTEM_LOGIN", AuthService()->SubSystemLoginSite()));
|
||||
Vars.push_back(std::make_pair("USER_SIGNATURE", AuthService()->UserSignature()));
|
||||
Vars.push_back(std::make_pair("SUB_SIGNATURE", AuthService()->SubSignature()));
|
||||
}
|
||||
|
||||
auto Password1 = Form.get("password1","bla");
|
||||
auto Password2 = Form.get("password2","blu");
|
||||
auto Id = Form.get("id","");
|
||||
auto now = OpenWifi::Now();
|
||||
void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
|
||||
Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}",
|
||||
Request->clientAddress().toString(), Link.userId));
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset.html"};
|
||||
Types::StringPairVec FormVars{
|
||||
{"UUID", Link.id},
|
||||
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
|
||||
AddGlobalVars(FormVars);
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
SecurityObjects::ActionLink Link;
|
||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
|
||||
return DoReturnA404();
|
||||
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() + "/sub_signup_verification.html"};
|
||||
Types::StringPairVec FormVars{
|
||||
{"UUID", Link.id},
|
||||
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
|
||||
AddGlobalVars(FormVars);
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
if(now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
void RESTAPI_action_links::CompleteResetPassword() {
|
||||
RESTAPI_PartHandler PartHandler;
|
||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||
if (!Form.empty()) {
|
||||
|
||||
if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(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);
|
||||
}
|
||||
auto Password1 = Form.get("password1", "bla");
|
||||
auto Password2 = Form.get("password2", "blu");
|
||||
auto Id = Form.get("id", "");
|
||||
auto now = OpenWifi::Now();
|
||||
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
SecurityObjects::ActionLink Link;
|
||||
if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link))
|
||||
return DoReturnA404();
|
||||
|
||||
bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
|
||||
if(!Found) {
|
||||
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."}};
|
||||
return SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
if (now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
if(UInfo.blackListed || UInfo.suspended) {
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_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);
|
||||
}
|
||||
if (Password1 != Password2 || !AuthService()->ValidatePassword(Password2) ||
|
||||
!AuthService()->ValidatePassword(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 + ")"}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo);
|
||||
if(!GoodPassword) {
|
||||
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);
|
||||
}
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
UInfo.modified = OpenWifi::Now();
|
||||
if(Link.userAction)
|
||||
StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
|
||||
else
|
||||
StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
|
||||
bool Found = Link.userAction
|
||||
? StorageService()->UserDB().GetUserById(Link.userId, UInfo)
|
||||
: StorageService()->SubDB().GetUserById(Link.userId, UInfo);
|
||||
if (!Found) {
|
||||
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."}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
if (UInfo.blackListed || UInfo.suspended) {
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_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."}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::CompleteSubVerification() {
|
||||
RESTAPI_PartHandler PartHandler;
|
||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||
bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1, UInfo)
|
||||
: AuthService()->SetSubPassword(Password1, UInfo);
|
||||
if (!GoodPassword) {
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
|
||||
Types::StringPairVec FormVars{
|
||||
{"UUID", Id}, {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
if (!Form.empty()) {
|
||||
auto Password1 = Form.get("password1","bla");
|
||||
auto Password2 = Form.get("password2","blu");
|
||||
auto Id = Form.get("id","");
|
||||
auto now = 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);
|
||||
|
||||
SecurityObjects::ActionLink Link;
|
||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) {
|
||||
return DoReturnA404();
|
||||
}
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_success.html"};
|
||||
Types::StringPairVec FormVars{{"UUID", Id},
|
||||
{"USERNAME", UInfo.email},
|
||||
{"ACTION_LINK", MicroService::instance().GetUIURI()}};
|
||||
AddGlobalVars(FormVars);
|
||||
StorageService()->ActionLinksDB().CompleteAction(Id);
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
} else {
|
||||
DoReturnA404();
|
||||
}
|
||||
}
|
||||
|
||||
if(now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
void RESTAPI_action_links::CompleteSubVerification() {
|
||||
RESTAPI_PartHandler PartHandler;
|
||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||
|
||||
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);
|
||||
}
|
||||
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::UserInfo UInfo;
|
||||
bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo);
|
||||
if(!Found) {
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
|
||||
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);
|
||||
}
|
||||
SecurityObjects::ActionLink Link;
|
||||
if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link)) {
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (Password1 != Password2 || !AuthService()->ValidateSubPassword(Password1)) {
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/sub_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 + ")"}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
UInfo.modified = OpenWifi::Now();
|
||||
UInfo.changePassword = false;
|
||||
UInfo.lastEmailCheck = OpenWifi::Now();
|
||||
UInfo.waitingForEmailCheck = false;
|
||||
UInfo.validated = OpenWifi::Now();
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
bool Found = StorageService()->SubDB().GetUserById(Link.userId, UInfo);
|
||||
if (!Found) {
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
|
||||
Types::StringPairVec FormVars{
|
||||
{"UUID", Id},
|
||||
{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact "
|
||||
"your system administrator."}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
|
||||
if (UInfo.blackListed || UInfo.suspended) {
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/sub_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."}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
||||
{"USERNAME", UInfo.email} };
|
||||
StorageService()->ActionLinksDB().CompleteAction(Id);
|
||||
bool GoodPassword = AuthService()->SetSubPassword(Password1, UInfo);
|
||||
if (!GoodPassword) {
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
|
||||
Types::StringPairVec FormVars{
|
||||
{"UUID", Id}, {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
UInfo.modified = OpenWifi::Now();
|
||||
UInfo.changePassword = false;
|
||||
UInfo.lastEmailCheck = OpenWifi::Now();
|
||||
UInfo.waitingForEmailCheck = false;
|
||||
UInfo.validated = OpenWifi::Now();
|
||||
|
||||
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
|
||||
auto now = OpenWifi::Now();
|
||||
StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
|
||||
|
||||
if(now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Link.id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_success.html"};
|
||||
Types::StringPairVec FormVars{{"UUID", Id}, {"USERNAME", UInfo.email}};
|
||||
StorageService()->ActionLinksDB().CompleteAction(Id);
|
||||
|
||||
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);
|
||||
}
|
||||
// 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));
|
||||
AddGlobalVars(FormVars);
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
Logger().information(fmt::format(
|
||||
"({}): Completed subscriber e-mail verification. FORM notified.", UInfo.email));
|
||||
} else {
|
||||
DoReturnA404();
|
||||
}
|
||||
}
|
||||
|
||||
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},
|
||||
{"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);
|
||||
}
|
||||
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
|
||||
auto now = OpenWifi::Now();
|
||||
|
||||
void RESTAPI_action_links::DoReturnA404() {
|
||||
Types::StringPairVec FormVars;
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/404_error.html"};
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
if (now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Link.id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::CompleteEmailInvitation() {
|
||||
/// TODO:
|
||||
}
|
||||
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"};
|
||||
AddGlobalVars(FormVars);
|
||||
return SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) {
|
||||
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},
|
||||
{"USERNAME", UInfo.email},
|
||||
{"ACTION_LINK", MicroService::instance().GetUIURI()}};
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"};
|
||||
AddGlobalVars(FormVars);
|
||||
StorageService()->ActionLinksDB().CompleteAction(Link.id);
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
}
|
||||
void RESTAPI_action_links::DoReturnA404() {
|
||||
Types::StringPairVec FormVars;
|
||||
Poco::File FormFile{Daemon()->AssetDir() + "/404_error.html"};
|
||||
AddGlobalVars(FormVars);
|
||||
SendHTMLFileBack(FormFile, FormVars);
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) {
|
||||
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) {}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -4,36 +4,35 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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)
|
||||
: 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);
|
||||
void DoReturnA404();
|
||||
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
|
||||
void CompleteEmailInvitation();
|
||||
class RESTAPI_action_links : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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_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);
|
||||
void DoReturnA404();
|
||||
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
|
||||
void CompleteEmailInvitation();
|
||||
static void AddGlobalVars(Types::StringPairVec &Vars);
|
||||
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final{};
|
||||
void DoPut() final{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
165
src/RESTAPI/RESTAPI_apiKey_handler.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-11-04.
|
||||
//
|
||||
|
||||
#include "RESTAPI_apiKey_handler.h"
|
||||
#include "RESTAPI/RESTAPI_db_helpers.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_apiKey_handler::DoGet() {
|
||||
std::string user_uuid = GetBinding("uuid", "");
|
||||
if (user_uuid.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
if (user_uuid != UserInfo_.userinfo.id &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
SecurityObjects::ApiKeyEntryList List;
|
||||
if (DB_.GetRecords(0, 500, List.apiKeys, fmt::format(" userUuid='{}' ", user_uuid))) {
|
||||
for (auto &key : List.apiKeys) {
|
||||
Sanitize(UserInfo_, key);
|
||||
}
|
||||
Poco::JSON::Object Answer;
|
||||
List.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_apiKey_handler::DoDelete() {
|
||||
std::string user_uuid = GetBinding("uuid", "");
|
||||
if (user_uuid.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
if (user_uuid != UserInfo_.userinfo.id &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if (user_uuid != UserInfo_.userinfo.id) {
|
||||
if (!StorageService()->UserDB().Exists("id", user_uuid)) {
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
std::string ApiKeyId = GetParameter("keyUuid", "");
|
||||
if (ApiKeyId.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
SecurityObjects::ApiKeyEntry ApiKey;
|
||||
if (StorageService()->ApiKeyDB().GetRecord("id", ApiKeyId, ApiKey)) {
|
||||
if (ApiKey.userUuid == user_uuid) {
|
||||
AuthService()->RemoveTokenSystemWide(ApiKey.apiKey);
|
||||
DB_.DeleteRecord("id", ApiKeyId);
|
||||
return OK();
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_apiKey_handler::DoPost() {
|
||||
std::string user_uuid = GetBinding("uuid", "");
|
||||
|
||||
if (user_uuid.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
if (user_uuid != UserInfo_.userinfo.id &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if (user_uuid != UserInfo_.userinfo.id) {
|
||||
// Must verify if the user exists
|
||||
if (!StorageService()->UserDB().Exists("id", user_uuid)) {
|
||||
return BadRequest(RESTAPI::Errors::UserMustExist);
|
||||
}
|
||||
}
|
||||
|
||||
SecurityObjects::ApiKeyEntry NewKey;
|
||||
if (!NewKey.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
NewKey.lastUse = 0;
|
||||
|
||||
if (!Utils::IsAlphaNumeric(NewKey.name) || NewKey.name.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
Poco::toLowerInPlace(NewKey.name);
|
||||
NewKey.userUuid = user_uuid;
|
||||
if (NewKey.expiresOn < Utils::Now()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
// does a key of that name already exit for this user?
|
||||
SecurityObjects::ApiKeyEntryList ExistingList;
|
||||
if (DB_.GetRecords(0, 500, ExistingList.apiKeys,
|
||||
fmt::format(" userUuid='{}' ", user_uuid))) {
|
||||
if (std::find_if(ExistingList.apiKeys.begin(), ExistingList.apiKeys.end(),
|
||||
[NewKey](const SecurityObjects::ApiKeyEntry &E) -> bool {
|
||||
return E.name == NewKey.name;
|
||||
}) != ExistingList.apiKeys.end()) {
|
||||
return BadRequest(RESTAPI::Errors::ApiKeyNameAlreadyExists);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExistingList.apiKeys.size() >= 10) {
|
||||
return BadRequest(RESTAPI::Errors::TooManyApiKeys);
|
||||
}
|
||||
|
||||
NewKey.id = MicroServiceCreateUUID();
|
||||
NewKey.userUuid = user_uuid;
|
||||
NewKey.salt = std::to_string(Utils::Now());
|
||||
NewKey.apiKey = Utils::ComputeHash(NewKey.salt, UserInfo_.userinfo.id,
|
||||
UserInfo_.webtoken.access_token_);
|
||||
NewKey.created = Utils::Now();
|
||||
|
||||
if (DB_.CreateRecord(NewKey)) {
|
||||
Poco::JSON::Object Answer;
|
||||
NewKey.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::RecordNotCreated);
|
||||
}
|
||||
|
||||
void RESTAPI_apiKey_handler::DoPut() {
|
||||
std::string user_uuid = GetBinding("uuid", "");
|
||||
if (user_uuid.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
if (user_uuid != UserInfo_.userinfo.id &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
SecurityObjects::ApiKeyEntry NewKey;
|
||||
if (!NewKey.from_json(ParsedBody_)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
SecurityObjects::ApiKeyEntry ExistingKey;
|
||||
if (!DB_.GetRecord("id", NewKey.id, ExistingKey)) {
|
||||
return BadRequest(RESTAPI::Errors::ApiKeyDoesNotExist);
|
||||
}
|
||||
|
||||
if (ExistingKey.userUuid != user_uuid) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||
}
|
||||
|
||||
AssignIfPresent(ParsedBody_, "description", ExistingKey.description);
|
||||
|
||||
if (DB_.UpdateRecord("id", ExistingKey.id, ExistingKey)) {
|
||||
Poco::JSON::Object Answer;
|
||||
ExistingKey.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::RecordNotUpdated);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
32
src/RESTAPI/RESTAPI_apiKey_handler.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-11-04.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StorageService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_apiKey_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_apiKey_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, TransactionId, Internal) {}
|
||||
static auto PathName() { return std::list<std::string>{"/api/v1/apiKey/{uuid}"}; };
|
||||
|
||||
private:
|
||||
ApiKeyDB &DB_ = StorageService()->ApiKeyDB();
|
||||
|
||||
void DoGet() final;
|
||||
void DoPut() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
@@ -3,23 +3,23 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_asset_server.h"
|
||||
#include "Daemon.h"
|
||||
#include "Poco/File.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_asset_server::DoGet() {
|
||||
Poco::File AssetFile;
|
||||
void RESTAPI_asset_server::DoGet() {
|
||||
Poco::File AssetFile;
|
||||
|
||||
if(Request->getURI().find("/favicon.ico") != std::string::npos) {
|
||||
AssetFile = Daemon()->AssetDir() + "/favicon.ico";
|
||||
} else {
|
||||
std::string AssetName = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
AssetFile = Daemon()->AssetDir() + "/" + AssetName;
|
||||
}
|
||||
if(!AssetFile.isFile()) {
|
||||
return NotFound();
|
||||
}
|
||||
SendFile(AssetFile);
|
||||
}
|
||||
}
|
||||
if (Request->getURI().find("/favicon.ico") != std::string::npos) {
|
||||
AssetFile = Daemon()->AssetDir() + "/favicon.ico";
|
||||
} else {
|
||||
std::string AssetName = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
AssetFile = Daemon()->AssetDir() + "/" + AssetName;
|
||||
}
|
||||
if (!AssetFile.isFile()) {
|
||||
return NotFound();
|
||||
}
|
||||
SendFile(AssetFile);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,31 +4,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_asset_server : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_asset_server(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, false) {}
|
||||
static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" ,
|
||||
"/favicon.ico"}; };
|
||||
void DoGet() final;
|
||||
void DoPost() final {};
|
||||
void DoDelete() final {};
|
||||
void DoPut() final {};
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
class RESTAPI_asset_server : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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, false) {}
|
||||
static auto PathName() {
|
||||
return std::list<std::string>{"/wwwassets/{id}", "/favicon.ico"};
|
||||
};
|
||||
void DoGet() final;
|
||||
void DoPost() final{};
|
||||
void DoDelete() final{};
|
||||
void DoPut() final{};
|
||||
|
||||
private:
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -5,78 +5,85 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "Poco/CountingStream.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "RESTAPI_avatar_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void AvatarPartHandler::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 AvatarPartHandler::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_avatar_handler::DoPost() {
|
||||
std::string Id = UserInfo_.userinfo.id;
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
void RESTAPI_avatar_handler::DoPost() {
|
||||
std::string Id = UserInfo_.userinfo.id;
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
std::stringstream SS;
|
||||
AvatarPartHandler partHandler(Id, Logger_, SS);
|
||||
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
|
||||
Poco::JSON::Object Answer;
|
||||
std::stringstream SS;
|
||||
AvatarPartHandler 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()->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));
|
||||
} 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);
|
||||
}
|
||||
if (!partHandler.Name().empty() &&
|
||||
partHandler.Length() < MicroServiceConfigGetInt("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));
|
||||
} 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_avatar_handler::DoGet() {
|
||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
if (Id.empty()) {
|
||||
return NotFound();
|
||||
}
|
||||
void RESTAPI_avatar_handler::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)) {
|
||||
return NotFound();
|
||||
}
|
||||
Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size()));
|
||||
return SendFileContent(AvatarContent, Type, Name);
|
||||
}
|
||||
std::string Type, Name, AvatarContent;
|
||||
if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent,
|
||||
Type, Name)) {
|
||||
return NotFound();
|
||||
}
|
||||
Logger().information(fmt::format("Retrieving avatar for {}, size:{}",
|
||||
UserInfo_.userinfo.email, AvatarContent.size()));
|
||||
return SendFileContent(AvatarContent, Type, Name);
|
||||
}
|
||||
|
||||
void RESTAPI_avatar_handler::DoDelete() {
|
||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
void RESTAPI_avatar_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 (UserInfo_.userinfo.userRole != SecurityObjects::ROOT && Id != UserInfo_.userinfo.id) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
|
||||
return NotFound();
|
||||
}
|
||||
if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
|
||||
StorageService()->UserDB().SetAvatar(Id,"");
|
||||
OK();
|
||||
}
|
||||
}
|
||||
Logger().information(fmt::format("Deleted avatar for {}", UserInfo_.userinfo.email));
|
||||
StorageService()->UserDB().SetAvatar(Id, "");
|
||||
OK();
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -3,51 +3,47 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/Net/PartHandler.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AvatarPartHandler : public Poco::Net::PartHandler {
|
||||
public:
|
||||
AvatarPartHandler(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_; }
|
||||
class AvatarPartHandler : public Poco::Net::PartHandler {
|
||||
public:
|
||||
AvatarPartHandler(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_;
|
||||
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_; };
|
||||
};
|
||||
inline Poco::Logger &Logger() { return Logger_; };
|
||||
};
|
||||
|
||||
class RESTAPI_avatar_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_avatar_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/avatar/{id}"}; };
|
||||
class RESTAPI_avatar_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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/avatar/{id}"}; };
|
||||
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
void DoPut() final {};
|
||||
|
||||
};
|
||||
}
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
void DoPut() final{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -8,10 +8,15 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) {
|
||||
U.currentPassword.clear();
|
||||
U.lastPasswords.clear();
|
||||
U.oauthType.clear();
|
||||
}
|
||||
inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
|
||||
SecurityObjects::UserInfo &U) {
|
||||
U.currentPassword.clear();
|
||||
U.lastPasswords.clear();
|
||||
U.oauthType.clear();
|
||||
}
|
||||
|
||||
}
|
||||
inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
|
||||
SecurityObjects::ApiKeyEntry &U) {
|
||||
U.salt.clear();
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -3,36 +3,29 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_email_handler.h"
|
||||
|
||||
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "SMTPMailerService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_email_handler::DoPost() {
|
||||
const auto & Obj = ParsedBody_;
|
||||
if (Obj->has("subject") &&
|
||||
Obj->has("from") &&
|
||||
Obj->has("text") &&
|
||||
Obj->has("recipients") &&
|
||||
Obj->isArray("recipients")) {
|
||||
void RESTAPI_email_handler::DoPost() {
|
||||
const auto &Obj = ParsedBody_;
|
||||
if (Obj->has("subject") && Obj->has("from") && Obj->has("text") && Obj->has("recipients") &&
|
||||
Obj->isArray("recipients")) {
|
||||
|
||||
Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
|
||||
auto Recipient = Recipients->get(0).toString();
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = Recipient;
|
||||
Attrs[SUBJECT] = Obj->get("subject").toString();
|
||||
Attrs[TEXT] = Obj->get("text").toString();
|
||||
Attrs[SENDER] = Obj->get("from").toString();
|
||||
if(SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs)) {
|
||||
return OK();
|
||||
}
|
||||
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
}
|
||||
Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
|
||||
auto Recipient = Recipients->get(0).toString();
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = Recipient;
|
||||
Attrs[SUBJECT] = Obj->get("subject").toString();
|
||||
Attrs[TEXT] = Obj->get("text").toString();
|
||||
Attrs[SENDER] = Obj->get("from").toString();
|
||||
if (SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs, false)) {
|
||||
return OK();
|
||||
}
|
||||
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,22 +4,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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)
|
||||
: 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"};}
|
||||
void DoGet() final {};
|
||||
void DoPost() final;
|
||||
void DoDelete() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
class RESTAPI_email_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||
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"}; }
|
||||
void DoGet() final{};
|
||||
void DoPost() final;
|
||||
void DoDelete() final{};
|
||||
void DoPut() final{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -9,170 +9,176 @@
|
||||
#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"
|
||||
#include "RESTAPI_oauth2_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ow_constants.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::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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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");
|
||||
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);
|
||||
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 (!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::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;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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::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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
bool Expired = false;
|
||||
auto Code = AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
|
||||
switch (Code) {
|
||||
case 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);
|
||||
}
|
||||
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);
|
||||
case ACCOUNT_SUSPENDED:
|
||||
return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
|
||||
default:
|
||||
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -7,26 +7,27 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_oauth2_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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_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"}; };
|
||||
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"};
|
||||
};
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
void DoPut() final {};
|
||||
void DoPut() final{};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -7,30 +7,30 @@
|
||||
|
||||
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::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() {
|
||||
void RESTAPI_preferences::DoPut() {
|
||||
|
||||
SecurityObjects::Preferences P;
|
||||
SecurityObjects::Preferences P;
|
||||
|
||||
const auto & RawObject = ParsedBody_;
|
||||
if(!P.from_json(RawObject)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
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);
|
||||
P.id = UserInfo_.userinfo.id;
|
||||
P.modified = OpenWifi::Now();
|
||||
StorageService()->PreferencesDB().SetPreferences(P);
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
P.to_json(Answer);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
Poco::JSON::Object Answer;
|
||||
P.to_json(Answer);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,24 +4,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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 {};
|
||||
};
|
||||
}
|
||||
class RESTAPI_preferences : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -1,88 +1,67 @@
|
||||
//
|
||||
//
|
||||
// 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_apiKey_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_oauth2_handler.h"
|
||||
#include "RESTAPI/RESTAPI_preferences.h"
|
||||
#include "RESTAPI/RESTAPI_subpreferences.h"
|
||||
#include "RESTAPI/RESTAPI_signup_handler.h"
|
||||
#include "RESTAPI/RESTAPI_sms_handler.h"
|
||||
#include "RESTAPI/RESTAPI_subavatar_handler.h"
|
||||
#include "RESTAPI/RESTAPI_submfa_handler.h"
|
||||
#include "RESTAPI/RESTAPI_suboauth2_handler.h"
|
||||
#include "RESTAPI/RESTAPI_subpreferences.h"
|
||||
#include "RESTAPI/RESTAPI_subtotp_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_system_endpoints_handler.h"
|
||||
#include "RESTAPI/RESTAPI_totp_handler.h"
|
||||
#include "RESTAPI/RESTAPI_subtotp_handler.h"
|
||||
#include "RESTAPI/RESTAPI_signup_handler.h"
|
||||
#include "RESTAPI/RESTAPI_user_handler.h"
|
||||
#include "RESTAPI/RESTAPI_users_handler.h"
|
||||
#include "RESTAPI/RESTAPI_validate_apikey.h"
|
||||
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
|
||||
#include "RESTAPI/RESTAPI_validate_token_handler.h"
|
||||
|
||||
#include "RESTAPI_systemSecret_handler.h"
|
||||
#include "framework/RESTAPI_SystemCommand.h"
|
||||
#include "framework/RESTAPI_WebSocketServer.h"
|
||||
#include "framework/RESTAPI_SystemConfiguration.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_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
|
||||
RESTAPI_system_command, RESTAPI_system_configuration, 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, RESTAPI_validate_apikey, RESTAPI_webSocketServer,
|
||||
RESTAPI_apiKey_handler, RESTAPI_systemSecret_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) {
|
||||
Poco::Net::HTTPRequestHandler *
|
||||
RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger &L, RESTAPI_GenericServerAccounting &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);
|
||||
}
|
||||
}
|
||||
return RESTAPI_Router_I<
|
||||
RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
|
||||
RESTAPI_system_command, RESTAPI_system_configuration, 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_validate_apikey, RESTAPI_signup_handler, RESTAPI_systemSecret_handler>(
|
||||
Path, Bindings, L, S, TransactionId);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -3,72 +3,74 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_signup_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroServiceFuncs.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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
if (Existing.waitingForEmailCheck) {
|
||||
return BadRequest(RESTAPI::Errors::SignupEmailCheck);
|
||||
}
|
||||
|
||||
return BadRequest(RESTAPI::Errors::SignupWaitingForDevice);
|
||||
}
|
||||
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;
|
||||
SecurityObjects::UserInfo NewSub;
|
||||
NewSub.signingUp = operatorName + ":" + signupUUID;
|
||||
NewSub.waitingForEmailCheck = true;
|
||||
NewSub.name = UserName;
|
||||
NewSub.modified = OpenWifi::Now();
|
||||
NewSub.creationDate = OpenWifi::Now();
|
||||
NewSub.id = MicroServiceCreateUUID();
|
||||
NewSub.email = UserName;
|
||||
NewSub.userRole = SecurityObjects::SUBSCRIBER;
|
||||
NewSub.changePassword = true;
|
||||
NewSub.owner = owner;
|
||||
|
||||
StorageService()->SubDB().CreateRecord(NewSub);
|
||||
StorageService()->SubDB().CreateRecord(NewSub);
|
||||
|
||||
Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName));
|
||||
SecurityObjects::ActionLink NewLink;
|
||||
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);
|
||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
|
||||
NewLink.id = MicroServiceCreateUUID();
|
||||
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);
|
||||
}
|
||||
Poco::JSON::Object Answer;
|
||||
NewSub.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
void RESTAPI_signup_handler::DoPut() {
|
||||
// TODO
|
||||
}
|
||||
void RESTAPI_signup_handler::DoPut() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,36 +4,35 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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 ){}
|
||||
class RESTAPI_signup_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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"}; };
|
||||
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:
|
||||
/* 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:
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -5,55 +5,53 @@
|
||||
#include "RESTAPI_sms_handler.h"
|
||||
#include "SMSSender.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void OpenWifi::RESTAPI_sms_handler::DoPost() {
|
||||
const auto &Obj = ParsedBody_;
|
||||
void OpenWifi::RESTAPI_sms_handler::DoPost() {
|
||||
const auto &Obj = ParsedBody_;
|
||||
|
||||
if(!SMSSender()->Enabled()) {
|
||||
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
||||
}
|
||||
if (!SMSSender()->Enabled()) {
|
||||
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
||||
}
|
||||
|
||||
std::string Arg;
|
||||
if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) {
|
||||
auto Number = Obj->get("to").toString();
|
||||
if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
|
||||
return OK();
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
||||
}
|
||||
std::string Arg;
|
||||
if (HasParameter("validateNumber", Arg) && Arg == "true" && Obj->has("to")) {
|
||||
auto Number = Obj->get("to").toString();
|
||||
if (SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
|
||||
return OK();
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
||||
}
|
||||
|
||||
std::string Code;
|
||||
if( HasParameter("completeValidation",Arg) &&
|
||||
Arg=="true" &&
|
||||
HasParameter("validationCode", Code) &&
|
||||
Obj->has("to")) {
|
||||
auto Number = Obj->get("to").toString();
|
||||
if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
|
||||
return OK();
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
|
||||
}
|
||||
std::string Code;
|
||||
if (HasParameter("completeValidation", Arg) && Arg == "true" &&
|
||||
HasParameter("validationCode", Code) && Obj->has("to")) {
|
||||
auto Number = Obj->get("to").toString();
|
||||
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);
|
||||
}
|
||||
if(Internal_) {
|
||||
poco_information(Logger(),fmt::format("Internal SMS request: TID={}", TransactionId_));
|
||||
} else if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::PARTNER &&
|
||||
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if (Obj->has("to") &&
|
||||
Obj->has("text")) {
|
||||
if (Obj->has("to") && Obj->has("text")) {
|
||||
|
||||
std::string PhoneNumber = Obj->get("to").toString();
|
||||
std::string Text = Obj->get("text").toString();
|
||||
if(SMSSender()->Send(PhoneNumber, Text))
|
||||
return OK();
|
||||
std::string PhoneNumber = Obj->get("to").toString();
|
||||
std::string Text = Obj->get("text").toString();
|
||||
if (SMSSender()->Send(PhoneNumber, Text))
|
||||
return OK();
|
||||
|
||||
return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,22 +4,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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)
|
||||
: 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"};}
|
||||
void DoGet() final {};
|
||||
void DoPost() final;
|
||||
void DoDelete() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
class RESTAPI_sms_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||
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"}; }
|
||||
void DoGet() final{};
|
||||
void DoPost() final;
|
||||
void DoDelete() final{};
|
||||
void DoPut() final{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -5,77 +5,84 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "Poco/CountingStream.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "RESTAPI_subavatar_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/MicroServiceFuncs.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 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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
if (!partHandler.Name().empty() &&
|
||||
partHandler.Length() < MicroServiceConfigGetInt("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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
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, "");
|
||||
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 (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();
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -3,51 +3,47 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/Net/PartHandler.h"
|
||||
#include "framework/RESTAPI_Handler.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_; }
|
||||
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_;
|
||||
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_; }
|
||||
};
|
||||
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}"}; };
|
||||
class RESTAPI_subavatar_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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 {};
|
||||
|
||||
};
|
||||
}
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
void DoPut() final{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -3,135 +3,140 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_submfa_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "SMSSender.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_submfa_handler::DoGet() {
|
||||
SecurityObjects::UserInfo User;
|
||||
void RESTAPI_submfa_handler::DoGet() {
|
||||
SecurityObjects::UserInfo User;
|
||||
|
||||
if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) {
|
||||
Poco::JSON::Object Answer;
|
||||
SecurityObjects::SubMfaConfig MFC;
|
||||
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();
|
||||
}
|
||||
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() {
|
||||
void RESTAPI_submfa_handler::DoPut() {
|
||||
|
||||
try {
|
||||
const auto & Body = ParsedBody_;
|
||||
try {
|
||||
const auto &Body = ParsedBody_;
|
||||
|
||||
SecurityObjects::SubMfaConfig MFC;
|
||||
SecurityObjects::SubMfaConfig MFC;
|
||||
|
||||
if (!MFC.from_json(Body)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
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);
|
||||
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;
|
||||
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);
|
||||
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();
|
||||
MFC.sms = MFC.sms;
|
||||
MFC.type = "email";
|
||||
MFC.email = UserInfo_.userinfo.email;
|
||||
MFC.id = MicroServiceCreateUUID();
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
MFC.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
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);
|
||||
}
|
||||
} 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()->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()->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);
|
||||
}
|
||||
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;
|
||||
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().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);
|
||||
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();
|
||||
MFC.sms = MFC.sms;
|
||||
MFC.type = "sms";
|
||||
MFC.email = UserInfo_.userinfo.email;
|
||||
MFC.id = MicroServiceCreateUUID();
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
MFC.to_json(Answer);
|
||||
Poco::JSON::Object Answer;
|
||||
MFC.to_json(Answer);
|
||||
|
||||
return ReturnObject(Answer);
|
||||
return ReturnObject(Answer);
|
||||
|
||||
} else {
|
||||
return InternalError(RESTAPI::Errors::SMSTryLater);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
} else {
|
||||
return InternalError(RESTAPI::Errors::SMSTryLater);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -4,24 +4,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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 ;
|
||||
};
|
||||
}
|
||||
class RESTAPI_submfa_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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;
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -5,161 +5,167 @@
|
||||
#include "RESTAPI_suboauth2_handler.h"
|
||||
#include "AuthService.h"
|
||||
#include "MFAServer.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI/RESTAPI_db_helpers.h"
|
||||
#include "StorageService.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::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::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");
|
||||
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);
|
||||
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 (!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::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;
|
||||
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);
|
||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
|
||||
NewLink.id = MicroServiceCreateUUID();
|
||||
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);
|
||||
}
|
||||
}
|
||||
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::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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
bool Expired = false;
|
||||
auto Code = AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
|
||||
switch (Code) {
|
||||
case 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);
|
||||
}
|
||||
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);
|
||||
case ACCOUNT_SUSPENDED:
|
||||
return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
|
||||
default:
|
||||
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
||||
}
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -3,25 +3,27 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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 {};
|
||||
};
|
||||
}
|
||||
class RESTAPI_suboauth2_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -7,30 +7,30 @@
|
||||
|
||||
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::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() {
|
||||
void RESTAPI_subpreferences::DoPut() {
|
||||
|
||||
SecurityObjects::Preferences P;
|
||||
SecurityObjects::Preferences P;
|
||||
|
||||
const auto & RawObject = ParsedBody_;
|
||||
if(!P.from_json(RawObject)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
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);
|
||||
P.id = UserInfo_.userinfo.id;
|
||||
P.modified = OpenWifi::Now();
|
||||
StorageService()->SubPreferencesDB().SetPreferences(P);
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
P.to_json(Answer);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
Poco::JSON::Object Answer;
|
||||
P.to_json(Answer);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,24 +4,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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 {};
|
||||
};
|
||||
}
|
||||
class RESTAPI_subpreferences : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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{};
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -5,33 +5,35 @@
|
||||
#include "RESTAPI_subtotp_handler.h"
|
||||
|
||||
#include "TotpCache.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_subtotp_handler::DoGet() {
|
||||
void RESTAPI_subtotp_handler::DoGet() {
|
||||
|
||||
auto Reset = GetBoolParameter("reset",false);
|
||||
std::string QRCode;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -2,28 +2,25 @@
|
||||
// Created by stephane bourque on 2022-01-31.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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:
|
||||
class RESTAPI_subtotp_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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:
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -3,314 +3,338 @@
|
||||
//
|
||||
|
||||
#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 "RESTAPI/RESTAPI_db_helpers.h"
|
||||
#include "SMSSender.h"
|
||||
#include "SMTPMailerService.h"
|
||||
#include "StorageService.h"
|
||||
#include "TotpCache.h"
|
||||
#include "framework/ow_constants.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_subuser_handler::DoGet() {
|
||||
std::string Id = GetBinding("id", "");
|
||||
if(Id.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||
}
|
||||
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::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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
SecurityObjects::UserInfo TargetUser;
|
||||
if (!StorageService()->SubDB().GetUserById(Id, TargetUser)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
||||
}
|
||||
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 (!Internal_ &&
|
||||
!ACLProcessor::Can(UserInfo_.userinfo, TargetUser, ACLProcessor::DELETE)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
|
||||
return NotFound();
|
||||
}
|
||||
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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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.currentPassword.empty()) {
|
||||
if (!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidPassword);
|
||||
}
|
||||
}
|
||||
|
||||
if(NewUser.name.empty())
|
||||
NewUser.name = NewUser.email;
|
||||
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();
|
||||
// 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 (!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 (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();
|
||||
}
|
||||
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));
|
||||
}
|
||||
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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
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 (!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("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));
|
||||
if (GetBoolParameter("forgotPassword") || GetBoolParameter("resetPassword")) {
|
||||
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);
|
||||
SecurityObjects::ActionLink NewLink;
|
||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
|
||||
NewLink.id = MicroServiceCreateUUID();
|
||||
NewLink.userId = Existing.id;
|
||||
NewLink.created = OpenWifi::Now();
|
||||
NewLink.expires = NewLink.created + (24 * 60 * 60);
|
||||
NewLink.userAction = false;
|
||||
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
||||
|
||||
return OK();
|
||||
}
|
||||
return OK();
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo NewUser;
|
||||
const auto & RawObject = ParsedBody_;
|
||||
if(!NewUser.from_json(RawObject)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
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);
|
||||
}
|
||||
// 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);
|
||||
// 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")) {
|
||||
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 (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 (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 (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::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);
|
||||
}
|
||||
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;
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
@@ -4,28 +4,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.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:
|
||||
class RESTAPI_subuser_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||
RESTAPI_GenericServerAccounting &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:
|
||||
};
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -3,78 +3,84 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_subusers_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTAPI/RESTAPI_db_helpers.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_subusers_handler::DoGet() {
|
||||
bool IdOnly = GetBoolParameter("idOnly");
|
||||
auto operatorId = GetParameter("operatorId");
|
||||
auto nameSearch = GetParameter("nameSearch");
|
||||
auto emailSearch = GetParameter("emailSearch");
|
||||
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));
|
||||
}
|
||||
std::string baseQuery;
|
||||
if (!nameSearch.empty() || !emailSearch.empty()) {
|
||||
if (!nameSearch.empty())
|
||||
baseQuery = fmt::format(" Lower(name) like('%{}%') ",
|
||||
ORM::Escape(Poco::toLower(nameSearch)));
|
||||
if (!emailSearch.empty())
|
||||
baseQuery += baseQuery.empty()
|
||||
? fmt::format(" Lower(email) like('%{}%') ",
|
||||
ORM::Escape(Poco::toLower(emailSearch)))
|
||||
: fmt::format(" and Lower(email) like('%{}%') ",
|
||||
ORM::Escape(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);
|
||||
}
|
||||
if (QB_.CountOnly) {
|
||||
std::string whereClause;
|
||||
if (!operatorId.empty() && Utils::ValidUUID(operatorId)) {
|
||||
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() && Utils::ValidUUID(operatorId)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
} // namespace OpenWifi
|
||||