Compare commits
211 Commits
WIFI-10942
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ebb9dbe14 | ||
|
|
b51148e9c6 | ||
|
|
966ddd3cbf | ||
|
|
2781342aa5 | ||
|
|
b98dd457a6 | ||
|
|
54fc3dc6c4 | ||
|
|
9d3fe561a4 | ||
|
|
3e13e18f6c | ||
|
|
1977ecdfb7 | ||
|
|
1d703e1737 | ||
|
|
22ddb40d4c | ||
|
|
791b72aec4 | ||
|
|
46b9524903 | ||
|
|
bb09f919e6 | ||
|
|
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
|
||||||
|
...
|
||||||
|
|
||||||
12
.github/workflows/ci.yml
vendored
@@ -21,13 +21,13 @@ defaults:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
|
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||||
DOCKER_REGISTRY_USERNAME: ucentral
|
DOCKER_REGISTRY_USERNAME: ucentral
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: github
|
path: github
|
||||||
@@ -58,11 +58,11 @@ jobs:
|
|||||||
- name: Get base branch name and set as output
|
- name: Get base branch name and set as output
|
||||||
id: get_base_branch
|
id: get_base_branch
|
||||||
run: |
|
run: |
|
||||||
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
|
echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
|
echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: github
|
path: github
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
- docker
|
- docker
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: github
|
path: github
|
||||||
|
|||||||
2
.github/workflows/enforce-jira-issue-key.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: 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
|
HELM_REPO_USERNAME: ucentral
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout uCentral assembly chart repo
|
- name: Checkout uCentral assembly chart repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
path: wlan-cloud-ucentralsec
|
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)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(owsec VERSION 2.7.0)
|
project(owsec VERSION 4.1.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
@@ -32,17 +32,17 @@ endif()
|
|||||||
|
|
||||||
find_package(Git QUIET)
|
find_package(Git QUIET)
|
||||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
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}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
RESULT_VARIABLE GIT_RESULT
|
RESULT_VARIABLE GIT_RESULT
|
||||||
OUTPUT_VARIABLE GIT_HASH)
|
OUTPUT_VARIABLE GIT_HASH)
|
||||||
if(NOT GIT_RESULT EQUAL "0")
|
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()
|
endif()
|
||||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
|
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT -DBOOST_NO_CXX98_FUNCTION_BASE=1)
|
||||||
|
|
||||||
set(BUILD_SHARED_LIBS 1)
|
set(BUILD_SHARED_LIBS 1)
|
||||||
|
|
||||||
@@ -75,18 +75,63 @@ add_executable( owsec
|
|||||||
src/framework/CountryCodes.h
|
src/framework/CountryCodes.h
|
||||||
src/framework/KafkaTopics.h
|
src/framework/KafkaTopics.h
|
||||||
src/framework/MicroService.h
|
src/framework/MicroService.h
|
||||||
|
src/framework/OpenWifiTypes.h
|
||||||
src/framework/orm.h
|
src/framework/orm.h
|
||||||
src/framework/StorageClass.h
|
src/framework/StorageClass.h
|
||||||
src/framework/ow_constants.h
|
src/framework/MicroServiceErrorHandler.h
|
||||||
src/framework/WebSocketClientNotifications.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/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp
|
||||||
src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
|
src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
|
||||||
src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h
|
src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h
|
||||||
src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.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_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
|
||||||
src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
|
src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
|
||||||
src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
|
src/RESTAPI/RESTAPI_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/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
|
||||||
src/ActionLinkManager.cpp src/ActionLinkManager.h
|
src/ActionLinkManager.cpp src/ActionLinkManager.h
|
||||||
src/ACLProcessor.h
|
src/ACLProcessor.h
|
||||||
src/framework/OpenWifiTypes.h
|
|
||||||
src/storage/orm_users.cpp src/storage/orm_users.h
|
src/storage/orm_users.cpp src/storage/orm_users.h
|
||||||
src/storage/orm_tokens.cpp src/storage/orm_tokens.h
|
src/storage/orm_tokens.cpp src/storage/orm_tokens.h
|
||||||
src/storage/orm_preferences.cpp src/storage/orm_preferences.h
|
src/storage/orm_preferences.cpp src/storage/orm_preferences.h
|
||||||
src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
|
src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
|
||||||
src/storage/orm_avatar.cpp src/storage/orm_avatar.h
|
src/storage/orm_avatar.cpp src/storage/orm_avatar.h
|
||||||
src/SpecialUserHelpers.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)
|
if(NOT SMALL_BUILD)
|
||||||
target_link_libraries(owsec PUBLIC
|
target_link_libraries(owsec PUBLIC
|
||||||
@@ -135,8 +185,9 @@ if(NOT SMALL_BUILD)
|
|||||||
CppKafka::cppkafka
|
CppKafka::cppkafka
|
||||||
${AWSSDK_LINK_LIBRARIES}
|
${AWSSDK_LINK_LIBRARIES}
|
||||||
fmt::fmt
|
fmt::fmt
|
||||||
|
resolv
|
||||||
)
|
)
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
target_link_libraries(owsec PUBLIC PocoJSON)
|
target_link_libraries(owsec PUBLIC PocoJSON)
|
||||||
endif()
|
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 DEBIAN_VERSION=11.5-slim
|
||||||
ARG POCO_VERSION=poco-tip-v1
|
ARG POCO_VERSION=poco-tip-v2
|
||||||
ARG FMTLIB_VERSION=9.0.0
|
|
||||||
ARG CPPKAFKA_VERSION=tip-v1
|
ARG CPPKAFKA_VERSION=tip-v1
|
||||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
ARG VALIJASON_VERSION=tip-v1
|
||||||
ARG AWS_SDK_VERSION=1.9.315
|
|
||||||
|
|
||||||
FROM debian:$DEBIAN_VERSION AS build-base
|
FROM debian:$DEBIAN_VERSION AS build-base
|
||||||
|
|
||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
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 \
|
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
||||||
librdkafka-dev libboost-all-dev libssl-dev \
|
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
|
FROM build-base AS poco-build
|
||||||
|
|
||||||
ARG POCO_VERSION
|
ARG POCO_VERSION
|
||||||
|
|
||||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-poco/git/refs/tags/${POCO_VERSION} version.json
|
||||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch ${POCO_VERSION} /poco
|
||||||
|
|
||||||
WORKDIR /poco
|
WORKDIR /poco
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
@@ -27,26 +25,12 @@ RUN cmake ..
|
|||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
RUN cmake --build . --target install
|
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
|
FROM build-base AS cppkafka-build
|
||||||
|
|
||||||
ARG CPPKAFKA_VERSION
|
ARG CPPKAFKA_VERSION
|
||||||
|
|
||||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
RUN git clone https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||||
|
|
||||||
WORKDIR /cppkafka
|
WORKDIR /cppkafka
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
@@ -55,62 +39,44 @@ RUN cmake ..
|
|||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
RUN cmake --build . --target install
|
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
|
ADD https://api.github.com/repos/Telecominfraproject/wlan-cloud-lib-valijson/git/refs/tags/${VALIJASON_VERSION} version.json
|
||||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
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
|
RUN mkdir cmake-build
|
||||||
WORKDIR cmake-build
|
WORKDIR cmake-build
|
||||||
RUN cmake ..
|
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 . --config Release -j8
|
||||||
RUN cmake --build . --target install
|
RUN cmake --build . --target install
|
||||||
|
|
||||||
FROM build-base AS owsec-build
|
FROM build-base AS owsec-build
|
||||||
|
|
||||||
ADD CMakeLists.txt build /owsec/
|
ADD CMakeLists.txt build /owsec/
|
||||||
|
ADD overlays /owsec/overlays
|
||||||
ADD cmake /owsec/cmake
|
ADD cmake /owsec/cmake
|
||||||
ADD src /owsec/src
|
ADD src /owsec/src
|
||||||
ADD .git /owsec/.git
|
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/include /usr/local/include
|
||||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
|
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/include /usr/local/include
|
||||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
|
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
|
WORKDIR /owsec
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
WORKDIR /owsec/cmake-build
|
WORKDIR /owsec/cmake-build
|
||||||
RUN cmake .. \
|
RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||||
-Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
|
|
||||||
-DBUILD_SHARED_LIBS=ON
|
|
||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
|
|
||||||
FROM debian:$DEBIAN_VERSION
|
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 \
|
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
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 readiness_check /readiness_check
|
||||||
COPY test_scripts/curl/cli /cli
|
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
|
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
||||||
|
|
||||||
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
|
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
|
||||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
|
COPY --from=owsec-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
|
||||||
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib
|
COPY --from=cppkafka-build /cppkafka/cmake-build/src/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=poco-build /poco/cmake-build/lib/ /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=valijson-build /usr/local/include /usr/local/include
|
||||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
|
|
||||||
|
|
||||||
RUN ldconfig
|
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
|
# OpenWiFi Security (OWSEC)
|
||||||
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.
|
## 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
|
## 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
|
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
|
||||||
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:
|
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`)
|
- get a token (`/oauth2`)
|
||||||
- find the endpoints on the system (`/systemEndpoints`)
|
- 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)
|
- choose a microservice to manage (pick an endpoint that matches what you are trying to do by looking at its
|
||||||
- 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)
|
`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.
|
The CLI for the [OWGW](https://github.com/telecominfraproject/wlan-cloud-ucentralsec/blob/main/test_scripts/curl/cli) has
|
||||||
Look for the `setgateway` function.
|
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
|
## Firewall Considerations
|
||||||
The entire uCentral systems uses several MicroServices. In order for the whole system to work, you should provide the following port
|
| Port | Description | Configurable |
|
||||||
access:
|
|:------|:-------------------------------------------|:------------:|
|
||||||
|
| 16001 | Default port from the devices to the OWSEC | yes |
|
||||||
|
|
||||||
- Security
|
### Environment variables
|
||||||
- Properties file: owsec.properties
|
The following environment variables should be set from the root directory of the service. They tell the OWGW process where to find
|
||||||
- Ports
|
the configuration and the root directory.
|
||||||
- Public: 16001
|
```bash
|
||||||
- Private: 17001
|
export OWGW_ROOT=`pwd`
|
||||||
- ALB: 16101
|
export OWGW_CONFIG=`pwd`
|
||||||
|
```
|
||||||
|
You can run the shell script `set_env.sh` from the microservice root.
|
||||||
|
|
||||||
- Gateway:
|
### OWSEC Service Configuration
|
||||||
- Properties file: owgw.properties
|
The configuration is kept in a file called `owsec.properties`. To understand the content of this file,
|
||||||
- Ports
|
please look [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/CONFIGURATION.md)
|
||||||
- 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.
|
|
||||||
|
|
||||||
### Default username and password
|
### Default username and password
|
||||||
The default username and password are set in `owsec.properties` file. The following entries manage the 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.username = tip@ucentral.com
|
||||||
authentication.default.password = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
authentication.default.password = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||||
```
|
```
|
||||||
@@ -75,36 +109,17 @@ echo -n "weLoveWifiroot@system.com" | shasum -a 256
|
|||||||
b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c -
|
b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c -
|
||||||
```
|
```
|
||||||
Then you need to modify your properties file like this
|
Then you need to modify your properties file like this
|
||||||
```text
|
```properties
|
||||||
authentication.default.username = root@system.com
|
authentication.default.username = root@system.com
|
||||||
authentication.default.password = b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c
|
authentication.default.password = b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c
|
||||||
```
|
```
|
||||||
Remember, when you login, use `root@system.com` with the password `weLoveWifi`, not this monster digit sequence.
|
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
|
### 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.
|
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:
|
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 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 FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
|
||||||
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
|
export OWSEC_DEFAULT_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:
|
CLI is also included in Docker image if you want to run it this way:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
export OWSEC=openwifi.wlan.local:16001
|
export OWSEC=openwifi.wlan.local:16001
|
||||||
#export FLAGS="-k"
|
#export FLAGS="-k"
|
||||||
export OWSEC_DEFAULT_USERNAME=root@system.com
|
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
|
/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
|
||||||
```
|
```
|
||||||
|
|
||||||
### Kafka integration
|
It is very important that you not use spaces in your OrgName.
|
||||||
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
|
## Kafka topics
|
||||||
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
|
Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md)
|
||||||
|
|
||||||
```
|
## Contributions
|
||||||
openwifi.kafka.group.id = security
|
We need more contributors. Should you wish to contribute,
|
||||||
openwifi.kafka.client.id = security1
|
please follow the [contributions](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONTRIBUTING.md) document.
|
||||||
openwifi.kafka.enable = true
|
|
||||||
openwifi.kafka.brokerlist = my.kafkaserver.arilia.com:9092
|
|
||||||
openwifi.kafka.auto.commit = false
|
|
||||||
openwifi.kafka.queue.buffering.max.ms = 50
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `openwifi.kafka.brokerlist`
|
## Pull Requests
|
||||||
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
|
Please create a branch with the Jira addressing the issue you are fixing or the feature you are implementing.
|
||||||
default.
|
Create a pull-request from the branch into master.
|
||||||
|
|
||||||
#### `openwifi.kafka.group.id`
|
## Additional OWSDK Microservices
|
||||||
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
|
Here is a list of additional OWSDK microservices
|
||||||
function provided. In this case, security.
|
| Name | Description | Link | OpenAPI |
|
||||||
|
| :--- | :--- | :---: | :---: |
|
||||||
### Certificates
|
| OWSEC | Security Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml) |
|
||||||
Of course we need certificates. In our case, we already have existing certificates we have. You should find out how your file name correspond
|
| OWGW | Controller Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/openapi/owgw.yaml) |
|
||||||
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
|
| 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) |
|
||||||
for the publicly visible interfaces. For private interfaces, self-signed certificates are OK. We will not describe how to use/create private certificates
|
| OWPROV | Provisioning Service | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov) | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/owprov.yaml) |
|
||||||
here.
|
| 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) |
|
||||||
#### 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.
|
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
|||||||
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owsec"} \
|
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owsec"} \
|
||||||
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owsec"} \
|
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owsec"} \
|
||||||
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
|
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
|
envsubst < /owsec.properties.tmpl > $OWSEC_CONFIG/owsec.properties
|
||||||
fi
|
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:
|
security:
|
||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
|
- ApiToken: []
|
||||||
|
|
||||||
components:
|
components:
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
@@ -28,6 +29,10 @@ components:
|
|||||||
type: http
|
type: http
|
||||||
scheme: bearer
|
scheme: bearer
|
||||||
bearerFormat: JWT
|
bearerFormat: JWT
|
||||||
|
ApiToken:
|
||||||
|
type: apiKey
|
||||||
|
in: header
|
||||||
|
name: X-API-TOKEN
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
NotFound:
|
NotFound:
|
||||||
@@ -66,7 +71,8 @@ components:
|
|||||||
- 11 # BAD_MFA_TRANSACTION
|
- 11 # BAD_MFA_TRANSACTION
|
||||||
- 12 # MFA_FAILURE
|
- 12 # MFA_FAILURE
|
||||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||||
- 14 # CANNOT REFRESH TOKEN
|
- 14 # CANNOT_REFRESH_TOKEN
|
||||||
|
- 15 # ACCOUNT_SUSPENDED
|
||||||
ErrorDetails:
|
ErrorDetails:
|
||||||
type: string
|
type: string
|
||||||
ErrorDescription:
|
ErrorDescription:
|
||||||
@@ -164,18 +170,61 @@ components:
|
|||||||
aclTemplate:
|
aclTemplate:
|
||||||
$ref: '#/components/schemas/AclTemplate'
|
$ref: '#/components/schemas/AclTemplate'
|
||||||
|
|
||||||
ApiKeyCreationRequest:
|
ApiKeyAccessRight:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
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:
|
name:
|
||||||
type: string
|
type: string
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
|
apiKey:
|
||||||
|
type: string
|
||||||
|
salt:
|
||||||
|
type: string
|
||||||
expiresOn:
|
expiresOn:
|
||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
|
lastUse:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
rights:
|
rights:
|
||||||
$ref: '#/components/schemas/AclTemplate'
|
$ref: '#/components/schemas/ApiKeyAccessRightList'
|
||||||
|
|
||||||
|
ApiKeyEntryList:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
apiKeys:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ApiKeyEntry'
|
||||||
|
|
||||||
ApiKeyCreationAnswer:
|
ApiKeyCreationAnswer:
|
||||||
type: object
|
type: object
|
||||||
@@ -194,7 +243,7 @@ components:
|
|||||||
apiKey:
|
apiKey:
|
||||||
type: string
|
type: string
|
||||||
rights:
|
rights:
|
||||||
$ref: '#/components/schemas/AclTemplate'
|
$ref: '#/components/schemas/ApiKeyAccessRightList'
|
||||||
|
|
||||||
AclTemplate:
|
AclTemplate:
|
||||||
type: object
|
type: object
|
||||||
@@ -444,6 +493,16 @@ components:
|
|||||||
sms:
|
sms:
|
||||||
type: string
|
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
|
## These are endpoints that all services in the uCentral stack must provide
|
||||||
@@ -506,12 +565,6 @@ components:
|
|||||||
- $ref: '#/components/schemas/StringList'
|
- $ref: '#/components/schemas/StringList'
|
||||||
- $ref: '#/components/schemas/TagValuePairList'
|
- $ref: '#/components/schemas/TagValuePairList'
|
||||||
|
|
||||||
SystemCommandResults:
|
|
||||||
type: object
|
|
||||||
oneOf:
|
|
||||||
- $ref: '#/components/schemas/StringList'
|
|
||||||
- $ref: '#/components/schemas/TagValuePairList'
|
|
||||||
|
|
||||||
SystemInfoResults:
|
SystemInfoResults:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -540,6 +593,33 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
format: int64
|
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:
|
ProfileAction:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -704,6 +784,23 @@ components:
|
|||||||
value:
|
value:
|
||||||
type: string
|
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
|
## End of uCentral system wide values
|
||||||
@@ -894,7 +991,7 @@ paths:
|
|||||||
/systemEndpoints:
|
/systemEndpoints:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Authentication
|
- System Commands
|
||||||
summary: Retrieve the system layout.
|
summary: Retrieve the system layout.
|
||||||
operationId: getSystemInfo
|
operationId: getSystemInfo
|
||||||
responses:
|
responses:
|
||||||
@@ -1034,6 +1131,12 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
required: true
|
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:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: '#/components/schemas/UserInfo'
|
$ref: '#/components/schemas/UserInfo'
|
||||||
@@ -1150,6 +1253,12 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
required: true
|
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:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: '#/components/schemas/UserInfo'
|
$ref: '#/components/schemas/UserInfo'
|
||||||
@@ -1348,7 +1457,7 @@ paths:
|
|||||||
/email:
|
/email:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Email
|
- Messaging
|
||||||
summary: Send test email with the system.
|
summary: Send test email with the system.
|
||||||
operationId: Send a test email
|
operationId: Send a test email
|
||||||
requestBody:
|
requestBody:
|
||||||
@@ -1379,7 +1488,7 @@ paths:
|
|||||||
/sms:
|
/sms:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Email
|
- Messaging
|
||||||
summary: Send test email with the system.
|
summary: Send test email with the system.
|
||||||
operationId: Send a test SMS
|
operationId: Send a test SMS
|
||||||
parameters:
|
parameters:
|
||||||
@@ -1634,7 +1743,103 @@ paths:
|
|||||||
404:
|
404:
|
||||||
$ref: '#/components/responses/NotFound'
|
$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
|
## 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:
|
/validateToken:
|
||||||
get:
|
get:
|
||||||
@@ -1732,6 +1924,26 @@ paths:
|
|||||||
404:
|
404:
|
||||||
$ref: '#/components/responses/NotFound'
|
$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:
|
/system:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -1776,21 +1988,167 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- info
|
- info
|
||||||
|
- extraConfiguration
|
||||||
|
- resources
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Successful command execution
|
$ref: '#/components/schemas/SystemCommandResults'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
oneOf:
|
|
||||||
- $ref: '#/components/schemas/SystemInfoResults'
|
|
||||||
403:
|
403:
|
||||||
$ref: '#/components/responses/Unauthorized'
|
$ref: '#/components/responses/Unauthorized'
|
||||||
404:
|
404:
|
||||||
$ref: '#/components/responses/NotFound'
|
$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
|
authentication.default.password = 13268b7daa751240369d125e79c873bd8dd3bef7981bdfd38ea03dbb1fbe7dcf
|
||||||
openwifi.system.data = $OWSEC_ROOT/data
|
openwifi.system.data = $OWSEC_ROOT/data
|
||||||
openwifi.system.uri.private = https://localhost:17001
|
openwifi.system.uri.private = https://localhost:17001
|
||||||
openwifi.system.uri.public = https://local.dpaas.arilia.com:16001
|
openwifi.system.uri.public = https://main.server.com:16001
|
||||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
openwifi.system.uri.ui = https://ucentral-ui.main.server.com
|
||||||
openwifi.security.restapi.disable = false
|
openwifi.security.restapi.disable = false
|
||||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
|
openwifi.system.commandchannel = /tmp/app.ucentralsec
|
||||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
|
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
|
||||||
@@ -64,9 +64,19 @@ mailer.loginmethod = login
|
|||||||
mailer.port = 587
|
mailer.port = 587
|
||||||
mailer.templates = $OWSEC_ROOT/templates
|
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
|
# NLB Support
|
||||||
@@ -80,7 +90,7 @@ alb.port = 16101
|
|||||||
openwifi.kafka.group.id = security
|
openwifi.kafka.group.id = security
|
||||||
openwifi.kafka.client.id = security1
|
openwifi.kafka.client.id = security1
|
||||||
openwifi.kafka.enable = true
|
openwifi.kafka.enable = true
|
||||||
openwifi.kafka.brokerlist = a1.arilia.com:9092
|
openwifi.kafka.brokerlist = kafka:9092
|
||||||
openwifi.kafka.auto.commit = false
|
openwifi.kafka.auto.commit = false
|
||||||
openwifi.kafka.queue.buffering.max.ms = 50
|
openwifi.kafka.queue.buffering.max.ms = 50
|
||||||
openwifi.kafka.ssl.ca.location =
|
openwifi.kafka.ssl.ca.location =
|
||||||
@@ -110,18 +120,18 @@ storage.type.sqlite.maxsessions = 128
|
|||||||
storage.type.postgresql.maxsessions = 64
|
storage.type.postgresql.maxsessions = 64
|
||||||
storage.type.postgresql.idletime = 60
|
storage.type.postgresql.idletime = 60
|
||||||
storage.type.postgresql.host = localhost
|
storage.type.postgresql.host = localhost
|
||||||
storage.type.postgresql.username = stephb
|
storage.type.postgresql.username = owsec
|
||||||
storage.type.postgresql.password = snoopy99
|
storage.type.postgresql.password = owsec
|
||||||
storage.type.postgresql.database = ucentral
|
storage.type.postgresql.database = owsec
|
||||||
storage.type.postgresql.port = 5432
|
storage.type.postgresql.port = 5432
|
||||||
storage.type.postgresql.connectiontimeout = 60
|
storage.type.postgresql.connectiontimeout = 60
|
||||||
|
|
||||||
storage.type.mysql.maxsessions = 64
|
storage.type.mysql.maxsessions = 64
|
||||||
storage.type.mysql.idletime = 60
|
storage.type.mysql.idletime = 60
|
||||||
storage.type.mysql.host = localhost
|
storage.type.mysql.host = localhost
|
||||||
storage.type.mysql.username = stephb
|
storage.type.mysql.username = owsec
|
||||||
storage.type.mysql.password = snoopy99
|
storage.type.mysql.password = owsec
|
||||||
storage.type.mysql.database = ucentral
|
storage.type.mysql.database = owsec
|
||||||
storage.type.mysql.port = 3306
|
storage.type.mysql.port = 3306
|
||||||
storage.type.mysql.connectiontimeout = 60
|
storage.type.mysql.connectiontimeout = 60
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ mailer.loginmethod = login
|
|||||||
mailer.port = ${MAILER_PORT}
|
mailer.port = ${MAILER_PORT}
|
||||||
mailer.templates = ${MAILER_TEMPLATES}
|
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
|
# Generic information for all micro services
|
||||||
|
|||||||
@@ -9,82 +9,124 @@
|
|||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
class ACLProcessor {
|
class ACLProcessor {
|
||||||
public:
|
public:
|
||||||
enum ACL_OPS {
|
enum ACL_OPS { READ, MODIFY, DELETE, CREATE };
|
||||||
READ,
|
/*
|
||||||
MODIFY,
|
* 0) You can only delete yourself if you are a subscriber
|
||||||
DELETE,
|
1) You cannot delete yourself
|
||||||
CREATE
|
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
|
||||||
* 0) You can only delete yourself if you are a subscriber
|
ROOT 5) Creation rules: ROOT -> create anything PARTNER -> (multi-tenant owner)
|
||||||
1) You cannot delete yourself
|
admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning ADMIN ->
|
||||||
2) If you are root, you can do anything.
|
admin-subs-csr-installer-noc-accounting ACCOUNTING -> subs-installer-csr
|
||||||
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
|
switch (Op) {
|
||||||
if(User.id == Target.id && User.userRole == SecurityObjects::SUBSCRIBER && Op == DELETE)
|
case DELETE: {
|
||||||
return true;
|
// 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
|
case READ: {
|
||||||
if(User.id == Target.id && Op==DELETE)
|
return User.userRole == SecurityObjects::ROOT ||
|
||||||
return false;
|
User.userRole == SecurityObjects::ADMIN ||
|
||||||
|
User.userRole == SecurityObjects::PARTNER;
|
||||||
|
} break;
|
||||||
|
|
||||||
// rule 2
|
case CREATE: {
|
||||||
if(User.userRole==SecurityObjects::ROOT)
|
switch (User.userRole) {
|
||||||
return true;
|
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
|
case MODIFY: {
|
||||||
if(User.id == Target.id)
|
switch (User.userRole) {
|
||||||
return true;
|
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
|
private:
|
||||||
if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
|
};
|
||||||
return false;
|
|
||||||
|
|
||||||
if(Op==CREATE) {
|
} // namespace OpenWifi
|
||||||
if(User.userRole==SecurityObjects::ROOT)
|
|
||||||
return true;
|
|
||||||
if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN ||
|
|
||||||
Target.userRole==SecurityObjects::SUBSCRIBER ||
|
|
||||||
Target.userRole==SecurityObjects::CSR ||
|
|
||||||
Target.userRole==SecurityObjects::INSTALLER ||
|
|
||||||
Target.userRole==SecurityObjects::NOC ||
|
|
||||||
Target.userRole==SecurityObjects::ACCOUNTING))
|
|
||||||
return true;
|
|
||||||
if(User.userRole==SecurityObjects::ADMIN &&
|
|
||||||
(Target.userRole==SecurityObjects::ADMIN ||
|
|
||||||
Target.userRole==SecurityObjects::SUBSCRIBER ||
|
|
||||||
Target.userRole==SecurityObjects::CSR ||
|
|
||||||
Target.userRole==SecurityObjects::INSTALLER ||
|
|
||||||
Target.userRole==SecurityObjects::NOC ||
|
|
||||||
Target.userRole==SecurityObjects::ACCOUNTING))
|
|
||||||
return true;
|
|
||||||
if(User.userRole==SecurityObjects::ACCOUNTING &&
|
|
||||||
(Target.userRole==SecurityObjects::SUBSCRIBER ||
|
|
||||||
Target.userRole==SecurityObjects::INSTALLER ||
|
|
||||||
Target.userRole==SecurityObjects::CSR))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
#endif // OWSEC_ACLPROCESSOR_H
|
||||||
}
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //OWSEC_ACLPROCESSOR_H
|
|
||||||
|
|||||||
@@ -3,124 +3,142 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "ActionLinkManager.h"
|
#include "ActionLinkManager.h"
|
||||||
#include "StorageService.h"
|
|
||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
|
||||||
#include "MessagingTemplates.h"
|
#include "MessagingTemplates.h"
|
||||||
|
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||||
|
#include "StorageService.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
int ActionLinkManager::Start() {
|
int ActionLinkManager::Start() {
|
||||||
poco_information(Logger(),"Starting...");
|
poco_information(Logger(), "Starting...");
|
||||||
if(!Running_)
|
if (!Running_)
|
||||||
Thr_.start(*this);
|
Thr_.start(*this);
|
||||||
return 0;
|
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() {
|
void ActionLinkManager::run() {
|
||||||
Running_ = true ;
|
Running_ = true;
|
||||||
Utils::SetThreadName("action-mgr");
|
Utils::SetThreadName("action-mgr");
|
||||||
|
|
||||||
while(Running_) {
|
Poco::Thread::trySleep(10000);
|
||||||
Poco::Thread::trySleep(2000);
|
|
||||||
if(!Running_)
|
|
||||||
break;
|
|
||||||
std::vector<SecurityObjects::ActionLink> Links;
|
|
||||||
{
|
|
||||||
std::lock_guard G(Mutex_);
|
|
||||||
StorageService()->ActionLinksDB().GetActions(Links);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Links.empty())
|
while (Running_) {
|
||||||
continue;
|
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 (Links.empty())
|
||||||
if(!Running_)
|
continue;
|
||||||
break;
|
|
||||||
|
|
||||||
SecurityObjects::UserInfo UInfo;
|
for (auto &i : Links) {
|
||||||
if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
|
if (!Running_)
|
||||||
i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) {
|
break;
|
||||||
StorageService()->ActionLinksDB().CancelAction(i.id);
|
|
||||||
continue;
|
|
||||||
} else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
|
|
||||||
i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL ||
|
|
||||||
i.action==OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP ) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) {
|
|
||||||
StorageService()->ActionLinksDB().CancelAction(i.id);
|
|
||||||
continue;
|
|
||||||
} else if((i.action==OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION) &&
|
|
||||||
(OpenWifi::Now()-i.created)>(24*60*60)) {
|
|
||||||
StorageService()->ActionLinksDB().CancelAction(i.id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(i.action) {
|
SecurityObjects::UserInfo UInfo;
|
||||||
case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
|
if ((i.action == OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
|
||||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) {
|
i.action == OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) &&
|
||||||
poco_information(Logger(),fmt::format("Send password reset link to {}",UInfo.email));
|
!StorageService()->UserDB().GetUserById(i.userId, UInfo)) {
|
||||||
}
|
StorageService()->ActionLinksDB().CancelAction(i.id);
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
continue;
|
||||||
}
|
} else if ((i.action ==
|
||||||
break;
|
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: {
|
switch (i.action) {
|
||||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) {
|
case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
|
||||||
poco_information(Logger(),fmt::format("Send email verification link to {}",UInfo.email));
|
if (AuthService()->SendEmailToUser(i.id, UInfo.email,
|
||||||
}
|
MessagingTemplates::FORGOT_PASSWORD)) {
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
poco_information(
|
||||||
}
|
Logger(), fmt::format("Send password reset link to {}", UInfo.email));
|
||||||
break;
|
}
|
||||||
|
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||||
|
} break;
|
||||||
|
|
||||||
case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
|
case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
|
||||||
if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) {
|
if (AuthService()->SendEmailToUser(i.id, UInfo.email,
|
||||||
poco_information(Logger(),fmt::format("Send new subscriber email invitation link to {}",UInfo.email));
|
MessagingTemplates::EMAIL_VERIFICATION)) {
|
||||||
}
|
poco_information(Logger(), fmt::format("Send email verification link to {}",
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
UInfo.email));
|
||||||
}
|
}
|
||||||
break;
|
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||||
|
} break;
|
||||||
|
|
||||||
case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
|
case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
|
||||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
|
if (AuthService()->SendEmailToUser(i.id, UInfo.email,
|
||||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) {
|
MessagingTemplates::EMAIL_INVITATION)) {
|
||||||
poco_information(Logger(),fmt::format("Send subscriber password reset link to {}",UInfo.email));
|
poco_information(
|
||||||
}
|
Logger(), fmt::format("Send new subscriber email invitation link to {}",
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
UInfo.email));
|
||||||
}
|
}
|
||||||
break;
|
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||||
|
} break;
|
||||||
|
|
||||||
case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
|
case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
|
||||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
|
if (AuthService()->SendEmailToSubUser(i.id, UInfo.email,
|
||||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
|
MessagingTemplates::SUB_FORGOT_PASSWORD,"")) {
|
||||||
poco_information(Logger(),fmt::format("Send subscriber email verification link to {}",UInfo.email));
|
poco_information(
|
||||||
}
|
Logger(),
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
fmt::format("Send subscriber password reset link to {}", UInfo.email));
|
||||||
}
|
}
|
||||||
break;
|
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||||
|
} break;
|
||||||
|
|
||||||
case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
|
case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
|
||||||
auto Signup = Poco::StringTokenizer(UInfo.signingUp,":");
|
if (AuthService()->SendEmailToSubUser(
|
||||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
|
i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION,"")) {
|
||||||
poco_information(Logger(),fmt::format("Send new subscriber email verification link to {}",UInfo.email));
|
poco_information(
|
||||||
}
|
Logger(), fmt::format("Send subscriber email verification link to {}",
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
UInfo.email));
|
||||||
}
|
}
|
||||||
break;
|
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
|
||||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
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.
|
// Created by stephane bourque on 2021-11-08.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef OWSEC_ACTIONLINKMANAGER_H
|
#pragma once
|
||||||
#define OWSEC_ACTIONLINKMANAGER_H
|
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
|
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
|
||||||
public:
|
public:
|
||||||
|
static ActionLinkManager *instance() {
|
||||||
|
static auto instance_ = new ActionLinkManager;
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
|
||||||
static ActionLinkManager * instance() {
|
int Start() final;
|
||||||
static auto instance_ = new ActionLinkManager;
|
void Stop() final;
|
||||||
return instance_;
|
void run() final;
|
||||||
}
|
|
||||||
|
|
||||||
int Start() final;
|
private:
|
||||||
void Stop() final;
|
Poco::Thread Thr_;
|
||||||
void run() final;
|
std::atomic_bool Running_ = false;
|
||||||
|
|
||||||
private:
|
ActionLinkManager() noexcept
|
||||||
Poco::Thread Thr_;
|
: SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server") {}
|
||||||
std::atomic_bool Running_ = false;
|
};
|
||||||
|
inline ActionLinkManager *ActionLinkManager() { return ActionLinkManager::instance(); }
|
||||||
ActionLinkManager() noexcept:
|
} // namespace OpenWifi
|
||||||
SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inline ActionLinkManager * ActionLinkManager() { return ActionLinkManager::instance(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //OWSEC_ACTIONLINKMANAGER_H
|
|
||||||
|
|||||||
1438
src/AuthService.cpp
@@ -6,163 +6,229 @@
|
|||||||
// Arilia Wireless Inc.
|
// Arilia Wireless Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRAL_UAUTHSERVICE_H
|
#pragma once
|
||||||
#define UCENTRAL_UAUTHSERVICE_H
|
|
||||||
|
|
||||||
#include <regex>
|
#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/JSON/Object.h"
|
||||||
|
#include "Poco/JWT/Signer.h"
|
||||||
#include "Poco/Net/HTTPServerRequest.h"
|
#include "Poco/Net/HTTPServerRequest.h"
|
||||||
#include "Poco/Net/HTTPServerResponse.h"
|
#include "Poco/Net/HTTPServerResponse.h"
|
||||||
#include "Poco/JWT/Signer.h"
|
|
||||||
#include "Poco/SHA2Engine.h"
|
#include "Poco/SHA2Engine.h"
|
||||||
#include "Poco/Crypto/DigestEngine.h"
|
#include "framework/SubSystemServer.h"
|
||||||
#include "Poco/HMACEngine.h"
|
|
||||||
#include "Poco/ExpireLRUCache.h"
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
#include "framework/ow_constants.h"
|
||||||
|
|
||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
|
||||||
#include "MessagingTemplates.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 {
|
class AuthService : public SubSystemServer {
|
||||||
public:
|
public:
|
||||||
|
enum ACCESS_TYPE { USERNAME, SERVER, CUSTOM };
|
||||||
|
|
||||||
enum ACCESS_TYPE {
|
static ACCESS_TYPE IntToAccessType(int C);
|
||||||
USERNAME,
|
static int AccessTypeToInt(ACCESS_TYPE T);
|
||||||
SERVER,
|
|
||||||
CUSTOM
|
|
||||||
};
|
|
||||||
|
|
||||||
static ACCESS_TYPE IntToAccessType(int C);
|
static auto instance() {
|
||||||
static int AccessTypeToInt(ACCESS_TYPE T);
|
static auto instance_ = new AuthService;
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
|
||||||
static auto instance() {
|
int Start() override;
|
||||||
static auto instance_ = new AuthService;
|
void Stop() override;
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Start() override;
|
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||||
void Stop() override;
|
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,
|
||||||
[[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
|
const std::string &Password,
|
||||||
void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
const std::string &NewPassword,
|
||||||
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
|
SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||||
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
|
bool &Expired);
|
||||||
void Logout(const std::string &token, bool EraseFromCache=true);
|
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]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||||
[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
|
std::string &SessionToken,
|
||||||
void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||||
[[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
|
std::uint64_t TID, bool &Expired);
|
||||||
[[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;};
|
[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub(std::string &UserName,
|
||||||
void SubLogout(const std::string &token, bool EraseFromCache=true);
|
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);
|
void RemoveTokenSystemWide(const std::string &token);
|
||||||
bool ValidateSubPassword(const std::string &pwd);
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
|
bool ValidatePassword(const std::string &pwd);
|
||||||
[[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
|
bool ValidateSubPassword(const std::string &pwd);
|
||||||
[[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
|
|
||||||
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
|
|
||||||
|
|
||||||
[[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password);
|
[[nodiscard]] bool IsValidToken(const std::string &Token,
|
||||||
[[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
|
SecurityObjects::WebToken &WebToken,
|
||||||
[[nodiscard]] bool ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
|
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]] bool IsValidApiKey(const std::string &ApiKey,
|
||||||
[[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
|
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]] bool UpdatePassword(const std::string &Admin, const std::string &UserName,
|
||||||
[[nodiscard]] std::string ResetSubPassword(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]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName,
|
||||||
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
|
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 VerifyEmail(SecurityObjects::UserInfo &UInfo);
|
||||||
[[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName);
|
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
|
||||||
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &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);
|
[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||||
bool DeleteSubUserFromCache(const std::string &UserName);
|
const std::string &code);
|
||||||
void RevokeToken(std::string & Token);
|
|
||||||
void RevokeSubToken(std::string & Token);
|
|
||||||
|
|
||||||
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
|
bool DeleteUserFromCache(const std::string &UserName);
|
||||||
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
|
bool DeleteSubUserFromCache(const std::string &UserName);
|
||||||
}
|
void RevokeToken(std::string &Token);
|
||||||
|
void RevokeSubToken(std::string &Token);
|
||||||
|
|
||||||
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
|
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
|
||||||
return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
|
return MicroServicePublicEndPoint() + "/wwwassets/logo.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
|
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
|
||||||
inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
|
return MicroServiceWWWAssetsDir() + "/logo.png";
|
||||||
|
}
|
||||||
|
|
||||||
inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
|
[[nodiscard]] static inline const std::string GetSubLogoAssetURI() {
|
||||||
inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; }
|
return MicroServicePublicEndPoint() + "/wwwassets/sub_logo.png";
|
||||||
|
}
|
||||||
|
|
||||||
bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
|
[[nodiscard]] static inline const std::string GetSubLogoAssetFileName() {
|
||||||
bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
|
return MicroServiceWWWAssetsDir() + "/sub_logo.png";
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
inline const std::string &GetPasswordPolicy() const { return PasswordPolicy_; }
|
||||||
Poco::SHA2Engine SHA2_;
|
inline const std::string &GetAccessPolicy() const { return AccessPolicy_; }
|
||||||
|
|
||||||
std::string AccessPolicy_;
|
inline const std::string &GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
|
||||||
std::string PasswordPolicy_;
|
inline const std::string &GetSubAccessPolicy() const { return SubAccessPolicy_; }
|
||||||
std::string SubAccessPolicy_;
|
|
||||||
std::string SubPasswordPolicy_;
|
|
||||||
std::string PasswordValidationStr_;
|
|
||||||
std::string SubPasswordValidationStr_;
|
|
||||||
std::regex PasswordValidation_;
|
|
||||||
std::regex SubPasswordValidation_;
|
|
||||||
|
|
||||||
uint64_t TokenAging_ = 15 * 24 * 60 * 60;
|
bool RefreshUserToken(Poco::Net::HTTPServerRequest &Request,
|
||||||
uint64_t HowManyOldPassword_=5;
|
const std::string &RefreshToken,
|
||||||
uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ;
|
SecurityObjects::UserInfoAndPolicy &UI);
|
||||||
|
bool RefreshSubToken(Poco::Net::HTTPServerRequest &Request, const std::string &RefreshToken,
|
||||||
|
SecurityObjects::UserInfoAndPolicy &UI);
|
||||||
|
|
||||||
class SHA256Engine : public Poco::Crypto::DigestEngine
|
[[nodiscard]] inline auto HelperEmail() const { return HelperEmail_; };
|
||||||
{
|
[[nodiscard]] inline auto SubHelperEmail() const { return SubHelperEmail_; };
|
||||||
public:
|
[[nodiscard]] inline auto GlobalHelperEmail() const { return GlobalHelperEmail_; };
|
||||||
enum
|
[[nodiscard]] inline auto GlobalSubHelperEmail() const { return GlobalSubHelperEmail_; };
|
||||||
{
|
[[nodiscard]] inline auto HelperSite() const { return HelperSite_; };
|
||||||
BLOCK_SIZE = 64,
|
[[nodiscard]] inline auto SubHelperSite() const { return SubHelperSite_; };
|
||||||
DIGEST_SIZE = 32
|
[[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()
|
private:
|
||||||
: DigestEngine("SHA256")
|
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:
|
std::string HelperEmail_;
|
||||||
SubSystemServer("Authentication", "AUTH-SVR", "authentication")
|
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 ) {
|
SHA256Engine() : DigestEngine("SHA256") {}
|
||||||
if(Sub)
|
};
|
||||||
return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, TID, Expired );
|
|
||||||
else
|
|
||||||
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, TID, Expired );
|
|
||||||
}
|
|
||||||
|
|
||||||
} // 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.
|
// Arilia Wireless Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "Poco/Environment.h"
|
||||||
#include "Poco/Util/Application.h"
|
#include "Poco/Util/Application.h"
|
||||||
#include "Poco/Util/Option.h"
|
#include "Poco/Util/Option.h"
|
||||||
#include "Poco/Environment.h"
|
|
||||||
|
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
|
|
||||||
#include <aws/core/Aws.h>
|
#include <aws/core/Aws.h>
|
||||||
#include <aws/s3/model/AccessControlPolicy.h>
|
#include <aws/s3/model/AccessControlPolicy.h>
|
||||||
|
|
||||||
#include "StorageService.h"
|
#include "ActionLinkManager.h"
|
||||||
#include "SMTPMailerService.h"
|
|
||||||
#include "AuthService.h"
|
#include "AuthService.h"
|
||||||
#include "SMSSender.h"
|
#include "SMSSender.h"
|
||||||
#include "ActionLinkManager.h"
|
#include "SMTPMailerService.h"
|
||||||
|
#include "StorageService.h"
|
||||||
#include "TotpCache.h"
|
#include "TotpCache.h"
|
||||||
|
#include "framework/RESTAPI_RateLimiter.h"
|
||||||
|
#include "framework/UI_WebSocketClientServer.h"
|
||||||
|
#include <SecretStore.h>
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class Daemon *Daemon::instance_ = nullptr;
|
class Daemon *Daemon::instance_ = nullptr;
|
||||||
|
|
||||||
class Daemon *Daemon::instance() {
|
class Daemon *Daemon::instance() {
|
||||||
if (instance_ == nullptr) {
|
if (instance_ == nullptr) {
|
||||||
instance_ = new Daemon(vDAEMON_PROPERTIES_FILENAME,
|
instance_ =
|
||||||
vDAEMON_ROOT_ENV_VAR,
|
new Daemon(vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR,
|
||||||
vDAEMON_CONFIG_ENV_VAR,
|
vDAEMON_CONFIG_ENV_VAR, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
|
||||||
vDAEMON_APP_NAME,
|
SubSystemVec{StorageService(), SMSSender(), AuthService(), ActionLinkManager(),
|
||||||
vDAEMON_BUS_TIMER,
|
SMTPMailerService(), RESTAPI_RateLimiter(), TotpCache(),
|
||||||
SubSystemVec{
|
UI_WebSocketClientServer(), SecretStore()});
|
||||||
StorageService(),
|
}
|
||||||
SMSSender(),
|
return instance_;
|
||||||
ActionLinkManager(),
|
}
|
||||||
SMTPMailerService(),
|
|
||||||
RESTAPI_RateLimiter(),
|
|
||||||
TotpCache(),
|
|
||||||
AuthService()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||||
AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
|
AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||||
|
Daemon()->PostInitialization(self);
|
||||||
|
}
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
try {
|
try {
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
Aws::SDKOptions AwsOptions;
|
Aws::SDKOptions AwsOptions;
|
||||||
AwsOptions.memoryManagementOptions.memoryManager = nullptr;
|
AwsOptions.memoryManagementOptions.memoryManager = nullptr;
|
||||||
AwsOptions.cryptoOptions.initAndCleanupOpenSSL = false;
|
AwsOptions.cryptoOptions.initAndCleanupOpenSSL = false;
|
||||||
AwsOptions.httpOptions.initAndCleanupCurl = true;
|
AwsOptions.httpOptions.initAndCleanupCurl = true;
|
||||||
|
|
||||||
Aws::InitAPI(AwsOptions);
|
Aws::InitAPI(AwsOptions);
|
||||||
|
|
||||||
int ExitCode=0;
|
int ExitCode = 0;
|
||||||
{
|
{
|
||||||
auto App = OpenWifi::Daemon::instance();
|
auto App = OpenWifi::Daemon::instance();
|
||||||
ExitCode = App->run(argc, argv);
|
ExitCode = App->run(argc, argv);
|
||||||
}
|
}
|
||||||
ShutdownAPI(AwsOptions);
|
ShutdownAPI(AwsOptions);
|
||||||
return ExitCode;
|
return ExitCode;
|
||||||
} catch (Poco::Exception &exc) {
|
} catch (Poco::Exception &exc) {
|
||||||
std::cout << exc.displayText() << std::endl;
|
std::cout << exc.displayText() << std::endl;
|
||||||
return Poco::Util::Application::EXIT_SOFTWARE;
|
return Poco::Util::Application::EXIT_SOFTWARE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// end of namespace
|
// end of namespace
|
||||||
|
|||||||
69
src/Daemon.h
@@ -2,57 +2,50 @@
|
|||||||
// Created by stephane bourque on 2021-06-10.
|
// Created by stephane bourque on 2021-06-10.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALSEC_DAEMON_H
|
#pragma once
|
||||||
#define UCENTRALSEC_DAEMON_H
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <vector>
|
#include <iostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#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/Application.h"
|
||||||
#include "Poco/Util/ServerApplication.h"
|
|
||||||
#include "Poco/Util/Option.h"
|
#include "Poco/Util/Option.h"
|
||||||
#include "Poco/Util/OptionSet.h"
|
#include "Poco/Util/OptionSet.h"
|
||||||
#include "Poco/UUIDGenerator.h"
|
#include "Poco/Util/ServerApplication.h"
|
||||||
#include "Poco/ErrorHandler.h"
|
|
||||||
#include "Poco/Crypto/RSAKey.h"
|
|
||||||
#include "Poco/Crypto/CipherFactory.h"
|
|
||||||
#include "Poco/Crypto/Cipher.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
[[maybe_unused]] static const char * vDAEMON_PROPERTIES_FILENAME = "owsec.properties";
|
[[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_ROOT_ENV_VAR = "OWSEC_ROOT";
|
||||||
[[maybe_unused]] static const char * vDAEMON_CONFIG_ENV_VAR = "OWSEC_CONFIG";
|
[[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 char *vDAEMON_APP_NAME = uSERVICE_SECURITY.c_str();
|
||||||
[[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000;
|
[[maybe_unused]] static const uint64_t vDAEMON_BUS_TIMER = 5000;
|
||||||
|
|
||||||
class Daemon : public MicroService {
|
class Daemon : public MicroService {
|
||||||
public:
|
public:
|
||||||
explicit Daemon(const std::string & PropFile,
|
explicit Daemon(const std::string &PropFile, const std::string &RootEnv,
|
||||||
const std::string & RootEnv,
|
const std::string &ConfigEnv, const std::string &AppName, uint64_t BusTimer,
|
||||||
const std::string & ConfigEnv,
|
const SubSystemVec &SubSystems)
|
||||||
const std::string & AppName,
|
: MicroService(PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems){};
|
||||||
uint64_t BusTimer,
|
|
||||||
const SubSystemVec & SubSystems) :
|
|
||||||
MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
|
|
||||||
|
|
||||||
void PostInitialization(Poco::Util::Application &self);
|
void PostInitialization(Poco::Util::Application &self);
|
||||||
static Daemon *instance();
|
static Daemon *instance();
|
||||||
inline const std::string & AssetDir() { return AssetDir_; }
|
inline const std::string &AssetDir() { return AssetDir_; }
|
||||||
private:
|
|
||||||
static Daemon *instance_;
|
|
||||||
std::string AssetDir_;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
private:
|
||||||
inline void DaemonPostInitialization(Poco::Util::Application &self) {
|
static Daemon *instance_;
|
||||||
Daemon()->PostInitialization(self);
|
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.
|
// Created by stephane bourque on 2021-10-11.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
|
||||||
|
|
||||||
#include "MFAServer.h"
|
#include "MFAServer.h"
|
||||||
|
#include "AuthService.h"
|
||||||
#include "SMSSender.h"
|
#include "SMSSender.h"
|
||||||
#include "SMTPMailerService.h"
|
#include "SMTPMailerService.h"
|
||||||
#include "AuthService.h"
|
|
||||||
#include "TotpCache.h"
|
#include "TotpCache.h"
|
||||||
|
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
int MFAServer::Start() {
|
int MFAServer::Start() { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MFAServer::Stop() {
|
void MFAServer::Stop() {}
|
||||||
}
|
|
||||||
|
|
||||||
bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &ChallengeStart) {
|
bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||||
std::lock_guard G(Mutex_);
|
Poco::JSON::Object &ChallengeStart) {
|
||||||
|
std::lock_guard G(Mutex_);
|
||||||
|
|
||||||
CleanCache();
|
CleanCache();
|
||||||
|
|
||||||
if(!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
|
if (!MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::string Challenge = MakeChallenge();
|
std::string Challenge = MakeChallenge();
|
||||||
std::string uuid = MicroService::CreateUUID();
|
std::string uuid = MicroServiceCreateUUID();
|
||||||
uint64_t Created = OpenWifi::Now();
|
uint64_t Created = Utils::Now();
|
||||||
|
|
||||||
ChallengeStart.set("uuid",uuid);
|
ChallengeStart.set("uuid", uuid);
|
||||||
ChallengeStart.set("created", Created);
|
ChallengeStart.set("created", Created);
|
||||||
ChallengeStart.set("question", "mfa challenge");
|
ChallengeStart.set("question", "mfa challenge");
|
||||||
ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
|
ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
|
||||||
|
|
||||||
Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method };
|
Cache_[uuid] = MFACacheEntry{.UInfo = UInfo,
|
||||||
return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
|
.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) {
|
bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||||
if(Method==MFAMETHODS::SMS && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
|
const std::string &Method, const std::string &Challenge) {
|
||||||
std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen.";
|
if (Method == MFAMETHODS::SMS && SMSSender()->Enabled() &&
|
||||||
return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message);
|
!UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
|
||||||
} else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
|
std::string Message = "This is your login code: " + Challenge +
|
||||||
return AuthService()->SendEmailChallengeCode(UInfo,Challenge);
|
" Please enter this in your login screen.";
|
||||||
} else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
|
return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number,
|
||||||
return true;
|
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) {
|
bool MFAServer::ResendCode(const std::string &uuid) {
|
||||||
std::lock_guard G(Mutex_);
|
std::lock_guard G(Mutex_);
|
||||||
auto Hint = Cache_.find(uuid);
|
auto Hint = Cache_.find(uuid);
|
||||||
if(Hint==Cache_.end())
|
if (Hint == Cache_.end())
|
||||||
return false;
|
return false;
|
||||||
return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
|
return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) {
|
bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
|
||||||
std::lock_guard G(Mutex_);
|
SecurityObjects::UserInfoAndPolicy &UInfo) {
|
||||||
|
std::lock_guard G(Mutex_);
|
||||||
|
|
||||||
if(!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
|
if (!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto uuid = ChallengeResponse->get("uuid").toString();
|
auto uuid = ChallengeResponse->get("uuid").toString();
|
||||||
auto Hint = Cache_.find(uuid);
|
auto Hint = Cache_.find(uuid);
|
||||||
if(Hint == end(Cache_)) {
|
if (Hint == end(Cache_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto answer = ChallengeResponse->get("answer").toString();
|
auto answer = ChallengeResponse->get("answer").toString();
|
||||||
std::string Expecting;
|
std::string Expecting;
|
||||||
if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) {
|
if (Hint->second.Method == MFAMETHODS::AUTHENTICATOR) {
|
||||||
if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) {
|
if (!TotpCache()->ValidateCode(
|
||||||
return false;
|
Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret, answer,
|
||||||
}
|
Expecting)) {
|
||||||
} else if(Hint->second.Answer!=answer) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
} else if (Hint->second.Answer != answer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
UInfo = Hint->second.UInfo;
|
UInfo = Hint->second.UInfo;
|
||||||
Cache_.erase(Hint);
|
Cache_.erase(Hint);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MFAServer::MethodEnabled(const std::string &Method) {
|
bool MFAServer::MethodEnabled(const std::string &Method) {
|
||||||
if(Method==MFAMETHODS::SMS)
|
if (Method == MFAMETHODS::SMS)
|
||||||
return SMSSender()->Enabled();
|
return SMSSender()->Enabled();
|
||||||
|
|
||||||
if(Method==MFAMETHODS::EMAIL)
|
if (Method == MFAMETHODS::EMAIL)
|
||||||
return SMTPMailerService()->Enabled();
|
return SMTPMailerService()->Enabled();
|
||||||
|
|
||||||
if(Method==MFAMETHODS::AUTHENTICATOR)
|
if (Method == MFAMETHODS::AUTHENTICATOR)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MFAServer::CleanCache() {
|
void MFAServer::CleanCache() {
|
||||||
// it is assumed that you have locked Cache_ at this point.
|
// it is assumed that you have locked Cache_ at this point.
|
||||||
uint64_t Now = OpenWifi::Now();
|
uint64_t Now = Utils::Now();
|
||||||
for(auto i=begin(Cache_);i!=end(Cache_);) {
|
for (auto i = begin(Cache_); i != end(Cache_);) {
|
||||||
if((Now-i->second.Created)>300) {
|
if ((Now - i->second.Created) > 300) {
|
||||||
i = Cache_.erase(i);
|
i = Cache_.erase(i);
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,61 +4,62 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include "Poco/JSON/Object.h"
|
#include "Poco/JSON/Object.h"
|
||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
namespace MFAMETHODS {
|
namespace MFAMETHODS {
|
||||||
inline const static std::string SMS{"sms"};
|
inline const static std::string SMS{"sms"};
|
||||||
inline const static std::string EMAIL{"email"};
|
inline const static std::string EMAIL{"email"};
|
||||||
inline const static std::string AUTHENTICATOR{"authenticator"};
|
inline const static std::string AUTHENTICATOR{"authenticator"};
|
||||||
inline const static std::vector<std::string> Methods{ SMS, EMAIL, AUTHENTICATOR };
|
inline const static std::vector<std::string> Methods{SMS, EMAIL, AUTHENTICATOR};
|
||||||
inline bool Validate(const std::string &M) {
|
inline bool Validate(const std::string &M) {
|
||||||
return std::find(cbegin(Methods), cend(Methods),M)!=Methods.end();
|
return std::find(cbegin(Methods), cend(Methods), M) != Methods.end();
|
||||||
}
|
}
|
||||||
}
|
} // namespace MFAMETHODS
|
||||||
|
|
||||||
struct MFACacheEntry {
|
struct MFACacheEntry {
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
std::string Answer;
|
std::string Answer;
|
||||||
uint64_t Created;
|
uint64_t Created;
|
||||||
std::string Method;
|
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{
|
bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||||
public:
|
Poco::JSON::Object &Challenge);
|
||||||
int Start() override;
|
bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
|
||||||
void Stop() override;
|
SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||||
static auto instance() {
|
static bool MethodEnabled(const std::string &Method);
|
||||||
static auto instance_ = new MFAServer;
|
bool ResendCode(const std::string &uuid);
|
||||||
return instance_;
|
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);
|
static inline std::string MakeChallenge() {
|
||||||
bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
|
return fmt::format("{0:06}", MicroServiceRandom(1, 999999));
|
||||||
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() {
|
private:
|
||||||
return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) );
|
MFAChallengeCache Cache_;
|
||||||
}
|
MFAServer() noexcept : SubSystemServer("MFServer", "MFA-SVR", "mfa") {}
|
||||||
|
|
||||||
private:
|
void CleanCache();
|
||||||
MFAChallengeCache Cache_;
|
};
|
||||||
MFAServer() noexcept:
|
|
||||||
SubSystemServer("MFServer", "MFA-SVR", "mfa")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CleanCache();
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto MFAServer() { return MFAServer::instance(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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 {
|
namespace OpenWifi {
|
||||||
|
|
||||||
class MessagingTemplates {
|
class MessagingTemplates {
|
||||||
public:
|
public:
|
||||||
static MessagingTemplates & instance() {
|
static MessagingTemplates &instance() {
|
||||||
static auto instance = new MessagingTemplates;
|
static auto instance = new MessagingTemplates;
|
||||||
return *instance;
|
return *instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EMAIL_REASON {
|
enum EMAIL_REASON {
|
||||||
FORGOT_PASSWORD = 0,
|
FORGOT_PASSWORD = 0,
|
||||||
EMAIL_VERIFICATION,
|
EMAIL_VERIFICATION,
|
||||||
SIGNUP_VERIFICATION,
|
SUB_SIGNUP_VERIFICATION,
|
||||||
EMAIL_INVITATION,
|
EMAIL_INVITATION,
|
||||||
VERIFICATION_CODE,
|
VERIFICATION_CODE,
|
||||||
SUB_FORGOT_PASSWORD,
|
SUB_FORGOT_PASSWORD,
|
||||||
SUB_EMAIL_VERIFICATION,
|
SUB_EMAIL_VERIFICATION,
|
||||||
SUB_VERIFICATION_CODE
|
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) {
|
static std::string AddOperator(const std::string &filename,
|
||||||
if(OperatorName.empty())
|
const std::string &OperatorName) {
|
||||||
return "/" + filename;
|
if (OperatorName.empty())
|
||||||
return "/" + OperatorName + "/" + filename;
|
return "/" + filename;
|
||||||
}
|
return "/" + OperatorName + "/" + filename;
|
||||||
|
}
|
||||||
|
|
||||||
static std::string TemplateName( EMAIL_REASON r , const std::string &OperatorName="") {
|
static std::string TemplateName(EMAIL_REASON r, const std::string &OperatorName = "") {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName);
|
case FORGOT_PASSWORD:
|
||||||
case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName);
|
return AddOperator(EmailTemplateNames[FORGOT_PASSWORD], OperatorName);
|
||||||
case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName);
|
case EMAIL_VERIFICATION:
|
||||||
case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName);
|
return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION], OperatorName);
|
||||||
case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName);
|
case SUB_SIGNUP_VERIFICATION:
|
||||||
case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName);
|
return AddOperator(EmailTemplateNames[SUB_SIGNUP_VERIFICATION], OperatorName);
|
||||||
case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName);
|
case EMAIL_INVITATION:
|
||||||
case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName);
|
return AddOperator(EmailTemplateNames[EMAIL_INVITATION], OperatorName);
|
||||||
default:
|
case VERIFICATION_CODE:
|
||||||
return "";
|
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 = "" ) {
|
static std::string Logo(const std::string &OperatorName = "") {
|
||||||
return AddOperator("logo.jpg", OperatorName);
|
return AddOperator("logo.png", OperatorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string SubLogo(const std::string &OperatorName = "" ) {
|
static std::string SubLogo(const std::string &OperatorName = "") {
|
||||||
return AddOperator("sub_logo.jpg", OperatorName);
|
return AddOperator("sub_logo.png", OperatorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline const static std::vector<std::string> EmailTemplateNames = {
|
inline const static std::vector<std::string> EmailTemplateNames = {
|
||||||
"password_reset",
|
"password_reset",
|
||||||
"email_verification",
|
"email_verification",
|
||||||
"signup_verification",
|
"sub_signup_verification",
|
||||||
"email_invitation",
|
"email_invitation",
|
||||||
"verification_code",
|
"verification_code",
|
||||||
"sub_password_reset",
|
"sub_password_reset",
|
||||||
"sub_email_verification",
|
"sub_email_verification",
|
||||||
"sub_verification_code"
|
"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(); }
|
inline MessagingTemplates &MessagingTemplates() { return MessagingTemplates::instance(); }
|
||||||
|
|
||||||
} // OpenWifi
|
|
||||||
|
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -7,281 +7,350 @@
|
|||||||
|
|
||||||
#include "RESTAPI_action_links.h"
|
#include "RESTAPI_action_links.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
#include "framework/MicroService.h"
|
#include "framework/OpenAPIRequests.h"
|
||||||
|
#include "framework/RESTAPI_PartHandler.h"
|
||||||
|
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
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","");
|
void RESTAPI_action_links::DoGet() {
|
||||||
auto Id = GetParameter("id","");
|
|
||||||
|
|
||||||
SecurityObjects::ActionLink Link;
|
auto Action = GetParameter("action", "");
|
||||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
|
auto Id = GetParameter("id", "");
|
||||||
return DoReturnA404();
|
|
||||||
|
|
||||||
if(Action=="password_reset")
|
#if defined(TIP_CERT_SERVICE)
|
||||||
return RequestResetPassword(Link);
|
if (!OpenWifi::ProcessExternalActionLinks(*this, Id, Action)) {
|
||||||
else if(Action=="sub_password_reset")
|
return;
|
||||||
return RequestSubResetPassword(Link);
|
}
|
||||||
else if(Action=="email_verification")
|
#endif
|
||||||
return DoEmailVerification(Link);
|
|
||||||
else if(Action=="sub_email_verification")
|
|
||||||
return DoSubEmailVerification(Link);
|
|
||||||
else if(Action=="signup_verification")
|
|
||||||
return DoNewSubVerification(Link);
|
|
||||||
else
|
|
||||||
return DoReturnA404();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RESTAPI_action_links::DoPost() {
|
SecurityObjects::ActionLink Link;
|
||||||
auto Action = GetParameter("action","");
|
if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link))
|
||||||
|
return DoReturnA404();
|
||||||
|
|
||||||
if(Action=="password_reset")
|
if (Action == "password_reset")
|
||||||
return CompleteResetPassword();
|
return RequestResetPassword(Link);
|
||||||
else if(Action=="sub_password_reset")
|
else if (Action == "sub_password_reset")
|
||||||
return CompleteResetPassword();
|
return RequestResetPassword(Link);
|
||||||
else if(Action=="signup_completion")
|
else if (Action == "email_verification")
|
||||||
return CompleteSubVerification();
|
return DoEmailVerification(Link);
|
||||||
else if(Action=="email_invitation")
|
else if (Action == "sub_email_verification")
|
||||||
return CompleteEmailInvitation();
|
return DoEmailVerification(Link);
|
||||||
else
|
else if (Action == "signup_verification")
|
||||||
return DoReturnA404();
|
return DoNewSubVerification(Link);
|
||||||
}
|
else
|
||||||
|
return DoReturnA404();
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
|
void RESTAPI_action_links::DoPost() {
|
||||||
Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId));
|
auto Action = GetParameter("action", "");
|
||||||
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::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
|
if (Action == "password_reset")
|
||||||
Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}", Request->clientAddress().toString(), Link.userId));
|
return CompleteResetPassword();
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification.html"};
|
else if (Action == "sub_password_reset")
|
||||||
Types::StringPairVec FormVars{ {"UUID", Link.id},
|
return CompleteResetPassword();
|
||||||
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
|
else if (Action == "signup_completion")
|
||||||
SendHTMLFileBack(FormFile,FormVars);
|
return CompleteSubVerification();
|
||||||
}
|
else if (Action == "email_invitation")
|
||||||
|
return CompleteEmailInvitation();
|
||||||
|
else
|
||||||
|
return DoReturnA404();
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_action_links::CompleteResetPassword() {
|
void RESTAPI_action_links::AddGlobalVars(Types::StringPairVec &Vars) {
|
||||||
// form has been posted...
|
Vars.push_back(std::make_pair("USER_HELPER_EMAIL", AuthService()->HelperEmail()));
|
||||||
RESTAPI_PartHandler PartHandler;
|
Vars.push_back(std::make_pair("SUB_HELPER_EMAIL", AuthService()->SubHelperEmail()));
|
||||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
Vars.push_back(
|
||||||
if (!Form.empty()) {
|
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");
|
void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
|
||||||
auto Password2 = Form.get("password2","blu");
|
Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}",
|
||||||
auto Id = Form.get("id","");
|
Request->clientAddress().toString(), Link.userId));
|
||||||
auto now = OpenWifi::Now();
|
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;
|
void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
|
||||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link))
|
Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}",
|
||||||
return DoReturnA404();
|
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) {
|
void RESTAPI_action_links::CompleteResetPassword() {
|
||||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
RESTAPI_PartHandler PartHandler;
|
||||||
return DoReturnA404();
|
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||||
}
|
if (!Form.empty()) {
|
||||||
|
|
||||||
if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
|
auto Password1 = Form.get("password1", "bla");
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
|
auto Password2 = Form.get("password2", "blu");
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
auto Id = Form.get("id", "");
|
||||||
{"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
|
auto now = OpenWifi::Now();
|
||||||
" 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (now > Link.expires) {
|
||||||
if(!Found) {
|
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
|
return DoReturnA404();
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
}
|
||||||
{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
|
|
||||||
return SendHTMLFileBack(FormFile,FormVars);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UInfo.blackListed || UInfo.suspended) {
|
if (Password1 != Password2 || !AuthService()->ValidatePassword(Password2) ||
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
|
!AuthService()->ValidatePassword(Password1)) {
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
|
||||||
{"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
|
Types::StringPairVec FormVars{
|
||||||
return SendHTMLFileBack(FormFile,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);
|
SecurityObjects::UserInfo 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
UInfo.modified = OpenWifi::Now();
|
bool Found = Link.userAction
|
||||||
if(Link.userAction)
|
? StorageService()->UserDB().GetUserById(Link.userId, UInfo)
|
||||||
StorageService()->UserDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
|
: StorageService()->SubDB().GetUserById(Link.userId, UInfo);
|
||||||
else
|
if (!Found) {
|
||||||
StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
|
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
|
||||||
|
Types::StringPairVec FormVars{
|
||||||
|
{"UUID", Id},
|
||||||
|
{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact "
|
||||||
|
"your system administrator."}};
|
||||||
|
AddGlobalVars(FormVars);
|
||||||
|
return SendHTMLFileBack(FormFile, FormVars);
|
||||||
|
}
|
||||||
|
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"};
|
if (UInfo.blackListed || UInfo.suspended) {
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
|
||||||
{"USERNAME", UInfo.email},
|
Types::StringPairVec FormVars{
|
||||||
{"ACTION_LINK",MicroService::instance().GetUIURI()}};
|
{"UUID", Id},
|
||||||
StorageService()->ActionLinksDB().CompleteAction(Id);
|
{"ERROR_TEXT", "Please contact our system administrators. We have identified "
|
||||||
SendHTMLFileBack(FormFile,FormVars);
|
"an error in your account that must be resolved first."}};
|
||||||
} else {
|
AddGlobalVars(FormVars);
|
||||||
DoReturnA404();
|
return SendHTMLFileBack(FormFile, FormVars);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RESTAPI_action_links::CompleteSubVerification() {
|
bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1, UInfo)
|
||||||
RESTAPI_PartHandler PartHandler;
|
: AuthService()->SetSubPassword(Password1, UInfo);
|
||||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
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()) {
|
UInfo.modified = OpenWifi::Now();
|
||||||
auto Password1 = Form.get("password1","bla");
|
if (Link.userAction)
|
||||||
auto Password2 = Form.get("password2","blu");
|
StorageService()->UserDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
|
||||||
auto Id = Form.get("id","");
|
else
|
||||||
auto now = OpenWifi::Now();
|
StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
|
||||||
|
|
||||||
SecurityObjects::ActionLink Link;
|
Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_success.html"};
|
||||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) {
|
Types::StringPairVec FormVars{{"UUID", Id},
|
||||||
return DoReturnA404();
|
{"USERNAME", UInfo.email},
|
||||||
}
|
{"ACTION_LINK", MicroService::instance().GetUIURI()}};
|
||||||
|
AddGlobalVars(FormVars);
|
||||||
|
StorageService()->ActionLinksDB().CompleteAction(Id);
|
||||||
|
SendHTMLFileBack(FormFile, FormVars);
|
||||||
|
} else {
|
||||||
|
DoReturnA404();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(now > Link.expires) {
|
void RESTAPI_action_links::CompleteSubVerification() {
|
||||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
RESTAPI_PartHandler PartHandler;
|
||||||
return DoReturnA404();
|
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||||
}
|
|
||||||
|
|
||||||
if(Password1!=Password2 || !AuthService()->ValidateSubPassword(Password1)) {
|
if (!Form.empty()) {
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
|
auto Password1 = Form.get("password1", "bla");
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
auto Password2 = Form.get("password2", "blu");
|
||||||
{"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
|
auto Id = Form.get("id", "");
|
||||||
" accepted password creation restrictions. Please consult our on-line help"
|
auto now = OpenWifi::Now();
|
||||||
" to look at the our password policy. If you would like to contact us, please mention"
|
|
||||||
" id(" + Id + ")"}};
|
|
||||||
return SendHTMLFileBack(FormFile,FormVars);
|
|
||||||
}
|
|
||||||
|
|
||||||
SecurityObjects::UserInfo UInfo;
|
SecurityObjects::ActionLink Link;
|
||||||
bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo);
|
if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link)) {
|
||||||
if(!Found) {
|
return DoReturnA404();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UInfo.blackListed || UInfo.suspended) {
|
if (now > Link.expires) {
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
|
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
return DoReturnA404();
|
||||||
{"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
|
}
|
||||||
return SendHTMLFileBack(FormFile,FormVars);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GoodPassword = AuthService()->SetSubPassword(Password1,UInfo);
|
if (Password1 != Password2 || !AuthService()->ValidateSubPassword(Password1)) {
|
||||||
if(!GoodPassword) {
|
Poco::File FormFile{Daemon()->AssetDir() + "/sub_password_reset_error.html"};
|
||||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
|
Types::StringPairVec FormVars{
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
{"UUID", Id},
|
||||||
{"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
|
{"ERROR_TEXT",
|
||||||
return SendHTMLFileBack(FormFile,FormVars);
|
"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();
|
SecurityObjects::UserInfo UInfo;
|
||||||
UInfo.changePassword = false;
|
bool Found = StorageService()->SubDB().GetUserById(Link.userId, UInfo);
|
||||||
UInfo.lastEmailCheck = OpenWifi::Now();
|
if (!Found) {
|
||||||
UInfo.waitingForEmailCheck = false;
|
Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
|
||||||
UInfo.validated = OpenWifi::Now();
|
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"};
|
bool GoodPassword = AuthService()->SetSubPassword(Password1, UInfo);
|
||||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
if (!GoodPassword) {
|
||||||
{"USERNAME", UInfo.email} };
|
Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
|
||||||
StorageService()->ActionLinksDB().CompleteAction(Id);
|
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
|
UInfo.modified = OpenWifi::Now();
|
||||||
Poco::JSON::Object Body;
|
UInfo.changePassword = false;
|
||||||
auto RawSignup = Poco::StringTokenizer(UInfo.signingUp,":");
|
UInfo.lastEmailCheck = OpenWifi::Now();
|
||||||
Body.set("signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]);
|
UInfo.waitingForEmailCheck = false;
|
||||||
OpenAPIRequestPut ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup",
|
UInfo.validated = OpenWifi::Now();
|
||||||
{
|
|
||||||
{"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} ,
|
|
||||||
{"operation", "emailVerified"}
|
|
||||||
},
|
|
||||||
Body,30000);
|
|
||||||
Logger().information(fmt::format("({}): Completed subscriber e-mail verification and password.",UInfo.email));
|
|
||||||
Poco::JSON::Object::Ptr Response;
|
|
||||||
auto Status = ProvRequest.Do(Response);
|
|
||||||
std::stringstream ooo;
|
|
||||||
if(Response!= nullptr)
|
|
||||||
Response->stringify(ooo);
|
|
||||||
Logger().information(fmt::format("({}): Completed subscriber e-mail verification. Provisioning notified, Error={}.",
|
|
||||||
UInfo.email, Status));
|
|
||||||
SendHTMLFileBack(FormFile,FormVars);
|
|
||||||
Logger().information(fmt::format("({}): Completed subscriber e-mail verification. FORM notified.",UInfo.email));
|
|
||||||
} else {
|
|
||||||
DoReturnA404();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
|
StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
|
||||||
auto now = OpenWifi::Now();
|
|
||||||
|
|
||||||
if(now > Link.expires) {
|
Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_success.html"};
|
||||||
StorageService()->ActionLinksDB().CancelAction(Link.id);
|
Types::StringPairVec FormVars{{"UUID", Id}, {"USERNAME", UInfo.email}};
|
||||||
return DoReturnA404();
|
StorageService()->ActionLinksDB().CompleteAction(Id);
|
||||||
}
|
|
||||||
|
|
||||||
SecurityObjects::UserInfo UInfo;
|
// Send the update to the provisioning service
|
||||||
bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
|
Poco::JSON::Object Body;
|
||||||
if (!Found) {
|
auto RawSignup = Poco::StringTokenizer(UInfo.signingUp, ":");
|
||||||
Types::StringPairVec FormVars{{"UUID", Link.id},
|
Body.set("signupUUID", RawSignup.count() == 1 ? UInfo.signingUp : RawSignup[1]);
|
||||||
{"ERROR_TEXT", "This does not appear to be a valid email verification link.."}};
|
OpenAPIRequestPut ProvRequest(
|
||||||
Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"};
|
uSERVICE_PROVISIONING, "/api/v1/signup",
|
||||||
return SendHTMLFileBack(FormFile, FormVars);
|
{{"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(),
|
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
|
||||||
UInfo.email));
|
auto now = OpenWifi::Now();
|
||||||
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::DoReturnA404() {
|
if (now > Link.expires) {
|
||||||
Types::StringPairVec FormVars;
|
StorageService()->ActionLinksDB().CancelAction(Link.id);
|
||||||
Poco::File FormFile{Daemon()->AssetDir() + "/404_error.html"};
|
return DoReturnA404();
|
||||||
SendHTMLFileBack(FormFile, FormVars);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RESTAPI_action_links::CompleteEmailInvitation() {
|
SecurityObjects::UserInfo UInfo;
|
||||||
/// TODO:
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_action_links : public RESTAPIHandler {
|
class RESTAPI_action_links : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_POST,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal, false, true,
|
||||||
Internal,
|
RateLimit{.Interval = 1000, .MaxCalls = 10}) {}
|
||||||
false,
|
static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
|
||||||
true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
|
void RequestResetPassword(SecurityObjects::ActionLink &Link);
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
|
void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
|
||||||
void RequestResetPassword(SecurityObjects::ActionLink &Link);
|
void CompleteResetPassword();
|
||||||
void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
|
void CompleteSubVerification();
|
||||||
void CompleteResetPassword();
|
void DoEmailVerification(SecurityObjects::ActionLink &Link);
|
||||||
void CompleteSubVerification();
|
void DoSubEmailVerification(SecurityObjects::ActionLink &Link);
|
||||||
void DoEmailVerification(SecurityObjects::ActionLink &Link);
|
void DoReturnA404();
|
||||||
void DoSubEmailVerification(SecurityObjects::ActionLink &Link);
|
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
|
||||||
void DoReturnA404();
|
void CompleteEmailInvitation();
|
||||||
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
|
static void AddGlobalVars(Types::StringPairVec &Vars);
|
||||||
void CompleteEmailInvitation();
|
|
||||||
|
|
||||||
void DoGet() final;
|
void DoGet() final;
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoDelete() final {};
|
void DoDelete() final{};
|
||||||
void DoPut() 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 "RESTAPI_asset_server.h"
|
||||||
|
#include "Daemon.h"
|
||||||
#include "Poco/File.h"
|
#include "Poco/File.h"
|
||||||
#include "framework/ow_constants.h"
|
#include "framework/ow_constants.h"
|
||||||
#include "Daemon.h"
|
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
void RESTAPI_asset_server::DoGet() {
|
void RESTAPI_asset_server::DoGet() {
|
||||||
Poco::File AssetFile;
|
Poco::File AssetFile;
|
||||||
|
|
||||||
if(Request->getURI().find("/favicon.ico") != std::string::npos) {
|
if (Request->getURI().find("/favicon.ico") != std::string::npos) {
|
||||||
AssetFile = Daemon()->AssetDir() + "/favicon.ico";
|
AssetFile = Daemon()->AssetDir() + "/favicon.ico";
|
||||||
} else {
|
} else {
|
||||||
std::string AssetName = GetBinding(RESTAPI::Protocol::ID, "");
|
std::string AssetName = GetBinding(RESTAPI::Protocol::ID, "");
|
||||||
AssetFile = Daemon()->AssetDir() + "/" + AssetName;
|
AssetFile = Daemon()->AssetDir() + "/" + AssetName;
|
||||||
}
|
}
|
||||||
if(!AssetFile.isFile()) {
|
if (!AssetFile.isFile()) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
SendFile(AssetFile);
|
SendFile(AssetFile);
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,31 +4,29 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_asset_server : public RESTAPIHandler {
|
class RESTAPI_asset_server : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>
|
bool Internal)
|
||||||
{Poco::Net::HTTPRequest::HTTP_POST,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal, false) {}
|
||||||
Internal, false) {}
|
static auto PathName() {
|
||||||
static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" ,
|
return std::list<std::string>{"/wwwassets/{id}", "/favicon.ico"};
|
||||||
"/favicon.ico"}; };
|
};
|
||||||
void DoGet() final;
|
void DoGet() final;
|
||||||
void DoPost() final {};
|
void DoPost() final{};
|
||||||
void DoDelete() final {};
|
void DoDelete() final{};
|
||||||
void DoPut() final {};
|
void DoPut() final{};
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -5,78 +5,85 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Poco/CountingStream.h"
|
||||||
|
#include "Poco/Net/HTMLForm.h"
|
||||||
#include "RESTAPI_avatar_handler.h"
|
#include "RESTAPI_avatar_handler.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
#include "Poco/Net/HTMLForm.h"
|
#include "framework/MicroServiceFuncs.h"
|
||||||
#include "framework/MicroService.h"
|
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void AvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
|
void AvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header,
|
||||||
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
|
std::istream &Stream) {
|
||||||
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
|
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
|
||||||
std::string Disposition;
|
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
|
||||||
Poco::Net::NameValueCollection Parameters;
|
std::string Disposition;
|
||||||
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
|
Poco::Net::NameValueCollection Parameters;
|
||||||
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
|
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION],
|
||||||
}
|
Disposition, Parameters);
|
||||||
Poco::CountingInputStream InputStream(Stream);
|
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
|
||||||
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
|
}
|
||||||
Length_ = OutputStream_.str().size();
|
Poco::CountingInputStream InputStream(Stream);
|
||||||
};
|
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
|
||||||
|
Length_ = OutputStream_.str().size();
|
||||||
|
};
|
||||||
|
|
||||||
void RESTAPI_avatar_handler::DoPost() {
|
void RESTAPI_avatar_handler::DoPost() {
|
||||||
std::string Id = UserInfo_.userinfo.id;
|
std::string Id = UserInfo_.userinfo.id;
|
||||||
SecurityObjects::UserInfo UInfo;
|
SecurityObjects::UserInfo UInfo;
|
||||||
|
|
||||||
std::stringstream SS;
|
std::stringstream SS;
|
||||||
AvatarPartHandler partHandler(Id, Logger_, SS);
|
AvatarPartHandler partHandler(Id, Logger_, SS);
|
||||||
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
|
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
|
|
||||||
if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
|
if (!partHandler.Name().empty() &&
|
||||||
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
partHandler.Length() < MicroServiceConfigGetInt("openwifi.avatar.maxsize", 2000000)) {
|
||||||
Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
|
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
||||||
Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
|
Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
|
||||||
StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email,
|
Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(),
|
||||||
Id, SS.str(), partHandler.ContentType(), partHandler.Name());
|
partHandler.ContentType()));
|
||||||
StorageService()->UserDB().SetAvatar(Id,"1");
|
StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, SS.str(),
|
||||||
Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email));
|
partHandler.ContentType(), partHandler.Name());
|
||||||
} else {
|
StorageService()->UserDB().SetAvatar(Id, "1");
|
||||||
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
Logger().information(fmt::format("Adding avatar for {}", UserInfo_.userinfo.email));
|
||||||
Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
|
} else {
|
||||||
Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
|
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
||||||
}
|
Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
|
||||||
ReturnObject(Answer);
|
Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
|
||||||
}
|
}
|
||||||
|
ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_avatar_handler::DoGet() {
|
void RESTAPI_avatar_handler::DoGet() {
|
||||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||||
if (Id.empty()) {
|
if (Id.empty()) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Type, Name, AvatarContent;
|
std::string Type, Name, AvatarContent;
|
||||||
if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
|
if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent,
|
||||||
return NotFound();
|
Type, Name)) {
|
||||||
}
|
return NotFound();
|
||||||
Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size()));
|
}
|
||||||
return SendFileContent(AvatarContent, Type, Name);
|
Logger().information(fmt::format("Retrieving avatar for {}, size:{}",
|
||||||
}
|
UserInfo_.userinfo.email, AvatarContent.size()));
|
||||||
|
return SendFileContent(AvatarContent, Type, Name);
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_avatar_handler::DoDelete() {
|
void RESTAPI_avatar_handler::DoDelete() {
|
||||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||||
|
|
||||||
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
|
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT && Id != UserInfo_.userinfo.id) {
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
|
if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
|
Logger().information(fmt::format("Deleted avatar for {}", UserInfo_.userinfo.email));
|
||||||
StorageService()->UserDB().SetAvatar(Id,"");
|
StorageService()->UserDB().SetAvatar(Id, "");
|
||||||
OK();
|
OK();
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -3,51 +3,47 @@
|
|||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "Poco/Net/PartHandler.h"
|
||||||
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
class AvatarPartHandler : public Poco::Net::PartHandler {
|
class AvatarPartHandler : public Poco::Net::PartHandler {
|
||||||
public:
|
public:
|
||||||
AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
|
AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
|
||||||
Id_(std::move(Id)),
|
: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
|
||||||
Logger_(Logger),
|
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
|
||||||
OutputStream_(ofs){
|
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||||
}
|
[[nodiscard]] std::string &Name() { return Name_; }
|
||||||
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
|
[[nodiscard]] std::string &ContentType() { return FileType_; }
|
||||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
|
||||||
[[nodiscard]] std::string &Name() { return Name_; }
|
|
||||||
[[nodiscard]] std::string &ContentType() { return FileType_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t Length_ = 0;
|
uint64_t Length_ = 0;
|
||||||
std::string FileType_;
|
std::string FileType_;
|
||||||
std::string Name_;
|
std::string Name_;
|
||||||
std::string Id_;
|
std::string Id_;
|
||||||
Poco::Logger &Logger_;
|
Poco::Logger &Logger_;
|
||||||
std::stringstream &OutputStream_;
|
std::stringstream &OutputStream_;
|
||||||
|
|
||||||
inline Poco::Logger & Logger() { return Logger_; };
|
inline Poco::Logger &Logger() { return Logger_; };
|
||||||
};
|
};
|
||||||
|
|
||||||
class RESTAPI_avatar_handler : public RESTAPIHandler {
|
class RESTAPI_avatar_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_POST,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal) {}
|
||||||
Internal) {}
|
static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; };
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; };
|
|
||||||
|
|
||||||
void DoGet() final;
|
void DoGet() final;
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoDelete() final;
|
void DoDelete() final;
|
||||||
void DoPut() final {};
|
void DoPut() final{};
|
||||||
|
};
|
||||||
};
|
} // namespace OpenWifi
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,10 +8,15 @@
|
|||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) {
|
inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
|
||||||
U.currentPassword.clear();
|
SecurityObjects::UserInfo &U) {
|
||||||
U.lastPasswords.clear();
|
U.currentPassword.clear();
|
||||||
U.oauthType.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 "RESTAPI_email_handler.h"
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Exception.h"
|
|
||||||
#include "Poco/JSON/Parser.h"
|
#include "Poco/JSON/Parser.h"
|
||||||
|
|
||||||
#include "SMTPMailerService.h"
|
#include "SMTPMailerService.h"
|
||||||
#include "framework/ow_constants.h"
|
#include "framework/ow_constants.h"
|
||||||
#include "framework/MicroService.h"
|
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
void RESTAPI_email_handler::DoPost() {
|
void RESTAPI_email_handler::DoPost() {
|
||||||
const auto & Obj = ParsedBody_;
|
const auto &Obj = ParsedBody_;
|
||||||
if (Obj->has("subject") &&
|
if (Obj->has("subject") && Obj->has("from") && Obj->has("text") && Obj->has("recipients") &&
|
||||||
Obj->has("from") &&
|
Obj->isArray("recipients")) {
|
||||||
Obj->has("text") &&
|
|
||||||
Obj->has("recipients") &&
|
|
||||||
Obj->isArray("recipients")) {
|
|
||||||
|
|
||||||
Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
|
Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
|
||||||
auto Recipient = Recipients->get(0).toString();
|
auto Recipient = Recipients->get(0).toString();
|
||||||
MessageAttributes Attrs;
|
MessageAttributes Attrs;
|
||||||
Attrs[RECIPIENT_EMAIL] = Recipient;
|
Attrs[RECIPIENT_EMAIL] = Recipient;
|
||||||
Attrs[SUBJECT] = Obj->get("subject").toString();
|
Attrs[SUBJECT] = Obj->get("subject").toString();
|
||||||
Attrs[TEXT] = Obj->get("text").toString();
|
Attrs[TEXT] = Obj->get("text").toString();
|
||||||
Attrs[SENDER] = Obj->get("from").toString();
|
Attrs[SENDER] = Obj->get("from").toString();
|
||||||
if(SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs)) {
|
if (SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs, false)) {
|
||||||
return OK();
|
return OK();
|
||||||
}
|
}
|
||||||
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
|
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,22 +4,22 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_email_handler : public RESTAPIHandler {
|
class RESTAPI_email_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
: RESTAPIHandler(bindings, L,
|
||||||
Server,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
TransactionId,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
Internal) {}
|
Server, TransactionId, Internal) {}
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/email"};}
|
static auto PathName() { return std::list<std::string>{"/api/v1/email"}; }
|
||||||
void DoGet() final {};
|
void DoGet() final{};
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoDelete() final {};
|
void DoDelete() final{};
|
||||||
void DoPut() final {};
|
void DoPut() final{};
|
||||||
};
|
};
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -9,170 +9,176 @@
|
|||||||
#include "Poco/JSON/Parser.h"
|
#include "Poco/JSON/Parser.h"
|
||||||
|
|
||||||
#include "AuthService.h"
|
#include "AuthService.h"
|
||||||
#include "RESTAPI_oauth2_handler.h"
|
|
||||||
#include "MFAServer.h"
|
#include "MFAServer.h"
|
||||||
#include "framework/ow_constants.h"
|
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include "StorageService.h"
|
|
||||||
#include "RESTAPI_db_helpers.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 {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_oauth2_handler::DoGet() {
|
void RESTAPI_oauth2_handler::DoGet() {
|
||||||
bool Expired = false, Contacted = false;
|
bool Expired = false, Contacted = false;
|
||||||
if (!IsAuthorized(Expired, Contacted)) {
|
if (!IsAuthorized(Expired, Contacted)) {
|
||||||
if (Expired)
|
if (Expired)
|
||||||
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
|
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
|
||||||
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
|
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
|
||||||
}
|
}
|
||||||
if (GetBoolParameter(RESTAPI::Protocol::ME)) {
|
if (GetBoolParameter(RESTAPI::Protocol::ME)) {
|
||||||
Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
|
Logger_.information(fmt::format("REQUEST-ME({}): Request for {}",
|
||||||
UserInfo_.userinfo.email));
|
Request->clientAddress().toString(),
|
||||||
Poco::JSON::Object Me;
|
UserInfo_.userinfo.email));
|
||||||
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
|
Poco::JSON::Object Me;
|
||||||
Sanitize(UserInfo_, ReturnedUser);
|
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
|
||||||
ReturnedUser.to_json(Me);
|
Sanitize(UserInfo_, ReturnedUser);
|
||||||
return ReturnObject(Me);
|
ReturnedUser.to_json(Me);
|
||||||
}
|
return ReturnObject(Me);
|
||||||
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
|
}
|
||||||
}
|
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_oauth2_handler::DoDelete() {
|
void RESTAPI_oauth2_handler::DoDelete() {
|
||||||
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
|
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
|
||||||
std::string SessionToken;
|
std::string SessionToken;
|
||||||
try {
|
try {
|
||||||
Poco::Net::OAuth20Credentials Auth(*Request);
|
Poco::Net::OAuth20Credentials Auth(*Request);
|
||||||
if (Auth.getScheme() == "Bearer") {
|
if (Auth.getScheme() == "Bearer") {
|
||||||
SessionToken = Auth.getBearerToken();
|
SessionToken = Auth.getBearerToken();
|
||||||
}
|
}
|
||||||
} catch (const Poco::Exception &E) {
|
} catch (const Poco::Exception &E) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
if (Token.empty() || (Token != SessionToken)) {
|
if (Token.empty() || (Token != SessionToken)) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthService()->Logout(Token);
|
AuthService()->Logout(Token);
|
||||||
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_oauth2_handler::DoPost() {
|
void RESTAPI_oauth2_handler::DoPost() {
|
||||||
|
|
||||||
const auto & Obj = ParsedBody_;
|
const auto &Obj = ParsedBody_;
|
||||||
if(Obj == nullptr) {
|
if (Obj == nullptr) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
||||||
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
||||||
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
|
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
|
||||||
auto refreshToken = GetS("refreshToken", Obj);
|
auto refreshToken = GetS("refreshToken", Obj);
|
||||||
auto grant_type = GetParameter("grant_type");
|
auto grant_type = GetParameter("grant_type");
|
||||||
|
|
||||||
Poco::toLowerInPlace(userId);
|
Poco::toLowerInPlace(userId);
|
||||||
|
|
||||||
if(!refreshToken.empty() && grant_type == "refresh_token") {
|
if (!refreshToken.empty() && grant_type == "refresh_token") {
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
if(AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) {
|
if (AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) {
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
UInfo.webtoken.to_json(Answer);
|
UInfo.webtoken.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
} else {
|
} else {
|
||||||
return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
|
return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
|
if (GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
|
||||||
Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
|
Logger_.information(
|
||||||
Poco::JSON::Object Answer;
|
fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
|
||||||
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
|
Poco::JSON::Object Answer;
|
||||||
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
|
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN,
|
||||||
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
|
AuthService()->PasswordValidationExpression());
|
||||||
return ReturnObject(Answer);
|
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
|
||||||
}
|
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
|
if (GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
|
||||||
SecurityObjects::UserInfo UInfo1;
|
SecurityObjects::UserInfo UInfo1;
|
||||||
auto UserExists = StorageService()->UserDB().GetUserByEmail(userId,UInfo1);
|
auto UserExists = StorageService()->UserDB().GetUserByEmail(userId, UInfo1);
|
||||||
if(UserExists) {
|
if (UserExists) {
|
||||||
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
|
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
|
||||||
SecurityObjects::ActionLink NewLink;
|
Request->clientAddress().toString(), userId));
|
||||||
|
SecurityObjects::ActionLink NewLink;
|
||||||
|
|
||||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
|
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
|
||||||
NewLink.id = MicroService::CreateUUID();
|
NewLink.id = MicroService::CreateUUID();
|
||||||
NewLink.userId = UInfo1.id;
|
NewLink.userId = UInfo1.id;
|
||||||
NewLink.created = OpenWifi::Now();
|
NewLink.created = OpenWifi::Now();
|
||||||
NewLink.expires = NewLink.created + (24*60*60);
|
NewLink.expires = NewLink.created + (24 * 60 * 60);
|
||||||
NewLink.userAction = true;
|
NewLink.userAction = true;
|
||||||
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
||||||
|
|
||||||
Poco::JSON::Object ReturnObj;
|
Poco::JSON::Object ReturnObj;
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
UInfo.webtoken.userMustChangePassword = true;
|
UInfo.webtoken.userMustChangePassword = true;
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
return ReturnObject(ReturnObj);
|
return ReturnObject(ReturnObj);
|
||||||
} else {
|
} else {
|
||||||
Poco::JSON::Object ReturnObj;
|
Poco::JSON::Object ReturnObj;
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
UInfo.webtoken.userMustChangePassword = true;
|
UInfo.webtoken.userMustChangePassword = true;
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
return ReturnObject(ReturnObj);
|
return ReturnObject(ReturnObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
|
if (GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
|
||||||
Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId));
|
Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}",
|
||||||
if(Obj->has("uuid")) {
|
Request->clientAddress().toString(), userId));
|
||||||
auto uuid = Obj->get("uuid").toString();
|
if (Obj->has("uuid")) {
|
||||||
if(MFAServer()->ResendCode(uuid))
|
auto uuid = Obj->get("uuid").toString();
|
||||||
return OK();
|
if (MFAServer()->ResendCode(uuid))
|
||||||
}
|
return OK();
|
||||||
return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
|
}
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
|
||||||
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
|
if (GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE, false)) {
|
||||||
Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId));
|
Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}",
|
||||||
if(Obj->has("uuid")) {
|
Request->clientAddress().toString(), userId));
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
if (Obj->has("uuid")) {
|
||||||
if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) {
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
Poco::JSON::Object ReturnObj;
|
if (MFAServer()->CompleteMFAChallenge(Obj, UInfo)) {
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
Poco::JSON::Object ReturnObj;
|
||||||
return ReturnObject(ReturnObj);
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
}
|
return ReturnObject(ReturnObj);
|
||||||
}
|
}
|
||||||
return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
|
}
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
bool Expired=false;
|
bool Expired = false;
|
||||||
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
|
auto Code = AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
|
||||||
if (Code==SUCCESS) {
|
switch (Code) {
|
||||||
Poco::JSON::Object ReturnObj;
|
case SUCCESS: {
|
||||||
if(AuthService()->RequiresMFA(UInfo)) {
|
Poco::JSON::Object ReturnObj;
|
||||||
if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
|
if (AuthService()->RequiresMFA(UInfo)) {
|
||||||
return ReturnObject(ReturnObj);
|
if (MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
|
||||||
}
|
return ReturnObject(ReturnObj);
|
||||||
Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
|
}
|
||||||
}
|
Logger_.warning(
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
"MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
|
||||||
return ReturnObject(ReturnObj);
|
}
|
||||||
} else {
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
|
return ReturnObject(ReturnObj);
|
||||||
switch(Code) {
|
}
|
||||||
case INVALID_CREDENTIALS:
|
case INVALID_CREDENTIALS:
|
||||||
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
||||||
case PASSWORD_INVALID:
|
case PASSWORD_INVALID:
|
||||||
return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
|
return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
|
||||||
case PASSWORD_ALREADY_USED:
|
case PASSWORD_ALREADY_USED:
|
||||||
return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
|
return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
|
||||||
case USERNAME_PENDING_VERIFICATION:
|
case USERNAME_PENDING_VERIFICATION:
|
||||||
return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
|
return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
|
||||||
case PASSWORD_CHANGE_REQUIRED:
|
case PASSWORD_CHANGE_REQUIRED:
|
||||||
return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
|
return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
|
||||||
default:
|
case ACCOUNT_SUSPENDED:
|
||||||
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
|
||||||
}
|
default:
|
||||||
return;
|
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -7,26 +7,27 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_oauth2_handler : public RESTAPIHandler {
|
class RESTAPI_oauth2_handler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
Server,
|
Server, TransactionId, Internal, false, true,
|
||||||
TransactionId,
|
RateLimit{.Interval = 1000, .MaxCalls = 10}) {}
|
||||||
Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {}
|
static auto PathName() {
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
|
return std::list<std::string>{"/api/v1/oauth2/{token}", "/api/v1/oauth2"};
|
||||||
|
};
|
||||||
void DoGet() final;
|
void DoGet() final;
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoDelete() final;
|
void DoDelete() final;
|
||||||
void DoPut() final {};
|
void DoPut() final{};
|
||||||
};
|
};
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,30 +7,30 @@
|
|||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_preferences::DoGet() {
|
void RESTAPI_preferences::DoGet() {
|
||||||
SecurityObjects::Preferences P;
|
SecurityObjects::Preferences P;
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
|
StorageService()->PreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
|
||||||
P.to_json(Answer);
|
P.to_json(Answer);
|
||||||
ReturnObject(Answer);
|
ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_preferences::DoPut() {
|
void RESTAPI_preferences::DoPut() {
|
||||||
|
|
||||||
SecurityObjects::Preferences P;
|
SecurityObjects::Preferences P;
|
||||||
|
|
||||||
const auto & RawObject = ParsedBody_;
|
const auto &RawObject = ParsedBody_;
|
||||||
if(!P.from_json(RawObject)) {
|
if (!P.from_json(RawObject)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
P.id = UserInfo_.userinfo.id;
|
P.id = UserInfo_.userinfo.id;
|
||||||
P.modified = OpenWifi::Now();
|
P.modified = OpenWifi::Now();
|
||||||
StorageService()->PreferencesDB().SetPreferences(P);
|
StorageService()->PreferencesDB().SetPreferences(P);
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
P.to_json(Answer);
|
P.to_json(Answer);
|
||||||
ReturnObject(Answer);
|
ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,24 +4,23 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_preferences : public RESTAPIHandler {
|
class RESTAPI_preferences : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal) {}
|
||||||
Internal) {}
|
static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; };
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; };
|
void DoGet() final;
|
||||||
void DoGet() final;
|
void DoPut() final;
|
||||||
void DoPut() final;
|
void DoPost() final{};
|
||||||
void DoPost() final {};
|
void DoDelete() final{};
|
||||||
void DoDelete() final {};
|
};
|
||||||
};
|
} // namespace OpenWifi
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,88 +1,67 @@
|
|||||||
//
|
//
|
||||||
// Created by stephane bourque on 2021-10-23.
|
// 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_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_asset_server.h"
|
||||||
#include "RESTAPI/RESTAPI_avatar_handler.h"
|
#include "RESTAPI/RESTAPI_avatar_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_subavatar_handler.h"
|
|
||||||
#include "RESTAPI/RESTAPI_email_handler.h"
|
#include "RESTAPI/RESTAPI_email_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_sms_handler.h"
|
#include "RESTAPI/RESTAPI_oauth2_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_validate_token_handler.h"
|
|
||||||
#include "RESTAPI/RESTAPI_preferences.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_suboauth2_handler.h"
|
||||||
|
#include "RESTAPI/RESTAPI_subpreferences.h"
|
||||||
|
#include "RESTAPI/RESTAPI_subtotp_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_subuser_handler.h"
|
#include "RESTAPI/RESTAPI_subuser_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_subusers_handler.h"
|
#include "RESTAPI/RESTAPI_subusers_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
|
#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_submfa_handler.h"
|
|
||||||
#include "RESTAPI/RESTAPI_totp_handler.h"
|
#include "RESTAPI/RESTAPI_totp_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_subtotp_handler.h"
|
#include "RESTAPI/RESTAPI_user_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_signup_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 {
|
namespace OpenWifi {
|
||||||
|
|
||||||
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
Poco::Net::HTTPRequestHandler *
|
||||||
Poco::Logger & L, RESTAPI_GenericServer & S,
|
RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||||
uint64_t TransactionId) {
|
Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
|
||||||
return RESTAPI_Router<
|
return RESTAPI_Router<
|
||||||
RESTAPI_oauth2_handler,
|
RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
|
||||||
RESTAPI_user_handler,
|
RESTAPI_system_command, RESTAPI_system_configuration, RESTAPI_asset_server, RESTAPI_system_endpoints_handler,
|
||||||
RESTAPI_users_handler,
|
RESTAPI_action_links, RESTAPI_avatar_handler, RESTAPI_subavatar_handler,
|
||||||
RESTAPI_system_command,
|
RESTAPI_email_handler, RESTAPI_sms_handler, RESTAPI_preferences, RESTAPI_subpreferences,
|
||||||
RESTAPI_asset_server,
|
RESTAPI_suboauth2_handler, RESTAPI_subuser_handler, RESTAPI_subusers_handler,
|
||||||
RESTAPI_system_endpoints_handler,
|
RESTAPI_submfa_handler, RESTAPI_totp_handler, RESTAPI_subtotp_handler,
|
||||||
RESTAPI_action_links,
|
RESTAPI_signup_handler, RESTAPI_validate_sub_token_handler,
|
||||||
RESTAPI_avatar_handler,
|
RESTAPI_validate_token_handler, RESTAPI_validate_apikey, RESTAPI_webSocketServer,
|
||||||
RESTAPI_subavatar_handler,
|
RESTAPI_apiKey_handler, RESTAPI_systemSecret_handler>(Path, Bindings, L, S,
|
||||||
RESTAPI_email_handler,
|
TransactionId);
|
||||||
RESTAPI_sms_handler,
|
}
|
||||||
RESTAPI_preferences,
|
|
||||||
RESTAPI_subpreferences,
|
|
||||||
RESTAPI_suboauth2_handler,
|
|
||||||
RESTAPI_subuser_handler,
|
|
||||||
RESTAPI_subusers_handler,
|
|
||||||
RESTAPI_submfa_handler,
|
|
||||||
RESTAPI_totp_handler,
|
|
||||||
RESTAPI_subtotp_handler,
|
|
||||||
RESTAPI_signup_handler,
|
|
||||||
RESTAPI_validate_sub_token_handler,
|
|
||||||
RESTAPI_validate_token_handler
|
|
||||||
>(Path, Bindings, L, S,TransactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
Poco::Net::HTTPRequestHandler *
|
||||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||||
|
Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
|
||||||
|
|
||||||
return RESTAPI_Router_I<
|
return RESTAPI_Router_I<
|
||||||
RESTAPI_oauth2_handler,
|
RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
|
||||||
RESTAPI_user_handler,
|
RESTAPI_system_command, RESTAPI_system_configuration, RESTAPI_asset_server, RESTAPI_system_endpoints_handler,
|
||||||
RESTAPI_users_handler,
|
RESTAPI_action_links, RESTAPI_avatar_handler, RESTAPI_subavatar_handler,
|
||||||
RESTAPI_system_command,
|
RESTAPI_email_handler, RESTAPI_sms_handler, RESTAPI_preferences, RESTAPI_subpreferences,
|
||||||
RESTAPI_asset_server,
|
RESTAPI_suboauth2_handler, RESTAPI_subuser_handler, RESTAPI_subusers_handler,
|
||||||
RESTAPI_system_endpoints_handler,
|
RESTAPI_submfa_handler, RESTAPI_totp_handler, RESTAPI_subtotp_handler,
|
||||||
RESTAPI_action_links,
|
RESTAPI_validate_sub_token_handler, RESTAPI_validate_token_handler,
|
||||||
RESTAPI_avatar_handler,
|
RESTAPI_validate_apikey, RESTAPI_signup_handler, RESTAPI_systemSecret_handler>(
|
||||||
RESTAPI_subavatar_handler,
|
Path, Bindings, L, S, TransactionId);
|
||||||
RESTAPI_email_handler,
|
}
|
||||||
RESTAPI_sms_handler,
|
} // namespace OpenWifi
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,72 +3,74 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "RESTAPI_signup_handler.h"
|
#include "RESTAPI_signup_handler.h"
|
||||||
#include "StorageService.h"
|
|
||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||||
|
#include "StorageService.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
#define __DBG__ std::cout << __LINE__ << std::endl;
|
#define __DBG__ std::cout << __LINE__ << std::endl;
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_signup_handler::DoPost() {
|
void RESTAPI_signup_handler::DoPost() {
|
||||||
auto UserName = GetParameter("email");
|
auto UserName = GetParameter("email");
|
||||||
auto signupUUID = GetParameter("signupUUID");
|
auto signupUUID = GetParameter("signupUUID");
|
||||||
auto owner = GetParameter("owner");
|
auto owner = GetParameter("owner");
|
||||||
auto operatorName = GetParameter("operatorName");
|
auto operatorName = GetParameter("operatorName");
|
||||||
if(UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) {
|
if (UserName.empty() || signupUUID.empty() || owner.empty() || operatorName.empty()) {
|
||||||
Logger().error("Signup requires: email, signupUUID, operatorName, and owner.");
|
Logger().error("Signup requires: email, signupUUID, operatorName, and owner.");
|
||||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Utils::ValidEMailAddress(UserName)) {
|
if (!Utils::ValidEMailAddress(UserName)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
|
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we already exist? Can only signup once...
|
// Do we already exist? Can only signup once...
|
||||||
SecurityObjects::UserInfo Existing;
|
SecurityObjects::UserInfo Existing;
|
||||||
if(StorageService()->SubDB().GetUserByEmail(UserName,Existing)) {
|
if (StorageService()->SubDB().GetUserByEmail(UserName, Existing)) {
|
||||||
if(Existing.signingUp.empty()) {
|
if (Existing.signingUp.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::SignupAlreadySigned);
|
return BadRequest(RESTAPI::Errors::SignupAlreadySigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Existing.waitingForEmailCheck) {
|
if (Existing.waitingForEmailCheck) {
|
||||||
return BadRequest(RESTAPI::Errors::SignupEmailCheck);
|
return BadRequest(RESTAPI::Errors::SignupEmailCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BadRequest(RESTAPI::Errors::SignupWaitingForDevice);
|
return BadRequest(RESTAPI::Errors::SignupWaitingForDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfo NewSub;
|
SecurityObjects::UserInfo NewSub;
|
||||||
NewSub.signingUp = operatorName + ":" + signupUUID;
|
NewSub.signingUp = operatorName + ":" + signupUUID;
|
||||||
NewSub.waitingForEmailCheck = true;
|
NewSub.waitingForEmailCheck = true;
|
||||||
NewSub.name = UserName;
|
NewSub.name = UserName;
|
||||||
NewSub.modified = OpenWifi::Now();
|
NewSub.modified = OpenWifi::Now();
|
||||||
NewSub.creationDate = OpenWifi::Now();
|
NewSub.creationDate = OpenWifi::Now();
|
||||||
NewSub.id = MicroService::instance().CreateUUID();
|
NewSub.id = MicroServiceCreateUUID();
|
||||||
NewSub.email = UserName;
|
NewSub.email = UserName;
|
||||||
NewSub.userRole = SecurityObjects::SUBSCRIBER;
|
NewSub.userRole = SecurityObjects::SUBSCRIBER;
|
||||||
NewSub.changePassword = true;
|
NewSub.changePassword = true;
|
||||||
NewSub.owner = owner;
|
NewSub.owner = owner;
|
||||||
|
|
||||||
StorageService()->SubDB().CreateRecord(NewSub);
|
StorageService()->SubDB().CreateRecord(NewSub);
|
||||||
|
|
||||||
Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName));
|
Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}",
|
||||||
SecurityObjects::ActionLink NewLink;
|
Request->clientAddress().toString(), UserName));
|
||||||
|
SecurityObjects::ActionLink NewLink;
|
||||||
|
|
||||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
|
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
|
||||||
NewLink.id = MicroService::CreateUUID();
|
NewLink.id = MicroServiceCreateUUID();
|
||||||
NewLink.userId = NewSub.id;
|
NewLink.userId = NewSub.id;
|
||||||
NewLink.created = OpenWifi::Now();
|
NewLink.created = OpenWifi::Now();
|
||||||
NewLink.expires = NewLink.created + (1*60*60); // 1 hour
|
NewLink.expires = NewLink.created + (1 * 60 * 60); // 1 hour
|
||||||
NewLink.userAction = false;
|
NewLink.userAction = false;
|
||||||
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
NewSub.to_json(Answer);
|
NewSub.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_signup_handler::DoPut() {
|
void RESTAPI_signup_handler::DoPut() {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,36 +4,35 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_signup_handler : public RESTAPIHandler {
|
class RESTAPI_signup_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_POST,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_PUT},
|
Poco::Net::HTTPRequest::HTTP_OPTIONS,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_PUT},
|
||||||
TransactionId,
|
Server, TransactionId, Internal, false, true) {}
|
||||||
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) {
|
/* inline bool RoleIsAuthorized(std::string & Reason) {
|
||||||
if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) {
|
if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) {
|
||||||
Reason = "User must be a subscriber";
|
Reason = "User must be a subscriber";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
void DoGet() final {};
|
void DoGet() final{};
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoPut() final ;
|
void DoPut() final;
|
||||||
void DoDelete() final {};
|
void DoDelete() final{};
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
private:
|
||||||
}
|
};
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -5,55 +5,53 @@
|
|||||||
#include "RESTAPI_sms_handler.h"
|
#include "RESTAPI_sms_handler.h"
|
||||||
#include "SMSSender.h"
|
#include "SMSSender.h"
|
||||||
#include "framework/ow_constants.h"
|
#include "framework/ow_constants.h"
|
||||||
#include "framework/MicroService.h"
|
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void OpenWifi::RESTAPI_sms_handler::DoPost() {
|
void OpenWifi::RESTAPI_sms_handler::DoPost() {
|
||||||
const auto &Obj = ParsedBody_;
|
const auto &Obj = ParsedBody_;
|
||||||
|
|
||||||
if(!SMSSender()->Enabled()) {
|
if (!SMSSender()->Enabled()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Arg;
|
std::string Arg;
|
||||||
if(HasParameter("validateNumber",Arg) && Arg=="true" && Obj->has("to")) {
|
if (HasParameter("validateNumber", Arg) && Arg == "true" && Obj->has("to")) {
|
||||||
auto Number = Obj->get("to").toString();
|
auto Number = Obj->get("to").toString();
|
||||||
if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
|
if (SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
|
||||||
return OK();
|
return OK();
|
||||||
}
|
}
|
||||||
return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Code;
|
std::string Code;
|
||||||
if( HasParameter("completeValidation",Arg) &&
|
if (HasParameter("completeValidation", Arg) && Arg == "true" &&
|
||||||
Arg=="true" &&
|
HasParameter("validationCode", Code) && Obj->has("to")) {
|
||||||
HasParameter("validationCode", Code) &&
|
auto Number = Obj->get("to").toString();
|
||||||
Obj->has("to")) {
|
if (SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
|
||||||
auto Number = Obj->get("to").toString();
|
return OK();
|
||||||
if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
|
}
|
||||||
return OK();
|
return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
|
||||||
}
|
}
|
||||||
return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT &&
|
if(Internal_) {
|
||||||
UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER &&
|
poco_information(Logger(),fmt::format("Internal SMS request: TID={}", TransactionId_));
|
||||||
UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
|
} else if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
UserInfo_.userinfo.userRole != SecurityObjects::PARTNER &&
|
||||||
}
|
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
|
||||||
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
if (Obj->has("to") &&
|
if (Obj->has("to") && Obj->has("text")) {
|
||||||
Obj->has("text")) {
|
|
||||||
|
|
||||||
std::string PhoneNumber = Obj->get("to").toString();
|
std::string PhoneNumber = Obj->get("to").toString();
|
||||||
std::string Text = Obj->get("text").toString();
|
std::string Text = Obj->get("text").toString();
|
||||||
if(SMSSender()->Send(PhoneNumber, Text))
|
if (SMSSender()->Send(PhoneNumber, Text))
|
||||||
return OK();
|
return OK();
|
||||||
|
|
||||||
return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
|
||||||
}
|
}
|
||||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,22 +4,22 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_sms_handler : public RESTAPIHandler {
|
class RESTAPI_sms_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
: RESTAPIHandler(bindings, L,
|
||||||
Server,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
TransactionId,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
Internal) {}
|
Server, TransactionId, Internal) {}
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/sms"};}
|
static auto PathName() { return std::list<std::string>{"/api/v1/sms"}; }
|
||||||
void DoGet() final {};
|
void DoGet() final{};
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoDelete() final {};
|
void DoDelete() final{};
|
||||||
void DoPut() final {};
|
void DoPut() final{};
|
||||||
};
|
};
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -5,77 +5,84 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Poco/CountingStream.h"
|
||||||
|
#include "Poco/Net/HTMLForm.h"
|
||||||
#include "RESTAPI_subavatar_handler.h"
|
#include "RESTAPI_subavatar_handler.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
#include "Poco/Net/HTMLForm.h"
|
#include "framework/MicroServiceFuncs.h"
|
||||||
#include "framework/MicroService.h"
|
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
|
void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header,
|
||||||
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
|
std::istream &Stream) {
|
||||||
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
|
FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
|
||||||
std::string Disposition;
|
if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
|
||||||
Poco::Net::NameValueCollection Parameters;
|
std::string Disposition;
|
||||||
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
|
Poco::Net::NameValueCollection Parameters;
|
||||||
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
|
Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION],
|
||||||
}
|
Disposition, Parameters);
|
||||||
Poco::CountingInputStream InputStream(Stream);
|
Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
|
||||||
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
|
}
|
||||||
Length_ = OutputStream_.str().size();
|
Poco::CountingInputStream InputStream(Stream);
|
||||||
};
|
Poco::StreamCopier::copyStream(InputStream, OutputStream_);
|
||||||
|
Length_ = OutputStream_.str().size();
|
||||||
|
};
|
||||||
|
|
||||||
void RESTAPI_subavatar_handler::DoPost() {
|
void RESTAPI_subavatar_handler::DoPost() {
|
||||||
std::string Id = UserInfo_.userinfo.id;
|
std::string Id = UserInfo_.userinfo.id;
|
||||||
SecurityObjects::UserInfo UInfo;
|
SecurityObjects::UserInfo UInfo;
|
||||||
|
|
||||||
std::stringstream SS;
|
std::stringstream SS;
|
||||||
SubAvatarPartHandler partHandler(Id, Logger_, SS);
|
SubAvatarPartHandler partHandler(Id, Logger_, SS);
|
||||||
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
|
Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
|
|
||||||
if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
|
if (!partHandler.Name().empty() &&
|
||||||
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
partHandler.Length() < MicroServiceConfigGetInt("openwifi.avatar.maxsize", 2000000)) {
|
||||||
Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
|
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
||||||
Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
|
Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
|
||||||
StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email,
|
Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(),
|
||||||
Id, SS.str(), partHandler.ContentType(), partHandler.Name());
|
partHandler.ContentType()));
|
||||||
StorageService()->SubDB().SetAvatar(Id,"1");
|
StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, SS.str(),
|
||||||
Logger().information(fmt::format("Adding avatar for {}",UserInfo_.userinfo.email));
|
partHandler.ContentType(),
|
||||||
} else {
|
partHandler.Name());
|
||||||
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
StorageService()->SubDB().SetAvatar(Id, "1");
|
||||||
Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
|
Logger().information(fmt::format("Adding avatar for {}", UserInfo_.userinfo.email));
|
||||||
Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
|
} else {
|
||||||
}
|
Answer.set(RESTAPI::Protocol::AVATARID, Id);
|
||||||
ReturnObject(Answer);
|
Answer.set(RESTAPI::Protocol::ERRORCODE, 13);
|
||||||
}
|
Answer.set(RESTAPI::Protocol::ERRORTEXT, "Avatar upload could not complete.");
|
||||||
|
}
|
||||||
|
ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_subavatar_handler::DoGet() {
|
void RESTAPI_subavatar_handler::DoGet() {
|
||||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||||
if (Id.empty()) {
|
if (Id.empty()) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Type, Name, AvatarContent;
|
std::string Type, Name, AvatarContent;
|
||||||
if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent, Type, Name)) {
|
if (!StorageService()->SubAvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, AvatarContent,
|
||||||
return NotFound();
|
Type, Name)) {
|
||||||
}
|
return NotFound();
|
||||||
Logger().information(fmt::format("Retrieving avatar for {}",UserInfo_.userinfo.email));
|
}
|
||||||
return SendFileContent(AvatarContent, Type, Name);
|
Logger().information(fmt::format("Retrieving avatar for {}", UserInfo_.userinfo.email));
|
||||||
}
|
return SendFileContent(AvatarContent, Type, Name);
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_subavatar_handler::DoDelete() {
|
void RESTAPI_subavatar_handler::DoDelete() {
|
||||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||||
|
|
||||||
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && Id!=UserInfo_.userinfo.id) {
|
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT && Id != UserInfo_.userinfo.id) {
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
|
if (!StorageService()->SubAvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
Logger().information(fmt::format("Deleted avatar for {}",UserInfo_.userinfo.email));
|
Logger().information(fmt::format("Deleted avatar for {}", UserInfo_.userinfo.email));
|
||||||
StorageService()->SubDB().SetAvatar(Id,"");
|
StorageService()->SubDB().SetAvatar(Id, "");
|
||||||
OK();
|
OK();
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -3,51 +3,47 @@
|
|||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "Poco/Net/PartHandler.h"
|
||||||
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
class SubAvatarPartHandler : public Poco::Net::PartHandler {
|
class SubAvatarPartHandler : public Poco::Net::PartHandler {
|
||||||
public:
|
public:
|
||||||
SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
|
SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
|
||||||
Id_(std::move(Id)),
|
: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
|
||||||
Logger_(Logger),
|
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
|
||||||
OutputStream_(ofs){
|
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||||
}
|
[[nodiscard]] std::string &Name() { return Name_; }
|
||||||
void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
|
[[nodiscard]] std::string &ContentType() { return FileType_; }
|
||||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
|
||||||
[[nodiscard]] std::string &Name() { return Name_; }
|
|
||||||
[[nodiscard]] std::string &ContentType() { return FileType_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t Length_ = 0;
|
uint64_t Length_ = 0;
|
||||||
std::string FileType_;
|
std::string FileType_;
|
||||||
std::string Name_;
|
std::string Name_;
|
||||||
std::string Id_;
|
std::string Id_;
|
||||||
Poco::Logger &Logger_;
|
Poco::Logger &Logger_;
|
||||||
std::stringstream &OutputStream_;
|
std::stringstream &OutputStream_;
|
||||||
|
|
||||||
inline Poco::Logger & Logger() { return Logger_; }
|
inline Poco::Logger &Logger() { return Logger_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class RESTAPI_subavatar_handler : public RESTAPIHandler {
|
class RESTAPI_subavatar_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_POST,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal) {}
|
||||||
Internal) {}
|
static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; };
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; };
|
|
||||||
|
|
||||||
void DoGet() final;
|
void DoGet() final;
|
||||||
void DoPost() final;
|
void DoPost() final;
|
||||||
void DoDelete() final;
|
void DoDelete() final;
|
||||||
void DoPut() final {};
|
void DoPut() final{};
|
||||||
|
};
|
||||||
};
|
} // namespace OpenWifi
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,135 +3,140 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "RESTAPI_submfa_handler.h"
|
#include "RESTAPI_submfa_handler.h"
|
||||||
#include "StorageService.h"
|
|
||||||
#include "SMSSender.h"
|
#include "SMSSender.h"
|
||||||
|
#include "StorageService.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_submfa_handler::DoGet() {
|
void RESTAPI_submfa_handler::DoGet() {
|
||||||
SecurityObjects::UserInfo User;
|
SecurityObjects::UserInfo User;
|
||||||
|
|
||||||
if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) {
|
if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User)) {
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
SecurityObjects::SubMfaConfig MFC;
|
SecurityObjects::SubMfaConfig MFC;
|
||||||
|
|
||||||
MFC.id = User.id;
|
MFC.id = User.id;
|
||||||
if(User.userTypeProprietaryInfo.mfa.enabled) {
|
if (User.userTypeProprietaryInfo.mfa.enabled) {
|
||||||
if(User.userTypeProprietaryInfo.mfa.method == "sms") {
|
if (User.userTypeProprietaryInfo.mfa.method == "sms") {
|
||||||
MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
|
MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
|
||||||
MFC.type = "sms";
|
MFC.type = "sms";
|
||||||
} else if(User.userTypeProprietaryInfo.mfa.method == "email") {
|
} else if (User.userTypeProprietaryInfo.mfa.method == "email") {
|
||||||
MFC.email = User.email;
|
MFC.email = User.email;
|
||||||
MFC.type = "email";
|
MFC.type = "email";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MFC.type = "disabled";
|
MFC.type = "disabled";
|
||||||
}
|
}
|
||||||
MFC.to_json(Answer);
|
MFC.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
NotFound();
|
NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_submfa_handler::DoPut() {
|
void RESTAPI_submfa_handler::DoPut() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const auto & Body = ParsedBody_;
|
const auto &Body = ParsedBody_;
|
||||||
|
|
||||||
SecurityObjects::SubMfaConfig MFC;
|
SecurityObjects::SubMfaConfig MFC;
|
||||||
|
|
||||||
if (!MFC.from_json(Body)) {
|
if (!MFC.from_json(Body)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MFC.type == "disabled") {
|
if (MFC.type == "disabled") {
|
||||||
SecurityObjects::UserInfo User;
|
SecurityObjects::UserInfo User;
|
||||||
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
|
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
|
||||||
User.userTypeProprietaryInfo.mfa.enabled = false;
|
User.userTypeProprietaryInfo.mfa.enabled = false;
|
||||||
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
|
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
|
||||||
|
UserInfo_.userinfo.id, User);
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
MFC.to_json(Answer);
|
MFC.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
} else if (MFC.type == "email") {
|
} else if (MFC.type == "email") {
|
||||||
SecurityObjects::UserInfo User;
|
SecurityObjects::UserInfo User;
|
||||||
|
|
||||||
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
|
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
|
||||||
User.userTypeProprietaryInfo.mfa.enabled = true;
|
User.userTypeProprietaryInfo.mfa.enabled = true;
|
||||||
User.userTypeProprietaryInfo.mfa.method = "email";
|
User.userTypeProprietaryInfo.mfa.method = "email";
|
||||||
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.sms = MFC.sms;
|
||||||
MFC.type = "email";
|
MFC.type = "email";
|
||||||
MFC.email = UserInfo_.userinfo.email;
|
MFC.email = UserInfo_.userinfo.email;
|
||||||
MFC.id = MicroService::instance().CreateUUID();
|
MFC.id = MicroServiceCreateUUID();
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
MFC.to_json(Answer);
|
MFC.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
|
|
||||||
} else if (MFC.type == "sms") {
|
} else if (MFC.type == "sms") {
|
||||||
if (GetBoolParameter("startValidation", false)) {
|
if (GetBoolParameter("startValidation", false)) {
|
||||||
if (MFC.sms.empty()) {
|
if (MFC.sms.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
|
return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!SMSSender()->Enabled()) {
|
if (!SMSSender()->Enabled()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
|
if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
|
||||||
return OK();
|
return OK();
|
||||||
} else {
|
} else {
|
||||||
return InternalError(RESTAPI::Errors::SMSTryLater);
|
return InternalError(RESTAPI::Errors::SMSTryLater);
|
||||||
}
|
}
|
||||||
} else if (GetBoolParameter("completeValidation", false)) {
|
} else if (GetBoolParameter("completeValidation", false)) {
|
||||||
|
|
||||||
if(!SMSSender()->Enabled()) {
|
if (!SMSSender()->Enabled()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ChallengeCode = GetParameter("challengeCode", "");
|
auto ChallengeCode = GetParameter("challengeCode", "");
|
||||||
if (ChallengeCode.empty()) {
|
if (ChallengeCode.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMissingChallenge);
|
return BadRequest(RESTAPI::Errors::SMSMissingChallenge);
|
||||||
}
|
}
|
||||||
if (MFC.sms.empty()) {
|
if (MFC.sms.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
|
return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
|
||||||
}
|
}
|
||||||
if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) {
|
if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode,
|
||||||
SecurityObjects::UserInfo User;
|
UserInfo_.userinfo.email)) {
|
||||||
|
SecurityObjects::UserInfo User;
|
||||||
|
|
||||||
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
|
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
|
||||||
User.userTypeProprietaryInfo.mfa.enabled = true;
|
User.userTypeProprietaryInfo.mfa.enabled = true;
|
||||||
User.userTypeProprietaryInfo.mfa.method = "sms";
|
User.userTypeProprietaryInfo.mfa.method = "sms";
|
||||||
SecurityObjects::MobilePhoneNumber PhoneNumber;
|
SecurityObjects::MobilePhoneNumber PhoneNumber;
|
||||||
PhoneNumber.number = MFC.sms;
|
PhoneNumber.number = MFC.sms;
|
||||||
PhoneNumber.primary = true;
|
PhoneNumber.primary = true;
|
||||||
PhoneNumber.verified = true;
|
PhoneNumber.verified = true;
|
||||||
User.userTypeProprietaryInfo.mobiles.clear();
|
User.userTypeProprietaryInfo.mobiles.clear();
|
||||||
User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
|
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.sms = MFC.sms;
|
||||||
MFC.type = "sms";
|
MFC.type = "sms";
|
||||||
MFC.email = UserInfo_.userinfo.email;
|
MFC.email = UserInfo_.userinfo.email;
|
||||||
MFC.id = MicroService::instance().CreateUUID();
|
MFC.id = MicroServiceCreateUUID();
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
MFC.to_json(Answer);
|
MFC.to_json(Answer);
|
||||||
|
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return InternalError(RESTAPI::Errors::SMSTryLater);
|
return InternalError(RESTAPI::Errors::SMSTryLater);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const Poco::Exception &E) {
|
} catch (const Poco::Exception &E) {
|
||||||
Logger_.log(E);
|
Logger_.log(E);
|
||||||
}
|
}
|
||||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -4,24 +4,24 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_submfa_handler : public RESTAPIHandler {
|
class RESTAPI_submfa_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
TransactionId,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10},
|
Server, TransactionId, Internal, true, false,
|
||||||
true) {}
|
RateLimit{.Interval = 1000, .MaxCalls = 10}, true) {}
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; };
|
static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; };
|
||||||
void DoGet() final;
|
void DoGet() final;
|
||||||
void DoPost() final {};
|
void DoPost() final{};
|
||||||
void DoDelete() final {};
|
void DoDelete() final{};
|
||||||
void DoPut() final ;
|
void DoPut() final;
|
||||||
};
|
};
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -5,161 +5,167 @@
|
|||||||
#include "RESTAPI_suboauth2_handler.h"
|
#include "RESTAPI_suboauth2_handler.h"
|
||||||
#include "AuthService.h"
|
#include "AuthService.h"
|
||||||
#include "MFAServer.h"
|
#include "MFAServer.h"
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include "StorageService.h"
|
|
||||||
#include "RESTAPI/RESTAPI_db_helpers.h"
|
#include "RESTAPI/RESTAPI_db_helpers.h"
|
||||||
|
#include "StorageService.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_suboauth2_handler::DoGet() {
|
void RESTAPI_suboauth2_handler::DoGet() {
|
||||||
bool Expired = false, Contacted = false;
|
bool Expired = false, Contacted = false;
|
||||||
if (!IsAuthorized(Expired, Contacted, true)) {
|
if (!IsAuthorized(Expired, Contacted, true)) {
|
||||||
if(Expired)
|
if (Expired)
|
||||||
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
|
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
|
||||||
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
|
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
|
||||||
}
|
}
|
||||||
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
|
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
|
||||||
if(GetMe) {
|
if (GetMe) {
|
||||||
Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
|
Logger_.information(fmt::format("REQUEST-ME({}): Request for {}",
|
||||||
UserInfo_.userinfo.email));
|
Request->clientAddress().toString(),
|
||||||
Poco::JSON::Object Me;
|
UserInfo_.userinfo.email));
|
||||||
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
|
Poco::JSON::Object Me;
|
||||||
Sanitize(UserInfo_, ReturnedUser);
|
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
|
||||||
ReturnedUser.to_json(Me);
|
Sanitize(UserInfo_, ReturnedUser);
|
||||||
return ReturnObject(Me);
|
ReturnedUser.to_json(Me);
|
||||||
}
|
return ReturnObject(Me);
|
||||||
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
|
}
|
||||||
}
|
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_suboauth2_handler::DoDelete() {
|
void RESTAPI_suboauth2_handler::DoDelete() {
|
||||||
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
|
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "");
|
||||||
std::string SessionToken;
|
std::string SessionToken;
|
||||||
try {
|
try {
|
||||||
Poco::Net::OAuth20Credentials Auth(*Request);
|
Poco::Net::OAuth20Credentials Auth(*Request);
|
||||||
if (Auth.getScheme() == "Bearer") {
|
if (Auth.getScheme() == "Bearer") {
|
||||||
SessionToken = Auth.getBearerToken();
|
SessionToken = Auth.getBearerToken();
|
||||||
}
|
}
|
||||||
} catch (const Poco::Exception &E) {
|
} catch (const Poco::Exception &E) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
if (Token.empty() || (Token != SessionToken)) {
|
if (Token.empty() || (Token != SessionToken)) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
}
|
}
|
||||||
AuthService()->SubLogout(Token);
|
AuthService()->SubLogout(Token);
|
||||||
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_suboauth2_handler::DoPost() {
|
void RESTAPI_suboauth2_handler::DoPost() {
|
||||||
const auto & Obj = ParsedBody_;
|
const auto &Obj = ParsedBody_;
|
||||||
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
||||||
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
||||||
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
|
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
|
||||||
auto refreshToken = GetS("refreshToken", Obj);
|
auto refreshToken = GetS("refreshToken", Obj);
|
||||||
auto grant_type = GetParameter("grant_type");
|
auto grant_type = GetParameter("grant_type");
|
||||||
|
|
||||||
Poco::toLowerInPlace(userId);
|
Poco::toLowerInPlace(userId);
|
||||||
|
|
||||||
if(!refreshToken.empty() && grant_type == "refresh_token") {
|
if (!refreshToken.empty() && grant_type == "refresh_token") {
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
if(AuthService()->RefreshSubToken(*Request, refreshToken, UInfo)) {
|
if (AuthService()->RefreshSubToken(*Request, refreshToken, UInfo)) {
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
UInfo.webtoken.to_json(Answer);
|
UInfo.webtoken.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
} else {
|
} else {
|
||||||
return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
|
return UnAuthorized(RESTAPI::Errors::CANNOT_REFRESH_TOKEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
|
if (GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
|
||||||
Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
|
Logger_.information(
|
||||||
Poco::JSON::Object Answer;
|
fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
|
||||||
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression());
|
Poco::JSON::Object Answer;
|
||||||
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy());
|
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN,
|
||||||
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy());
|
AuthService()->SubPasswordValidationExpression());
|
||||||
return ReturnObject(Answer);
|
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy());
|
||||||
}
|
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy());
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
|
if (GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD)) {
|
||||||
SecurityObjects::UserInfo UInfo1;
|
SecurityObjects::UserInfo UInfo1;
|
||||||
auto UserExists = StorageService()->SubDB().GetUserByEmail(userId,UInfo1);
|
auto UserExists = StorageService()->SubDB().GetUserByEmail(userId, UInfo1);
|
||||||
if(UserExists) {
|
if (UserExists) {
|
||||||
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
|
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
|
||||||
SecurityObjects::ActionLink NewLink;
|
Request->clientAddress().toString(), userId));
|
||||||
|
SecurityObjects::ActionLink NewLink;
|
||||||
|
|
||||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
|
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
|
||||||
NewLink.id = MicroService::CreateUUID();
|
NewLink.id = MicroServiceCreateUUID();
|
||||||
NewLink.userId = UInfo1.id;
|
NewLink.userId = UInfo1.id;
|
||||||
NewLink.created = OpenWifi::Now();
|
NewLink.created = OpenWifi::Now();
|
||||||
NewLink.expires = NewLink.created + (24*60*60);
|
NewLink.expires = NewLink.created + (24 * 60 * 60);
|
||||||
NewLink.userAction = false;
|
NewLink.userAction = false;
|
||||||
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
||||||
|
|
||||||
Poco::JSON::Object ReturnObj;
|
Poco::JSON::Object ReturnObj;
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
UInfo.webtoken.userMustChangePassword = true;
|
UInfo.webtoken.userMustChangePassword = true;
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
return ReturnObject(ReturnObj);
|
return ReturnObject(ReturnObj);
|
||||||
} else {
|
} else {
|
||||||
Poco::JSON::Object ReturnObj;
|
Poco::JSON::Object ReturnObj;
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
UInfo.webtoken.userMustChangePassword = true;
|
UInfo.webtoken.userMustChangePassword = true;
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
return ReturnObject(ReturnObj);
|
return ReturnObject(ReturnObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
|
if (GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE)) {
|
||||||
Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}", Request->clientAddress().toString(), userId));
|
Logger_.information(fmt::format("RESEND-MFA-CODE({}): Request for {}",
|
||||||
if(Obj->has("uuid")) {
|
Request->clientAddress().toString(), userId));
|
||||||
auto uuid = Obj->get("uuid").toString();
|
if (Obj->has("uuid")) {
|
||||||
if(MFAServer()->ResendCode(uuid))
|
auto uuid = Obj->get("uuid").toString();
|
||||||
return OK();
|
if (MFAServer()->ResendCode(uuid))
|
||||||
}
|
return OK();
|
||||||
return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
|
}
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::BAD_MFA_TRANSACTION);
|
||||||
|
}
|
||||||
|
|
||||||
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) {
|
if (GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE)) {
|
||||||
Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}", Request->clientAddress().toString(), userId));
|
Logger_.information(fmt::format("COMPLETE-MFA-CHALLENGE({}): Request for {}",
|
||||||
if(Obj->has("uuid") && Obj->has("answer")) {
|
Request->clientAddress().toString(), userId));
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
if (Obj->has("uuid") && Obj->has("answer")) {
|
||||||
if(MFAServer()->CompleteMFAChallenge(Obj,UInfo)) {
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
Poco::JSON::Object ReturnObj;
|
if (MFAServer()->CompleteMFAChallenge(Obj, UInfo)) {
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
Poco::JSON::Object ReturnObj;
|
||||||
return ReturnObject(ReturnObj);
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
}
|
return ReturnObject(ReturnObj);
|
||||||
}
|
}
|
||||||
return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
|
}
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::MFA_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||||
bool Expired=false;
|
bool Expired = false;
|
||||||
auto Code=AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
|
auto Code = AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
|
||||||
if (Code==SUCCESS) {
|
switch (Code) {
|
||||||
Poco::JSON::Object ReturnObj;
|
case SUCCESS: {
|
||||||
if(AuthService()->RequiresMFA(UInfo)) {
|
Poco::JSON::Object ReturnObj;
|
||||||
if(MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
|
if (AuthService()->RequiresMFA(UInfo)) {
|
||||||
return ReturnObject(ReturnObj);
|
if (MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
|
||||||
}
|
return ReturnObject(ReturnObj);
|
||||||
Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
|
}
|
||||||
}
|
Logger_.warning(
|
||||||
UInfo.webtoken.to_json(ReturnObj);
|
"MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
|
||||||
return ReturnObject(ReturnObj);
|
}
|
||||||
} else {
|
UInfo.webtoken.to_json(ReturnObj);
|
||||||
switch(Code) {
|
return ReturnObject(ReturnObj);
|
||||||
case INVALID_CREDENTIALS:
|
}
|
||||||
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
case INVALID_CREDENTIALS:
|
||||||
case PASSWORD_INVALID:
|
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
||||||
return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
|
case PASSWORD_INVALID:
|
||||||
case PASSWORD_ALREADY_USED:
|
return UnAuthorized(RESTAPI::Errors::PASSWORD_INVALID);
|
||||||
return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
|
case PASSWORD_ALREADY_USED:
|
||||||
case USERNAME_PENDING_VERIFICATION:
|
return UnAuthorized(RESTAPI::Errors::PASSWORD_ALREADY_USED);
|
||||||
return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
|
case USERNAME_PENDING_VERIFICATION:
|
||||||
case PASSWORD_CHANGE_REQUIRED:
|
return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
|
||||||
return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
|
case PASSWORD_CHANGE_REQUIRED:
|
||||||
default:
|
return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
|
||||||
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break;
|
case ACCOUNT_SUSPENDED:
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
|
||||||
return;
|
default:
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace OpenWifi
|
||||||
@@ -3,25 +3,27 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_suboauth2_handler : public RESTAPIHandler {
|
class RESTAPI_suboauth2_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
TransactionId,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10},
|
Server, TransactionId, Internal, false, false,
|
||||||
false) {}
|
RateLimit{.Interval = 1000, .MaxCalls = 10}, false) {}
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; };
|
static auto PathName() {
|
||||||
void DoGet() final;
|
return std::list<std::string>{"/api/v1/suboauth2/{token}", "/api/v1/suboauth2"};
|
||||||
void DoPost() final;
|
};
|
||||||
void DoDelete() final;
|
void DoGet() final;
|
||||||
void DoPut() final {};
|
void DoPost() final;
|
||||||
};
|
void DoDelete() final;
|
||||||
}
|
void DoPut() final{};
|
||||||
|
};
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -7,30 +7,30 @@
|
|||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_subpreferences::DoGet() {
|
void RESTAPI_subpreferences::DoGet() {
|
||||||
SecurityObjects::Preferences P;
|
SecurityObjects::Preferences P;
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
|
StorageService()->SubPreferencesDB().GetPreferences(UserInfo_.userinfo.id, P);
|
||||||
P.to_json(Answer);
|
P.to_json(Answer);
|
||||||
ReturnObject(Answer);
|
ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_subpreferences::DoPut() {
|
void RESTAPI_subpreferences::DoPut() {
|
||||||
|
|
||||||
SecurityObjects::Preferences P;
|
SecurityObjects::Preferences P;
|
||||||
|
|
||||||
const auto & RawObject = ParsedBody_;
|
const auto &RawObject = ParsedBody_;
|
||||||
if(!P.from_json(RawObject)) {
|
if (!P.from_json(RawObject)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
P.id = UserInfo_.userinfo.id;
|
P.id = UserInfo_.userinfo.id;
|
||||||
P.modified = OpenWifi::Now();
|
P.modified = OpenWifi::Now();
|
||||||
StorageService()->SubPreferencesDB().SetPreferences(P);
|
StorageService()->SubPreferencesDB().SetPreferences(P);
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
P.to_json(Answer);
|
P.to_json(Answer);
|
||||||
ReturnObject(Answer);
|
ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,24 +4,23 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_subpreferences : public RESTAPIHandler {
|
class RESTAPI_subpreferences : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>{
|
bool Internal)
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal) {}
|
||||||
Internal) {}
|
static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; };
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; };
|
void DoGet() final;
|
||||||
void DoGet() final;
|
void DoPut() final;
|
||||||
void DoPut() final;
|
void DoPost() final{};
|
||||||
void DoPost() final {};
|
void DoDelete() final{};
|
||||||
void DoDelete() final {};
|
};
|
||||||
};
|
} // namespace OpenWifi
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,33 +5,35 @@
|
|||||||
#include "RESTAPI_subtotp_handler.h"
|
#include "RESTAPI_subtotp_handler.h"
|
||||||
|
|
||||||
#include "TotpCache.h"
|
#include "TotpCache.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_subtotp_handler::DoGet() {
|
void RESTAPI_subtotp_handler::DoGet() {
|
||||||
|
|
||||||
auto Reset = GetBoolParameter("reset",false);
|
auto Reset = GetBoolParameter("reset", false);
|
||||||
std::string QRCode;
|
std::string QRCode;
|
||||||
|
|
||||||
if(TotpCache()->StartValidation(UserInfo_.userinfo,true,QRCode,Reset)) {
|
if (TotpCache()->StartValidation(UserInfo_.userinfo, true, QRCode, Reset)) {
|
||||||
return SendFileContent(QRCode, "image/svg+xml","qrcode.svg");
|
return SendFileContent(QRCode, "image/svg+xml", "qrcode.svg");
|
||||||
}
|
}
|
||||||
return BadRequest(RESTAPI::Errors::InvalidCommand);
|
return BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_subtotp_handler::DoPut() {
|
void RESTAPI_subtotp_handler::DoPut() {
|
||||||
auto Value = GetParameter("value","");
|
auto Value = GetParameter("value", "");
|
||||||
auto nextIndex = GetParameter("index",0);
|
auto nextIndex = GetParameter("index", 0);
|
||||||
bool moreCodes=false;
|
bool moreCodes = false;
|
||||||
|
|
||||||
RESTAPI::Errors::msg Error;
|
RESTAPI::Errors::msg Error;
|
||||||
if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, Error )) {
|
if (TotpCache()->ContinueValidation(UserInfo_.userinfo, true, Value, nextIndex, moreCodes,
|
||||||
Poco::JSON::Object Answer;
|
Error)) {
|
||||||
Answer.set("nextIndex", nextIndex);
|
Poco::JSON::Object Answer;
|
||||||
Answer.set("moreCodes", moreCodes);
|
Answer.set("nextIndex", nextIndex);
|
||||||
return ReturnObject(Answer);
|
Answer.set("moreCodes", moreCodes);
|
||||||
}
|
return ReturnObject(Answer);
|
||||||
return BadRequest(Error);
|
}
|
||||||
}
|
return BadRequest(Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -2,28 +2,25 @@
|
|||||||
// Created by stephane bourque on 2022-01-31.
|
// Created by stephane bourque on 2022-01-31.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_subtotp_handler : public RESTAPIHandler {
|
class RESTAPI_subtotp_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>
|
bool Internal)
|
||||||
{
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
},
|
Server, TransactionId, Internal) {}
|
||||||
Server,
|
static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; };
|
||||||
TransactionId,
|
void DoGet() final;
|
||||||
Internal) {}
|
void DoPost() final{};
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; };
|
void DoDelete() final{};
|
||||||
void DoGet() final;
|
void DoPut() final;
|
||||||
void DoPost() final {};
|
|
||||||
void DoDelete() final {};
|
|
||||||
void DoPut() final;
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
private:
|
||||||
}
|
};
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -3,314 +3,338 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "RESTAPI_subuser_handler.h"
|
#include "RESTAPI_subuser_handler.h"
|
||||||
#include "StorageService.h"
|
|
||||||
#include "framework/ow_constants.h"
|
|
||||||
#include "SMSSender.h"
|
|
||||||
#include "SMTPMailerService.h"
|
|
||||||
#include "ACLProcessor.h"
|
#include "ACLProcessor.h"
|
||||||
#include "AuthService.h"
|
#include "AuthService.h"
|
||||||
#include "RESTAPI/RESTAPI_db_helpers.h"
|
|
||||||
#include "MFAServer.h"
|
#include "MFAServer.h"
|
||||||
|
#include "RESTAPI/RESTAPI_db_helpers.h"
|
||||||
|
#include "SMSSender.h"
|
||||||
|
#include "SMTPMailerService.h"
|
||||||
|
#include "StorageService.h"
|
||||||
#include "TotpCache.h"
|
#include "TotpCache.h"
|
||||||
|
#include "framework/ow_constants.h"
|
||||||
|
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_subuser_handler::DoGet() {
|
void RESTAPI_subuser_handler::DoGet() {
|
||||||
std::string Id = GetBinding("id", "");
|
std::string Id = GetBinding("id", "");
|
||||||
if(Id.empty()) {
|
if (Id.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::toLowerInPlace(Id);
|
Poco::toLowerInPlace(Id);
|
||||||
std::string Arg;
|
std::string Arg;
|
||||||
SecurityObjects::UserInfo UInfo;
|
SecurityObjects::UserInfo UInfo;
|
||||||
if(HasParameter("byEmail",Arg) && Arg=="true") {
|
if (HasParameter("byEmail", Arg) && Arg == "true") {
|
||||||
if(!StorageService()->SubDB().GetUserByEmail(Id,UInfo)) {
|
if (!StorageService()->SubDB().GetUserByEmail(Id, UInfo)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
} else if(!StorageService()->SubDB().GetUserById(Id,UInfo)) {
|
} else if (!StorageService()->SubDB().GetUserById(Id, UInfo)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::JSON::Object UserInfoObject;
|
Poco::JSON::Object UserInfoObject;
|
||||||
Sanitize(UserInfo_, UInfo);
|
Sanitize(UserInfo_, UInfo);
|
||||||
UInfo.to_json(UserInfoObject);
|
UInfo.to_json(UserInfoObject);
|
||||||
ReturnObject(UserInfoObject);
|
ReturnObject(UserInfoObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RESTAPI_subuser_handler::DoDelete() {
|
void RESTAPI_subuser_handler::DoDelete() {
|
||||||
std::string Id = GetBinding("id", "");
|
std::string Id = GetBinding("id", "");
|
||||||
if(Id.empty()) {
|
if (Id.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfo TargetUser;
|
SecurityObjects::UserInfo TargetUser;
|
||||||
if(!StorageService()->SubDB().GetUserById(Id,TargetUser)) {
|
if (!StorageService()->SubDB().GetUserById(Id, TargetUser)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
|
if (TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) {
|
if (!Internal_ &&
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
!ACLProcessor::Can(UserInfo_.userinfo, TargetUser, ACLProcessor::DELETE)) {
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
|
if (!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email, Id)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthService()->DeleteSubUserFromCache(Id);
|
AuthService()->DeleteSubUserFromCache(Id);
|
||||||
StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
|
StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
|
||||||
StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
|
StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
|
||||||
StorageService()->SubAvatarDB().DeleteRecord("id", Id);
|
StorageService()->SubAvatarDB().DeleteRecord("id", Id);
|
||||||
Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email));
|
Logger_.information(
|
||||||
OK();
|
fmt::format("User '{}' deleted by '{}'.", Id, UserInfo_.userinfo.email));
|
||||||
}
|
OK();
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_subuser_handler::DoPost() {
|
void RESTAPI_subuser_handler::DoPost() {
|
||||||
std::string Id = GetBinding("id", "");
|
std::string Id = GetBinding("id", "");
|
||||||
if(Id!="0") {
|
if (Id != "0") {
|
||||||
return BadRequest(RESTAPI::Errors::IdMustBe0);
|
return BadRequest(RESTAPI::Errors::IdMustBe0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfo NewUser;
|
SecurityObjects::UserInfo NewUser;
|
||||||
const auto & RawObject = ParsedBody_;
|
const auto &RawObject = ParsedBody_;
|
||||||
if(!NewUser.from_json(RawObject)) {
|
if (!NewUser.from_json(RawObject)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) {
|
if (NewUser.userRole == SecurityObjects::UNKNOWN ||
|
||||||
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
NewUser.userRole != SecurityObjects::SUBSCRIBER) {
|
||||||
}
|
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
||||||
|
}
|
||||||
|
|
||||||
Poco::toLowerInPlace(NewUser.email);
|
Poco::toLowerInPlace(NewUser.email);
|
||||||
SecurityObjects::UserInfo Existing;
|
SecurityObjects::UserInfo Existing;
|
||||||
if(StorageService()->SubDB().GetUserByEmail(NewUser.email,Existing)) {
|
if (StorageService()->SubDB().GetUserByEmail(NewUser.email, Existing)) {
|
||||||
return BadRequest(RESTAPI::Errors::UserAlreadyExists);
|
return BadRequest(RESTAPI::Errors::UserAlreadyExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
|
if (!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, NewUser, ACLProcessor::CREATE)) {
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::toLowerInPlace(NewUser.email);
|
Poco::toLowerInPlace(NewUser.email);
|
||||||
if(!Utils::ValidEMailAddress(NewUser.email)) {
|
if (!Utils::ValidEMailAddress(NewUser.email)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
|
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!NewUser.currentPassword.empty()) {
|
if (!NewUser.currentPassword.empty()) {
|
||||||
if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
|
if (!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidPassword);
|
return BadRequest(RESTAPI::Errors::InvalidPassword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NewUser.name.empty())
|
if (NewUser.name.empty())
|
||||||
NewUser.name = NewUser.email;
|
NewUser.name = NewUser.email;
|
||||||
|
|
||||||
// You cannot enable MFA during user creation
|
// You cannot enable MFA during user creation
|
||||||
NewUser.userTypeProprietaryInfo.mfa.enabled = false;
|
NewUser.userTypeProprietaryInfo.mfa.enabled = false;
|
||||||
NewUser.userTypeProprietaryInfo.mfa.method = "";
|
NewUser.userTypeProprietaryInfo.mfa.method = "";
|
||||||
NewUser.userTypeProprietaryInfo.mobiles.clear();
|
NewUser.userTypeProprietaryInfo.mobiles.clear();
|
||||||
NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
|
NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
|
||||||
|
|
||||||
if(!StorageService()->SubDB().CreateUser(UserInfo_.userinfo.email, NewUser)) {
|
if (!StorageService()->SubDB().CreateUser(UserInfo_.userinfo.email, NewUser)) {
|
||||||
Logger_.information(fmt::format("Could not add user '{}'.",NewUser.email));
|
Logger_.information(fmt::format("Could not add user '{}'.", NewUser.email));
|
||||||
return BadRequest(RESTAPI::Errors::RecordNotCreated);
|
return BadRequest(RESTAPI::Errors::RecordNotCreated);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetParameter("email_verification","false")=="true") {
|
if (GetParameter("email_verification", "false") == "true") {
|
||||||
if(AuthService::VerifySubEmail(NewUser))
|
if (AuthService::VerifySubEmail(NewUser))
|
||||||
Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email));
|
Logger_.information(
|
||||||
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
|
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)) {
|
if (!StorageService()->SubDB().GetUserByEmail(NewUser.email, NewUser)) {
|
||||||
Logger_.information(fmt::format("User '{}' but not retrieved.",NewUser.email));
|
Logger_.information(fmt::format("User '{}' but not retrieved.", NewUser.email));
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::JSON::Object UserInfoObject;
|
Poco::JSON::Object UserInfoObject;
|
||||||
Sanitize(UserInfo_, NewUser);
|
Sanitize(UserInfo_, NewUser);
|
||||||
NewUser.to_json(UserInfoObject);
|
NewUser.to_json(UserInfoObject);
|
||||||
ReturnObject(UserInfoObject);
|
ReturnObject(UserInfoObject);
|
||||||
Logger_.information(fmt::format("User '{}' has been added by '{}')",NewUser.email, UserInfo_.userinfo.email));
|
Logger_.information(fmt::format("User '{}' has been added by '{}')", NewUser.email,
|
||||||
}
|
UserInfo_.userinfo.email));
|
||||||
|
}
|
||||||
|
|
||||||
void RESTAPI_subuser_handler::DoPut() {
|
void RESTAPI_subuser_handler::DoPut() {
|
||||||
std::string Id = GetBinding("id", "");
|
std::string Id = GetBinding("id", "");
|
||||||
if(Id.empty()) {
|
if (Id.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfo Existing;
|
SecurityObjects::UserInfo Existing;
|
||||||
if(!StorageService()->SubDB().GetUserById(Id,Existing)) {
|
if (!StorageService()->SubDB().GetUserById(Id, Existing)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
|
if (!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, Existing, ACLProcessor::MODIFY)) {
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetBoolParameter("resetMFA")) {
|
if (GetBoolParameter("resetMFA")) {
|
||||||
if( (UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
|
if ((UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
|
||||||
(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) ||
|
(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN &&
|
||||||
(UserInfo_.userinfo.id == Id)) {
|
Existing.userRole != SecurityObjects::ROOT) ||
|
||||||
Existing.userTypeProprietaryInfo.mfa.enabled = false;
|
(UserInfo_.userinfo.id == Id)) {
|
||||||
Existing.userTypeProprietaryInfo.mfa.method.clear();
|
Existing.userTypeProprietaryInfo.mfa.enabled = false;
|
||||||
Existing.userTypeProprietaryInfo.mobiles.clear();
|
Existing.userTypeProprietaryInfo.mfa.method.clear();
|
||||||
Existing.modified = OpenWifi::Now();
|
Existing.userTypeProprietaryInfo.mobiles.clear();
|
||||||
Existing.notes.push_back( SecurityObjects::NoteInfo{
|
Existing.modified = OpenWifi::Now();
|
||||||
.created=OpenWifi::Now(),
|
Existing.notes.push_back(
|
||||||
.createdBy=UserInfo_.userinfo.email,
|
SecurityObjects::NoteInfo{.created = OpenWifi::Now(),
|
||||||
.note="MFA Reset by " + UserInfo_.userinfo.email});
|
.createdBy = UserInfo_.userinfo.email,
|
||||||
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing);
|
.note = "MFA Reset by " + UserInfo_.userinfo.email});
|
||||||
SecurityObjects::UserInfo NewUserInfo;
|
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, Id, Existing);
|
||||||
StorageService()->SubDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
|
SecurityObjects::UserInfo NewUserInfo;
|
||||||
Poco::JSON::Object ModifiedObject;
|
StorageService()->SubDB().GetUserByEmail(UserInfo_.userinfo.email, NewUserInfo);
|
||||||
Sanitize(UserInfo_, NewUserInfo);
|
Poco::JSON::Object ModifiedObject;
|
||||||
NewUserInfo.to_json(ModifiedObject);
|
Sanitize(UserInfo_, NewUserInfo);
|
||||||
return ReturnObject(ModifiedObject);
|
NewUserInfo.to_json(ModifiedObject);
|
||||||
} else {
|
return ReturnObject(ModifiedObject);
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
} else {
|
||||||
}
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(GetBoolParameter("forgotPassword")) {
|
if (GetBoolParameter("forgotPassword") || GetBoolParameter("resetPassword")) {
|
||||||
Existing.changePassword = true;
|
Existing.changePassword = true;
|
||||||
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), Existing.email));
|
Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
|
||||||
|
Request->clientAddress().toString(), Existing.email));
|
||||||
|
|
||||||
SecurityObjects::ActionLink NewLink;
|
SecurityObjects::ActionLink NewLink;
|
||||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
|
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
|
||||||
NewLink.id = MicroService::CreateUUID();
|
NewLink.id = MicroServiceCreateUUID();
|
||||||
NewLink.userId = Existing.id;
|
NewLink.userId = Existing.id;
|
||||||
NewLink.created = OpenWifi::Now();
|
NewLink.created = OpenWifi::Now();
|
||||||
NewLink.expires = NewLink.created + (24*60*60);
|
NewLink.expires = NewLink.created + (24 * 60 * 60);
|
||||||
NewLink.userAction = false;
|
NewLink.userAction = false;
|
||||||
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
||||||
|
|
||||||
return OK();
|
return OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfo NewUser;
|
SecurityObjects::UserInfo NewUser;
|
||||||
const auto & RawObject = ParsedBody_;
|
const auto &RawObject = ParsedBody_;
|
||||||
if(!NewUser.from_json(RawObject)) {
|
if (!NewUser.from_json(RawObject)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
// some basic validations
|
// some basic validations
|
||||||
if(RawObject->has("userRole") &&
|
if (RawObject->has("userRole") &&
|
||||||
(SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN ||
|
(SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()) ==
|
||||||
SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) {
|
SecurityObjects::UNKNOWN ||
|
||||||
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()) ==
|
||||||
}
|
SecurityObjects::SUBSCRIBER)) {
|
||||||
|
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
||||||
|
}
|
||||||
|
|
||||||
// The only valid things to change are: changePassword, name,
|
// The only valid things to change are: changePassword, name,
|
||||||
AssignIfPresent(RawObject,"name", Existing.name);
|
AssignIfPresent(RawObject, "name", Existing.name);
|
||||||
AssignIfPresent(RawObject,"description", Existing.description);
|
AssignIfPresent(RawObject, "description", Existing.description);
|
||||||
AssignIfPresent(RawObject,"owner", Existing.owner);
|
AssignIfPresent(RawObject, "owner", Existing.owner);
|
||||||
AssignIfPresent(RawObject,"location", Existing.location);
|
AssignIfPresent(RawObject, "location", Existing.location);
|
||||||
AssignIfPresent(RawObject,"locale", Existing.locale);
|
AssignIfPresent(RawObject, "locale", Existing.locale);
|
||||||
AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
|
AssignIfPresent(RawObject, "changePassword", Existing.changePassword);
|
||||||
AssignIfPresent(RawObject,"suspended", Existing.suspended);
|
AssignIfPresent(RawObject, "suspended", Existing.suspended);
|
||||||
AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
|
AssignIfPresent(RawObject, "blackListed", Existing.blackListed);
|
||||||
|
|
||||||
if(RawObject->has("userRole")) {
|
if (RawObject->has("userRole")) {
|
||||||
auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
|
auto NewRole =
|
||||||
if(NewRole!=Existing.userRole) {
|
SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
|
||||||
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
|
if (NewRole != Existing.userRole) {
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
|
||||||
}
|
NewRole == SecurityObjects::ROOT) {
|
||||||
if(Id==UserInfo_.userinfo.id) {
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
}
|
||||||
}
|
if (Id == UserInfo_.userinfo.id) {
|
||||||
Existing.userRole = NewRole;
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
}
|
Existing.userRole = NewRole;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(RawObject->has("notes")) {
|
if (RawObject->has("notes")) {
|
||||||
SecurityObjects::NoteInfoVec NIV;
|
SecurityObjects::NoteInfoVec NIV;
|
||||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
|
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(
|
||||||
for(auto const &i:NIV) {
|
RawObject->get("notes").toString());
|
||||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
|
for (auto const &i : NIV) {
|
||||||
Existing.notes.push_back(ii);
|
SecurityObjects::NoteInfo ii{.created = (uint64_t)OpenWifi::Now(),
|
||||||
}
|
.createdBy = UserInfo_.userinfo.email,
|
||||||
}
|
.note = i.note};
|
||||||
if(RawObject->has("currentPassword")) {
|
Existing.notes.push_back(ii);
|
||||||
if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
|
}
|
||||||
return BadRequest(RESTAPI::Errors::InvalidPassword);
|
}
|
||||||
}
|
if (RawObject->has("currentPassword")) {
|
||||||
if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) {
|
if (!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
|
||||||
return BadRequest(RESTAPI::Errors::PasswordRejected);
|
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 (GetParameter("email_verification", "false") == "true") {
|
||||||
if(AuthService::VerifySubEmail(Existing))
|
if (AuthService::VerifySubEmail(Existing))
|
||||||
Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email));
|
Logger_.information(
|
||||||
}
|
fmt::format("Verification e-mail requested for {}", Existing.email));
|
||||||
|
}
|
||||||
|
|
||||||
if(RawObject->has("userTypeProprietaryInfo")) {
|
if (RawObject->has("userTypeProprietaryInfo")) {
|
||||||
if(NewUser.userTypeProprietaryInfo.mfa.enabled) {
|
if (NewUser.userTypeProprietaryInfo.mfa.enabled) {
|
||||||
if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
|
if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
|
||||||
return BadRequest(RESTAPI::Errors::BadMFAMethod);
|
return BadRequest(RESTAPI::Errors::BadMFAMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
|
if (NewUser.userTypeProprietaryInfo.mfa.enabled &&
|
||||||
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS &&
|
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS &&
|
||||||
!SMSSender()->Enabled()) {
|
!SMSSender()->Enabled()) {
|
||||||
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
return BadRequest(RESTAPI::Errors::SMSMFANotEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( NewUser.userTypeProprietaryInfo.mfa.enabled &&
|
if (NewUser.userTypeProprietaryInfo.mfa.enabled &&
|
||||||
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL &&
|
NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL &&
|
||||||
!SMTPMailerService()->Enabled()) {
|
!SMTPMailerService()->Enabled()) {
|
||||||
return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
|
return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
|
Existing.userTypeProprietaryInfo.mfa.method =
|
||||||
Existing.userTypeProprietaryInfo.mfa.enabled = true;
|
NewUser.userTypeProprietaryInfo.mfa.method;
|
||||||
|
Existing.userTypeProprietaryInfo.mfa.enabled = true;
|
||||||
|
|
||||||
if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
|
if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
|
||||||
if(NewUser.userTypeProprietaryInfo.mobiles.empty()) {
|
if (NewUser.userTypeProprietaryInfo.mobiles.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
|
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
|
||||||
}
|
}
|
||||||
if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) {
|
if (!SMSSender()->IsNumberValid(
|
||||||
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
|
NewUser.userTypeProprietaryInfo.mobiles[0].number,
|
||||||
}
|
UserInfo_.userinfo.email)) {
|
||||||
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
|
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
|
||||||
Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
|
}
|
||||||
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
|
Existing.userTypeProprietaryInfo.mobiles =
|
||||||
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
|
NewUser.userTypeProprietaryInfo.mobiles;
|
||||||
std::string Secret;
|
Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
|
||||||
Existing.userTypeProprietaryInfo.mobiles.clear();
|
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
|
||||||
if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
|
} else if (NewUser.userTypeProprietaryInfo.mfa.method ==
|
||||||
Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
|
MFAMETHODS::AUTHENTICATOR) {
|
||||||
} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
|
std::string Secret;
|
||||||
// we allow someone to use their old secret
|
Existing.userTypeProprietaryInfo.mobiles.clear();
|
||||||
} else {
|
if (Existing.userTypeProprietaryInfo.authenticatorSecret.empty() &&
|
||||||
return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
|
TotpCache()->CompleteValidation(UserInfo_.userinfo, false, Secret)) {
|
||||||
}
|
Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
|
||||||
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
|
} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
|
||||||
Existing.userTypeProprietaryInfo.mobiles.clear();
|
// we allow someone to use their old secret
|
||||||
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
|
} else {
|
||||||
}
|
return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
|
||||||
} else {
|
}
|
||||||
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
|
} else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
|
||||||
Existing.userTypeProprietaryInfo.mobiles.clear();
|
Existing.userTypeProprietaryInfo.mobiles.clear();
|
||||||
Existing.userTypeProprietaryInfo.mfa.enabled = false;
|
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)) {
|
if (StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, Id, Existing)) {
|
||||||
SecurityObjects::UserInfo NewUserInfo;
|
SecurityObjects::UserInfo NewUserInfo;
|
||||||
StorageService()->SubDB().GetUserById(Id,NewUserInfo);
|
StorageService()->SubDB().GetUserById(Id, NewUserInfo);
|
||||||
Poco::JSON::Object ModifiedObject;
|
Poco::JSON::Object ModifiedObject;
|
||||||
Sanitize(UserInfo_, NewUserInfo);
|
Sanitize(UserInfo_, NewUserInfo);
|
||||||
NewUserInfo.to_json(ModifiedObject);
|
NewUserInfo.to_json(ModifiedObject);
|
||||||
return ReturnObject(ModifiedObject);
|
return ReturnObject(ModifiedObject);
|
||||||
}
|
}
|
||||||
BadRequest(RESTAPI::Errors::RecordNotUpdated);
|
BadRequest(RESTAPI::Errors::RecordNotUpdated);
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||
@@ -4,28 +4,27 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_subuser_handler : public RESTAPIHandler {
|
class RESTAPI_subuser_handler : public RESTAPIHandler {
|
||||||
public:
|
public:
|
||||||
RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
|
RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
|
||||||
: RESTAPIHandler(bindings, L,
|
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
|
||||||
std::vector<std::string>
|
bool Internal)
|
||||||
{Poco::Net::HTTPRequest::HTTP_POST,
|
: RESTAPIHandler(bindings, L,
|
||||||
Poco::Net::HTTPRequest::HTTP_GET,
|
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
Server,
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
TransactionId,
|
Server, TransactionId, Internal) {}
|
||||||
Internal) {}
|
static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; };
|
||||||
static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; };
|
void DoGet() final;
|
||||||
void DoGet() final;
|
void DoPost() final;
|
||||||
void DoPost() final;
|
void DoDelete() final;
|
||||||
void DoDelete() final;
|
void DoPut() final;
|
||||||
void DoPut() final;
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
private:
|
||||||
}
|
};
|
||||||
|
} // namespace OpenWifi
|
||||||
|
|||||||
@@ -3,78 +3,84 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "RESTAPI_subusers_handler.h"
|
#include "RESTAPI_subusers_handler.h"
|
||||||
#include "StorageService.h"
|
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include "RESTAPI/RESTAPI_db_helpers.h"
|
#include "RESTAPI/RESTAPI_db_helpers.h"
|
||||||
|
#include "StorageService.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void RESTAPI_subusers_handler::DoGet() {
|
void RESTAPI_subusers_handler::DoGet() {
|
||||||
bool IdOnly = GetBoolParameter("idOnly");
|
bool IdOnly = GetBoolParameter("idOnly");
|
||||||
auto operatorId = GetParameter("operatorId");
|
auto operatorId = GetParameter("operatorId");
|
||||||
auto nameSearch = GetParameter("nameSearch");
|
auto nameSearch = GetParameter("nameSearch");
|
||||||
auto emailSearch = GetParameter("emailSearch");
|
auto emailSearch = GetParameter("emailSearch");
|
||||||
|
|
||||||
std::string baseQuery;
|
std::string baseQuery;
|
||||||
if(!nameSearch.empty() || !emailSearch.empty()) {
|
if (!nameSearch.empty() || !emailSearch.empty()) {
|
||||||
if(!nameSearch.empty())
|
if (!nameSearch.empty())
|
||||||
baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) );
|
baseQuery = fmt::format(" Lower(name) like('%{}%') ",
|
||||||
if(!emailSearch.empty())
|
ORM::Escape(Poco::toLower(nameSearch)));
|
||||||
baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch))
|
if (!emailSearch.empty())
|
||||||
: fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch));
|
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) {
|
if (QB_.CountOnly) {
|
||||||
std::string whereClause;
|
std::string whereClause;
|
||||||
if(!operatorId.empty()) {
|
if (!operatorId.empty() && Utils::ValidUUID(operatorId)) {
|
||||||
whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) :
|
whereClause = baseQuery.empty()
|
||||||
fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
|
? fmt::format(" owner='{}' ", operatorId)
|
||||||
auto count = StorageService()->SubDB().Count(whereClause);
|
: fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
|
||||||
return ReturnCountOnly(count);
|
auto count = StorageService()->SubDB().Count(whereClause);
|
||||||
}
|
return ReturnCountOnly(count);
|
||||||
auto count = StorageService()->UserDB().Count();
|
}
|
||||||
return ReturnCountOnly(count);
|
auto count = StorageService()->UserDB().Count();
|
||||||
} else if(QB_.Select.empty()) {
|
return ReturnCountOnly(count);
|
||||||
std::string whereClause;
|
} else if (QB_.Select.empty()) {
|
||||||
if(!operatorId.empty()) {
|
std::string whereClause;
|
||||||
whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) :
|
if (!operatorId.empty() && Utils::ValidUUID(operatorId)) {
|
||||||
fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
|
whereClause = baseQuery.empty()
|
||||||
}
|
? fmt::format(" owner='{}' ", operatorId)
|
||||||
|
: fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
|
||||||
|
}
|
||||||
|
|
||||||
SecurityObjects::UserInfoList Users;
|
SecurityObjects::UserInfoList Users;
|
||||||
if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, whereClause)) {
|
if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users.users,
|
||||||
for (auto &i : Users.users) {
|
whereClause)) {
|
||||||
Sanitize(UserInfo_, i);
|
for (auto &i : Users.users) {
|
||||||
}
|
Sanitize(UserInfo_, i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(IdOnly) {
|
if (IdOnly) {
|
||||||
Poco::JSON::Array Arr;
|
Poco::JSON::Array Arr;
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
|
|
||||||
for(const auto &i:Users.users) {
|
for (const auto &i : Users.users) {
|
||||||
Arr.add(i.id);
|
Arr.add(i.id);
|
||||||
}
|
}
|
||||||
Answer.set("users",Arr);
|
Answer.set("users", Arr);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
Users.to_json(Answer);
|
Users.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
} else {
|
} else {
|
||||||
SecurityObjects::UserInfoList Users;
|
SecurityObjects::UserInfoList Users;
|
||||||
for(auto &i:SelectedRecords()) {
|
for (auto &i : SelectedRecords()) {
|
||||||
SecurityObjects::UserInfo UInfo;
|
SecurityObjects::UserInfo UInfo;
|
||||||
if(StorageService()->SubDB().GetUserById(i,UInfo)) {
|
if (StorageService()->SubDB().GetUserById(i, UInfo)) {
|
||||||
Poco::JSON::Object Obj;
|
Poco::JSON::Object Obj;
|
||||||
Sanitize(UserInfo_, UInfo);
|
Sanitize(UserInfo_, UInfo);
|
||||||
Users.users.emplace_back(UInfo);
|
Users.users.emplace_back(UInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
Users.to_json(Answer);
|
Users.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace OpenWifi
|
||||||