Compare commits
	
		
			145 Commits
		
	
	
		
			v2.7.0-RC3
			...
			release/v2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c7a087ed4a | ||
| 
						 | 
					c911be58f6 | ||
| 
						 | 
					e23dda1df0 | ||
| 
						 | 
					e8955454f7 | ||
| 
						 | 
					6e0cf66008 | ||
| 
						 | 
					6d305636a0 | ||
| 
						 | 
					a9990a6bfd | ||
| 
						 | 
					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 | ||
| 
						 | 
					bbf1c61ea8 | ||
| 
						 | 
					e76fedb207 | ||
| 
						 | 
					4ab026b88c | ||
| 
						 | 
					4b184bae24 | ||
| 
						 | 
					c483c99802 | ||
| 
						 | 
					7ea1ccc9d9 | 
							
								
								
									
										178
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,178 @@
 | 
			
		||||
---
 | 
			
		||||
Language:        Cpp
 | 
			
		||||
# BasedOnStyle:  LLVM
 | 
			
		||||
AccessModifierOffset: -2
 | 
			
		||||
AlignAfterOpenBracket: Align
 | 
			
		||||
AlignArrayOfStructures: None
 | 
			
		||||
AlignConsecutiveMacros: None
 | 
			
		||||
AlignConsecutiveAssignments: None
 | 
			
		||||
AlignConsecutiveBitFields: None
 | 
			
		||||
AlignConsecutiveDeclarations: None
 | 
			
		||||
AlignEscapedNewlines: Right
 | 
			
		||||
AlignOperands:   Align
 | 
			
		||||
AlignTrailingComments: true
 | 
			
		||||
AllowAllArgumentsOnNextLine: true
 | 
			
		||||
AllowAllConstructorInitializersOnNextLine: true
 | 
			
		||||
AllowAllParametersOfDeclarationOnNextLine: true
 | 
			
		||||
AllowShortEnumsOnASingleLine: true
 | 
			
		||||
AllowShortBlocksOnASingleLine: Never
 | 
			
		||||
AllowShortCaseLabelsOnASingleLine: false
 | 
			
		||||
AllowShortFunctionsOnASingleLine: All
 | 
			
		||||
AllowShortLambdasOnASingleLine: All
 | 
			
		||||
AllowShortIfStatementsOnASingleLine: Never
 | 
			
		||||
AllowShortLoopsOnASingleLine: false
 | 
			
		||||
AlwaysBreakAfterDefinitionReturnType: None
 | 
			
		||||
AlwaysBreakAfterReturnType: None
 | 
			
		||||
AlwaysBreakBeforeMultilineStrings: false
 | 
			
		||||
AlwaysBreakTemplateDeclarations: MultiLine
 | 
			
		||||
AttributeMacros:
 | 
			
		||||
  - __capability
 | 
			
		||||
BinPackArguments: true
 | 
			
		||||
BinPackParameters: true
 | 
			
		||||
BraceWrapping:
 | 
			
		||||
  AfterCaseLabel:  false
 | 
			
		||||
  AfterClass:      false
 | 
			
		||||
  AfterControlStatement: Never
 | 
			
		||||
  AfterEnum:       false
 | 
			
		||||
  AfterFunction:   false
 | 
			
		||||
  AfterNamespace:  false
 | 
			
		||||
  AfterObjCDeclaration: false
 | 
			
		||||
  AfterStruct:     false
 | 
			
		||||
  AfterUnion:      false
 | 
			
		||||
  AfterExternBlock: false
 | 
			
		||||
  BeforeCatch:     false
 | 
			
		||||
  BeforeElse:      false
 | 
			
		||||
  BeforeLambdaBody: false
 | 
			
		||||
  BeforeWhile:     false
 | 
			
		||||
  IndentBraces:    false
 | 
			
		||||
  SplitEmptyFunction: true
 | 
			
		||||
  SplitEmptyRecord: true
 | 
			
		||||
  SplitEmptyNamespace: true
 | 
			
		||||
BreakBeforeBinaryOperators: None
 | 
			
		||||
BreakBeforeConceptDeclarations: true
 | 
			
		||||
BreakBeforeBraces: Attach
 | 
			
		||||
BreakBeforeInheritanceComma: false
 | 
			
		||||
BreakInheritanceList: BeforeColon
 | 
			
		||||
BreakBeforeTernaryOperators: true
 | 
			
		||||
BreakConstructorInitializersBeforeComma: false
 | 
			
		||||
BreakConstructorInitializers: BeforeColon
 | 
			
		||||
BreakAfterJavaFieldAnnotations: false
 | 
			
		||||
BreakStringLiterals: true
 | 
			
		||||
ColumnLimit:     100
 | 
			
		||||
CommentPragmas:  '^ IWYU pragma:'
 | 
			
		||||
CompactNamespaces: false
 | 
			
		||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
 | 
			
		||||
ConstructorInitializerIndentWidth: 4
 | 
			
		||||
ContinuationIndentWidth: 4
 | 
			
		||||
Cpp11BracedListStyle: true
 | 
			
		||||
DeriveLineEnding: true
 | 
			
		||||
DerivePointerAlignment: false
 | 
			
		||||
DisableFormat:   false
 | 
			
		||||
EmptyLineAfterAccessModifier: Never
 | 
			
		||||
EmptyLineBeforeAccessModifier: LogicalBlock
 | 
			
		||||
ExperimentalAutoDetectBinPacking: false
 | 
			
		||||
FixNamespaceComments: true
 | 
			
		||||
ForEachMacros:
 | 
			
		||||
  - foreach
 | 
			
		||||
  - Q_FOREACH
 | 
			
		||||
  - BOOST_FOREACH
 | 
			
		||||
IfMacros:
 | 
			
		||||
  - KJ_IF_MAYBE
 | 
			
		||||
IncludeBlocks:   Preserve
 | 
			
		||||
IncludeCategories:
 | 
			
		||||
  - Regex:           '^"(llvm|llvm-c|clang|clang-c)/'
 | 
			
		||||
    Priority:        2
 | 
			
		||||
    SortPriority:    0
 | 
			
		||||
    CaseSensitive:   false
 | 
			
		||||
  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
 | 
			
		||||
    Priority:        3
 | 
			
		||||
    SortPriority:    0
 | 
			
		||||
    CaseSensitive:   false
 | 
			
		||||
  - Regex:           '.*'
 | 
			
		||||
    Priority:        1
 | 
			
		||||
    SortPriority:    0
 | 
			
		||||
    CaseSensitive:   false
 | 
			
		||||
IncludeIsMainRegex: '(Test)?$'
 | 
			
		||||
IncludeIsMainSourceRegex: ''
 | 
			
		||||
IndentAccessModifiers: false
 | 
			
		||||
IndentCaseLabels: false
 | 
			
		||||
IndentCaseBlocks: false
 | 
			
		||||
IndentGotoLabels: true
 | 
			
		||||
IndentPPDirectives: None
 | 
			
		||||
IndentExternBlock: AfterExternBlock
 | 
			
		||||
IndentRequires:  false
 | 
			
		||||
IndentWidth:     4
 | 
			
		||||
IndentWrappedFunctionNames: false
 | 
			
		||||
InsertTrailingCommas: None
 | 
			
		||||
JavaScriptQuotes: Leave
 | 
			
		||||
JavaScriptWrapImports: true
 | 
			
		||||
KeepEmptyLinesAtTheStartOfBlocks: true
 | 
			
		||||
LambdaBodyIndentation: Signature
 | 
			
		||||
MacroBlockBegin: ''
 | 
			
		||||
MacroBlockEnd:   ''
 | 
			
		||||
MaxEmptyLinesToKeep: 1
 | 
			
		||||
NamespaceIndentation: All
 | 
			
		||||
ObjCBinPackProtocolList: Auto
 | 
			
		||||
ObjCBlockIndentWidth: 2
 | 
			
		||||
ObjCBreakBeforeNestedBlockParam: true
 | 
			
		||||
ObjCSpaceAfterProperty: false
 | 
			
		||||
ObjCSpaceBeforeProtocolList: true
 | 
			
		||||
PenaltyBreakAssignment: 2
 | 
			
		||||
PenaltyBreakBeforeFirstCallParameter: 19
 | 
			
		||||
PenaltyBreakComment: 300
 | 
			
		||||
PenaltyBreakFirstLessLess: 120
 | 
			
		||||
PenaltyBreakString: 1000
 | 
			
		||||
PenaltyBreakTemplateDeclaration: 10
 | 
			
		||||
PenaltyExcessCharacter: 1000000
 | 
			
		||||
PenaltyReturnTypeOnItsOwnLine: 60
 | 
			
		||||
PenaltyIndentedWhitespace: 0
 | 
			
		||||
PointerAlignment: Right
 | 
			
		||||
PPIndentWidth:   -1
 | 
			
		||||
ReferenceAlignment: Pointer
 | 
			
		||||
ReflowComments:  true
 | 
			
		||||
ShortNamespaceLines: 1
 | 
			
		||||
SortIncludes:    CaseSensitive
 | 
			
		||||
SortJavaStaticImport: Before
 | 
			
		||||
SortUsingDeclarations: true
 | 
			
		||||
SpaceAfterCStyleCast: false
 | 
			
		||||
SpaceAfterLogicalNot: false
 | 
			
		||||
SpaceAfterTemplateKeyword: true
 | 
			
		||||
SpaceBeforeAssignmentOperators: true
 | 
			
		||||
SpaceBeforeCaseColon: false
 | 
			
		||||
SpaceBeforeCpp11BracedList: false
 | 
			
		||||
SpaceBeforeCtorInitializerColon: true
 | 
			
		||||
SpaceBeforeInheritanceColon: true
 | 
			
		||||
SpaceBeforeParens: ControlStatements
 | 
			
		||||
SpaceAroundPointerQualifiers: Default
 | 
			
		||||
SpaceBeforeRangeBasedForLoopColon: true
 | 
			
		||||
SpaceInEmptyBlock: false
 | 
			
		||||
SpaceInEmptyParentheses: false
 | 
			
		||||
SpacesBeforeTrailingComments: 1
 | 
			
		||||
SpacesInAngles:  Never
 | 
			
		||||
SpacesInConditionalStatement: false
 | 
			
		||||
SpacesInContainerLiterals: true
 | 
			
		||||
SpacesInCStyleCastParentheses: false
 | 
			
		||||
SpacesInLineCommentPrefix:
 | 
			
		||||
  Minimum:         1
 | 
			
		||||
  Maximum:         -1
 | 
			
		||||
SpacesInParentheses: false
 | 
			
		||||
SpacesInSquareBrackets: false
 | 
			
		||||
SpaceBeforeSquareBrackets: false
 | 
			
		||||
BitFieldColonSpacing: Both
 | 
			
		||||
Standard:        Latest
 | 
			
		||||
StatementAttributeLikeMacros:
 | 
			
		||||
  - Q_EMIT
 | 
			
		||||
StatementMacros:
 | 
			
		||||
  - Q_UNUSED
 | 
			
		||||
  - QT_REQUIRE_VERSION
 | 
			
		||||
TabWidth:        4
 | 
			
		||||
UseCRLF:         false
 | 
			
		||||
UseTab:          Always
 | 
			
		||||
WhitespaceSensitiveMacros:
 | 
			
		||||
  - STRINGIZE
 | 
			
		||||
  - PP_STRINGIZE
 | 
			
		||||
  - BOOST_PP_STRINGIZE
 | 
			
		||||
  - NS_SWIFT_NAME
 | 
			
		||||
  - CF_SWIFT_NAME
 | 
			
		||||
...
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -27,7 +27,7 @@ jobs:
 | 
			
		||||
      DOCKER_REGISTRY_USERNAME: ucentral
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Checkout actions repo
 | 
			
		||||
      uses: actions/checkout@v2
 | 
			
		||||
      uses: actions/checkout@v3
 | 
			
		||||
      with:
 | 
			
		||||
        repository: Telecominfraproject/.github
 | 
			
		||||
        path: github
 | 
			
		||||
@@ -58,11 +58,11 @@ jobs:
 | 
			
		||||
    - name: Get base branch name and set as output
 | 
			
		||||
      id: get_base_branch
 | 
			
		||||
      run: |
 | 
			
		||||
        echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
 | 
			
		||||
        echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
 | 
			
		||||
        echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
 | 
			
		||||
        echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
    - name: Checkout actions repo
 | 
			
		||||
      uses: actions/checkout@v2
 | 
			
		||||
      uses: actions/checkout@v3
 | 
			
		||||
      with:
 | 
			
		||||
        repository: Telecominfraproject/.github
 | 
			
		||||
        path: github
 | 
			
		||||
@@ -87,7 +87,7 @@ jobs:
 | 
			
		||||
      - docker
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Checkout actions repo
 | 
			
		||||
      uses: actions/checkout@v2
 | 
			
		||||
      uses: actions/checkout@v3
 | 
			
		||||
      with:
 | 
			
		||||
        repository: Telecominfraproject/.github
 | 
			
		||||
        path: github
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -11,7 +11,7 @@ jobs:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout actions repo
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          repository: Telecominfraproject/.github
 | 
			
		||||
          path: github
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								.github/workflows/openapi-pages.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,38 @@
 | 
			
		||||
name: Update OpenAPI docs on GitHub Pages
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    paths:
 | 
			
		||||
      - 'openapi/**'
 | 
			
		||||
    branches:
 | 
			
		||||
      - main
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
 | 
			
		||||
defaults:
 | 
			
		||||
  run:
 | 
			
		||||
    shell: bash
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  docsgen:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
 | 
			
		||||
      - name: Generate static HTML page with docs from OpenAPI definition
 | 
			
		||||
        run: |
 | 
			
		||||
          docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openpapi/owsec.yaml -g html2 --skip-validate-spec -o /local/
 | 
			
		||||
 | 
			
		||||
      - name: Update OpenAPI docs
 | 
			
		||||
        run: |
 | 
			
		||||
          mkdir -p ~/.ssh
 | 
			
		||||
          ssh-keyscan -H github.com >> ~/.ssh/known_hosts
 | 
			
		||||
          echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
 | 
			
		||||
          git config --global credential.helper store
 | 
			
		||||
          git config --global user.email "tip-automation@telecominfraproject.com"
 | 
			
		||||
          git config --global user.name "TIP Automation User"
 | 
			
		||||
          git pull
 | 
			
		||||
          git checkout gh-pages || git checkout -b gh-pages
 | 
			
		||||
          mv index.html docs/index.html
 | 
			
		||||
          git add docs
 | 
			
		||||
          git commit -m'Update OpenAPI docs for GitHub pages'
 | 
			
		||||
          git push --set-upstream origin gh-pages
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -17,7 +17,7 @@ jobs:
 | 
			
		||||
      HELM_REPO_USERNAME: ucentral
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout uCentral assembly chart repo
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
        uses: actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          path: wlan-cloud-ucentralsec
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						@@ -1,21 +0,0 @@
 | 
			
		||||
# Default ignored files
 | 
			
		||||
/shelf/
 | 
			
		||||
/workspace.xml
 | 
			
		||||
# Datasource local storage ignored files
 | 
			
		||||
/dataSources/
 | 
			
		||||
/dataSources.local.xml
 | 
			
		||||
# Editor-based HTTP Client requests
 | 
			
		||||
/httpRequests/
 | 
			
		||||
/certs/
 | 
			
		||||
/logs/
 | 
			
		||||
*.csr
 | 
			
		||||
*.db
 | 
			
		||||
/docker-compose/certs/
 | 
			
		||||
/docker-compose/*-data/data/
 | 
			
		||||
/docker-compose/*-data/uploads/
 | 
			
		||||
/docker-compose/.env
 | 
			
		||||
/docker-compose/.env_*
 | 
			
		||||
/cmake-build/
 | 
			
		||||
*.pem
 | 
			
		||||
result.json
 | 
			
		||||
token.json
 | 
			
		||||
							
								
								
									
										191
									
								
								BUILDING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,191 @@
 | 
			
		||||
# Building from source
 | 
			
		||||
 | 
			
		||||
In order to build the 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/AriliaWireless/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 
 | 
			
		||||
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
 | 
			
		||||
sudo apt install librdkafka-dev default-libmysqlclient-dev
 | 
			
		||||
sudo apt install nlohmann-json-dev
 | 
			
		||||
 | 
			
		||||
cd ~
 | 
			
		||||
git clone https://github.com/AriliaWireless/poco --branch poco-tip-v1
 | 
			
		||||
cd poco
 | 
			
		||||
mkdir cmake-build
 | 
			
		||||
cd cmake-build
 | 
			
		||||
cmake ..
 | 
			
		||||
cmake --build . --config Release
 | 
			
		||||
sudo cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
cd ~
 | 
			
		||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
			
		||||
cd cppkafka
 | 
			
		||||
mkdir cmake-build
 | 
			
		||||
cd cmake-build
 | 
			
		||||
cmake ..
 | 
			
		||||
cmake --build . --config Release
 | 
			
		||||
sudo cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
cd ~
 | 
			
		||||
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
 | 
			
		||||
cd valijson
 | 
			
		||||
mkdir cmake-build
 | 
			
		||||
cd cmake-build
 | 
			
		||||
cmake ..
 | 
			
		||||
cmake --build . --config Release
 | 
			
		||||
sudo cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
sudo yum install 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/AriliaWireless/poco --branch poco-tip-v1
 | 
			
		||||
cd poco
 | 
			
		||||
mkdir cmake-build
 | 
			
		||||
cd cmake-build
 | 
			
		||||
cmake ..
 | 
			
		||||
cmake --build . --config Release
 | 
			
		||||
sudo cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
git clone https://github.com/AriliaWireless/cppkafka --branch tip-v1
 | 
			
		||||
cd cppkafka
 | 
			
		||||
mkdir cmake-build
 | 
			
		||||
cd cmake-build
 | 
			
		||||
cmake ..
 | 
			
		||||
cmake --build . --config Release
 | 
			
		||||
sudo cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
cd ~
 | 
			
		||||
git clone https://github.com/AriliaWireless/valijson --branch tip-v1
 | 
			
		||||
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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 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/AriliaWireless/poco --branch poco-tip-v1
 | 
			
		||||
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/AriliaWireless/cppkafka --branch tip-v1
 | 
			
		||||
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/AriliaWireless/valijson --branch tip-v1
 | 
			
		||||
cd valijson
 | 
			
		||||
mkdir cmake-build
 | 
			
		||||
cd 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/stephb9959/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
 | 
			
		||||
```
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.13)
 | 
			
		||||
project(owsec VERSION 2.7.0)
 | 
			
		||||
project(owsec VERSION 2.9.0)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 17)
 | 
			
		||||
 | 
			
		||||
@@ -32,12 +32,12 @@ endif()
 | 
			
		||||
 | 
			
		||||
find_package(Git QUIET)
 | 
			
		||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
 | 
			
		||||
    execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
 | 
			
		||||
    execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
 | 
			
		||||
            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
			
		||||
            RESULT_VARIABLE GIT_RESULT
 | 
			
		||||
            OUTPUT_VARIABLE GIT_HASH)
 | 
			
		||||
    if(NOT GIT_RESULT EQUAL "0")
 | 
			
		||||
        message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
 | 
			
		||||
        message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
 | 
			
		||||
    endif()
 | 
			
		||||
    string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
 | 
			
		||||
endif()
 | 
			
		||||
@@ -75,19 +75,63 @@ add_executable( owsec
 | 
			
		||||
        src/framework/CountryCodes.h
 | 
			
		||||
        src/framework/KafkaTopics.h
 | 
			
		||||
        src/framework/MicroService.h
 | 
			
		||||
        src/framework/OpenWifiTypes.h
 | 
			
		||||
        src/framework/orm.h
 | 
			
		||||
        src/framework/StorageClass.h
 | 
			
		||||
        src/framework/ow_constants.h
 | 
			
		||||
        src/framework/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/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
 | 
			
		||||
        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
 | 
			
		||||
        src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
 | 
			
		||||
        src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
 | 
			
		||||
 | 
			
		||||
        src/seclibs/qrcode/qrcodegen.hpp src/seclibs/qrcode/qrcodegen.cpp
 | 
			
		||||
        src/seclibs/cpptotp/bytes.cpp src/seclibs/cpptotp/bytes.h
 | 
			
		||||
        src/seclibs/cpptotp/otp.cpp src/seclibs/cpptotp/otp.h
 | 
			
		||||
        src/seclibs/cpptotp/sha1.cpp src/seclibs/cpptotp/sha1.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
 | 
			
		||||
        src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
 | 
			
		||||
        src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
 | 
			
		||||
        src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
 | 
			
		||||
        src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
 | 
			
		||||
        src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
 | 
			
		||||
@@ -119,14 +163,19 @@ add_executable( owsec
 | 
			
		||||
        src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
 | 
			
		||||
        src/ActionLinkManager.cpp src/ActionLinkManager.h
 | 
			
		||||
        src/ACLProcessor.h
 | 
			
		||||
        src/framework/OpenWifiTypes.h
 | 
			
		||||
        src/storage/orm_users.cpp src/storage/orm_users.h
 | 
			
		||||
        src/storage/orm_tokens.cpp src/storage/orm_tokens.h
 | 
			
		||||
        src/storage/orm_preferences.cpp src/storage/orm_preferences.h
 | 
			
		||||
        src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
 | 
			
		||||
        src/storage/orm_avatar.cpp src/storage/orm_avatar.h
 | 
			
		||||
        src/SpecialUserHelpers.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h src/MessagingTemplates.cpp src/MessagingTemplates.h)
 | 
			
		||||
        src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_totp_handler.cpp
 | 
			
		||||
        src/RESTAPI/RESTAPI_totp_handler.h
 | 
			
		||||
        src/TotpCache.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h
 | 
			
		||||
        src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h
 | 
			
		||||
        src/MessagingTemplates.h src/RESTAPI/RESTAPI_apiKey_handler.cpp src/RESTAPI/RESTAPI_apiKey_handler.h src/storage/orm_apikeys.cpp src/storage/orm_apikeys.h src/RESTAPI/RESTAPI_validate_apikey.cpp src/RESTAPI/RESTAPI_validate_apikey.h src/RESTAPI/RESTAPI_systemSecret_handler.cpp src/RESTAPI/RESTAPI_systemSecret_handler.h src/SecretStore.cpp src/SecretStore.h)
 | 
			
		||||
 | 
			
		||||
if(NOT SMALL_BUILD)
 | 
			
		||||
    target_link_libraries(owsec PUBLIC
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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. 
 | 
			
		||||
							
								
								
									
										104
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						@@ -1,18 +1,15 @@
 | 
			
		||||
ARG ALPINE_VERSION=3.16.2
 | 
			
		||||
ARG POCO_VERSION=poco-tip-v1
 | 
			
		||||
ARG FMTLIB_VERSION=9.0.0
 | 
			
		||||
ARG DEBIAN_VERSION=11.5-slim
 | 
			
		||||
ARG POCO_VERSION=poco-tip-v2
 | 
			
		||||
ARG CPPKAFKA_VERSION=tip-v1
 | 
			
		||||
ARG JSON_VALIDATOR_VERSION=2.1.0
 | 
			
		||||
ARG AWS_SDK_VERSION=1.9.315
 | 
			
		||||
ARG VALIJASON_VERSION=tip-v1
 | 
			
		||||
 | 
			
		||||
FROM alpine:$ALPINE_VERSION AS build-base
 | 
			
		||||
FROM debian:$DEBIAN_VERSION AS build-base
 | 
			
		||||
 | 
			
		||||
RUN apk add --update --no-cache \
 | 
			
		||||
    make cmake g++ git \
 | 
			
		||||
    unixodbc-dev postgresql-dev mariadb-dev \
 | 
			
		||||
    librdkafka-dev boost-dev openssl-dev \
 | 
			
		||||
    zlib-dev nlohmann-json \
 | 
			
		||||
    curl-dev
 | 
			
		||||
RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
			
		||||
    make cmake g++ git curl zip unzip pkg-config \
 | 
			
		||||
    libpq-dev libmariadb-dev libmariadbclient-dev-compat \
 | 
			
		||||
    librdkafka-dev libboost-all-dev libssl-dev \
 | 
			
		||||
    zlib1g-dev ca-certificates libcurl4-openssl-dev libfmt-dev
 | 
			
		||||
 | 
			
		||||
FROM build-base AS poco-build
 | 
			
		||||
 | 
			
		||||
@@ -28,20 +25,6 @@ RUN cmake ..
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
RUN cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
FROM build-base AS fmtlib-build
 | 
			
		||||
 | 
			
		||||
ARG FMTLIB_VERSION
 | 
			
		||||
 | 
			
		||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
 | 
			
		||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
 | 
			
		||||
 | 
			
		||||
WORKDIR /fmtlib
 | 
			
		||||
RUN mkdir cmake-build
 | 
			
		||||
WORKDIR cmake-build
 | 
			
		||||
RUN cmake ..
 | 
			
		||||
RUN make
 | 
			
		||||
RUN make install
 | 
			
		||||
 | 
			
		||||
FROM build-base AS cppkafka-build
 | 
			
		||||
 | 
			
		||||
ARG CPPKAFKA_VERSION
 | 
			
		||||
@@ -56,79 +39,61 @@ RUN cmake ..
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
RUN cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
FROM build-base AS json-schema-validator-build
 | 
			
		||||
FROM build-base AS valijson-build
 | 
			
		||||
 | 
			
		||||
ARG JSON_VALIDATOR_VERSION
 | 
			
		||||
ARG VALIJASON_VERSION
 | 
			
		||||
 | 
			
		||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
 | 
			
		||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
 | 
			
		||||
ADD https://api.github.com/repos/AriliaWireless/valijson/git/refs/tags/${VALIJASON_VERSION} version.json
 | 
			
		||||
RUN git clone https://github.com/AriliaWireless/valijson --branch ${VALIJASON_VERSION} /valijson
 | 
			
		||||
 | 
			
		||||
WORKDIR /json-schema-validator
 | 
			
		||||
WORKDIR /valijson
 | 
			
		||||
RUN mkdir cmake-build
 | 
			
		||||
WORKDIR cmake-build
 | 
			
		||||
RUN cmake ..
 | 
			
		||||
RUN make
 | 
			
		||||
RUN make install
 | 
			
		||||
 | 
			
		||||
FROM build-base AS aws-sdk-cpp-build
 | 
			
		||||
 | 
			
		||||
ARG AWS_SDK_VERSION
 | 
			
		||||
 | 
			
		||||
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json
 | 
			
		||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp
 | 
			
		||||
 | 
			
		||||
WORKDIR /aws-sdk-cpp
 | 
			
		||||
RUN mkdir cmake-build
 | 
			
		||||
WORKDIR cmake-build
 | 
			
		||||
RUN cmake .. -DBUILD_ONLY="sns;s3" \
 | 
			
		||||
             -DCMAKE_BUILD_TYPE=Release \
 | 
			
		||||
             -DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \
 | 
			
		||||
             -DAUTORUN_UNIT_TESTS=OFF
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
RUN cmake --build . --target install
 | 
			
		||||
 | 
			
		||||
FROM build-base AS owsec-build
 | 
			
		||||
 | 
			
		||||
ADD CMakeLists.txt build /owsec/
 | 
			
		||||
ADD overlays /owsec/overlays
 | 
			
		||||
ADD cmake /owsec/cmake
 | 
			
		||||
ADD src /owsec/src
 | 
			
		||||
ADD .git /owsec/.git
 | 
			
		||||
ARG VCPKG_VERSION=2022.11.14
 | 
			
		||||
RUN git clone --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg && \
 | 
			
		||||
    ./vcpkg/bootstrap-vcpkg.sh && \
 | 
			
		||||
    mkdir /vcpkg/custom-triplets && \
 | 
			
		||||
    cp /vcpkg/triplets/x64-linux.cmake /vcpkg/custom-triplets/x64-linux.cmake && \
 | 
			
		||||
    sed -i 's/set(VCPKG_LIBRARY.*/set(VCPKG_LIBRARY_LINKAGE dynamic)/g' /vcpkg/custom-triplets/x64-linux.cmake && \
 | 
			
		||||
    ./vcpkg/vcpkg install aws-sdk-cpp[sns]:x64-linux json-schema-validator:x64-linux --overlay-triplets=/vcpkg/custom-triplets --overlay-ports=/owsec/overlays
 | 
			
		||||
 | 
			
		||||
COPY --from=poco-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
 | 
			
		||||
COPY --from=cppkafka-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
 | 
			
		||||
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
 | 
			
		||||
 | 
			
		||||
COPY --from=fmtlib-build /usr/local/include /usr/local/include
 | 
			
		||||
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
 | 
			
		||||
 | 
			
		||||
WORKDIR /owsec
 | 
			
		||||
RUN mkdir cmake-build
 | 
			
		||||
WORKDIR /owsec/cmake-build
 | 
			
		||||
RUN cmake .. \
 | 
			
		||||
          -Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
 | 
			
		||||
          -DBUILD_SHARED_LIBS=ON
 | 
			
		||||
RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
 | 
			
		||||
RUN cmake --build . --config Release -j8
 | 
			
		||||
 | 
			
		||||
FROM alpine:$ALPINE_VERSION
 | 
			
		||||
FROM debian:$DEBIAN_VERSION
 | 
			
		||||
 | 
			
		||||
ENV OWSEC_USER=owsec \
 | 
			
		||||
    OWSEC_ROOT=/owsec-data \
 | 
			
		||||
    OWSEC_CONFIG=/owsec-data
 | 
			
		||||
 | 
			
		||||
RUN addgroup -S "$OWSEC_USER" && \
 | 
			
		||||
    adduser -S -G "$OWSEC_USER" "$OWSEC_USER"
 | 
			
		||||
RUN useradd "$OWSEC_USER"
 | 
			
		||||
 | 
			
		||||
RUN mkdir /openwifi
 | 
			
		||||
RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
 | 
			
		||||
    chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
 | 
			
		||||
 | 
			
		||||
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
 | 
			
		||||
    mariadb-connector-c libpq unixodbc postgresql-client
 | 
			
		||||
RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
			
		||||
    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
			
		||||
    libmariadb-dev-compat libpq5 postgresql-client libfmt7
 | 
			
		||||
 | 
			
		||||
COPY readiness_check /readiness_check
 | 
			
		||||
COPY test_scripts/curl/cli /cli
 | 
			
		||||
@@ -139,14 +104,15 @@ COPY templates /dist/templates
 | 
			
		||||
COPY docker-entrypoint.sh /
 | 
			
		||||
COPY wait-for-postgres.sh /
 | 
			
		||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
			
		||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
			
		||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
 | 
			
		||||
 | 
			
		||||
COPY --from=owsec-build /owsec/cmake-build/owsec /openwifi/owsec
 | 
			
		||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
 | 
			
		||||
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib
 | 
			
		||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
 | 
			
		||||
COPY --from=owsec-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
 | 
			
		||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/ /usr/local/lib/
 | 
			
		||||
COPY --from=poco-build /poco/cmake-build/lib/ /usr/local/lib/
 | 
			
		||||
COPY --from=valijson-build /usr/local/include /usr/local/include
 | 
			
		||||
 | 
			
		||||
RUN ldconfig
 | 
			
		||||
 | 
			
		||||
EXPOSE 16001 17001 16101
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										310
									
								
								README.md
									
									
									
									
									
								
							
							
						
						@@ -1,66 +1,100 @@
 | 
			
		||||
# ucentralsec
 | 
			
		||||
<p align="center">
 | 
			
		||||
    <img src="images/project/logo.svg" width="200"/>
 | 
			
		||||
</p>
 | 
			
		||||
 | 
			
		||||
uCentralSec is the Authentication & Resource Policy Access service for the uCentral system. In order to use the uCentral system
 | 
			
		||||
you must have at least 1 uCentralSec. uCentralSec is the first point of contact for the entire architecture. We strongly recommend using Docker 
 | 
			
		||||
to deploy all the uCentral services. If you would like to develop and play with the source, please do.
 | 
			
		||||
# OpenWiFi Security  (OWSEC)
 | 
			
		||||
 | 
			
		||||
## What is it?
 | 
			
		||||
The OWSEC is a service for the TIP OpenWiFi CloudSDK (OWSDK).
 | 
			
		||||
OWSEC is the Authentication and Resource Policy Access service for the TIP
 | 
			
		||||
OpenWiFi Cloud SDK (OWSDK). OWSEC,
 | 
			
		||||
like all other OWSDK microservices, is defined using an OpenAPI definition and uses the ucentral communication
 | 
			
		||||
protocol to interact with Access Points. To use the OWSUB, you either need to [build it](#building) or use the
 | 
			
		||||
[Docker version](#docker).
 | 
			
		||||
 | 
			
		||||
## Building
 | 
			
		||||
To build the microservice from source, please follow the instructions in [here](./BUILDING.md)
 | 
			
		||||
 | 
			
		||||
## Docker
 | 
			
		||||
To use the CLoudSDK deployment please follow [here](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy)
 | 
			
		||||
 | 
			
		||||
## OpenAPI
 | 
			
		||||
Like all other uCentral services, uCentralSec is defined through an OpenAPI. You can use this API to build your own applications or integration modules
 | 
			
		||||
into your own systems. If all you need it to access the uCentralGW for example (the service that manages the APs), you will need to:
 | 
			
		||||
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
 | 
			
		||||
Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openapi/owsec.yaml)) to get interactive docs page.
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
Like all other OWSDK services, OWSEC is defined through an OpenAPI. You can use this API to build your own 
 | 
			
		||||
applications or integration modules into your own systems. If all you need it to access the OWGW for 
 | 
			
		||||
example (the service that manages the APs), you will need to:
 | 
			
		||||
- get a token (`/oauth2`)
 | 
			
		||||
- find the endpoints on the system (`/systemEndpoints`) 
 | 
			
		||||
- choose one to manage (pick an endpoint that matches what you are trying to do by looking at its `type`. For the gateway, type = ucentrtalgw)
 | 
			
		||||
- make your calls (use the PublicEndPoint of the corresponding entry to make your calls, do not forget to add `/api/v1` as the root os the call)
 | 
			
		||||
- choose a microservice to manage (pick an endpoint that matches what you are trying to do by looking at its 
 | 
			
		||||
`type`. For the Cloud SDK Controller, type = owgw)
 | 
			
		||||
- make your calls (use the PublicEndPoint of the corresponding entry to make your calls, 
 | 
			
		||||
do not forget to add `/api/v1` as the root os the call)
 | 
			
		||||
 | 
			
		||||
The CLI for the [uCentralGW](https://github.com/telecominfraproject/wlan-cloud-ucentralgw/blob/main/test_scripts/curl/cli) has a very good example of this. 
 | 
			
		||||
Look for the `setgateway` function.
 | 
			
		||||
The CLI for the [OWGW](https://github.com/telecominfraproject/wlan-cloud-ucentralsec/blob/main/test_scripts/curl/cli) has 
 | 
			
		||||
a very good example of this. Look for the `setgateway` function.
 | 
			
		||||
 | 
			
		||||
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralsec/).
 | 
			
		||||
 | 
			
		||||
Also, you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://validator.swagger.io/validator?url=https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralsec/main/openpapi/owsec.yaml)) to get interactive docs page.
 | 
			
		||||
 | 
			
		||||
#### Expected directory layout
 | 
			
		||||
From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories.
 | 
			
		||||
```bash
 | 
			
		||||
mkdir certs
 | 
			
		||||
mkdir certs/cas
 | 
			
		||||
mkdir logs
 | 
			
		||||
mkdir uploads
 | 
			
		||||
```
 | 
			
		||||
You should now have the following:
 | 
			
		||||
```text
 | 
			
		||||
--+-- certs
 | 
			
		||||
  |   +--- cas
 | 
			
		||||
  +-- cmake
 | 
			
		||||
  +-- cmake-build
 | 
			
		||||
  +-- logs
 | 
			
		||||
  +-- src
 | 
			
		||||
  +-- test_scripts
 | 
			
		||||
  +-- openapi
 | 
			
		||||
  +-- uploads
 | 
			
		||||
  +-- owsec.properties
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Certificate
 | 
			
		||||
The OWSEC uses a certificate to provide security for the REST API Certificate to secure the Northbound API.
 | 
			
		||||
 | 
			
		||||
#### The `certs` directory
 | 
			
		||||
For all deployments, you will need the following `certs` directory, populated with the proper files.
 | 
			
		||||
 | 
			
		||||
```text
 | 
			
		||||
certs ---+--- restapi-ca.pem
 | 
			
		||||
         +--- restapi-cert.pem
 | 
			
		||||
         +--- restapi-key.pem
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Firewall Considerations
 | 
			
		||||
The entire uCentral systems uses several MicroServices. In order for the whole system to work, you should provide the following port
 | 
			
		||||
access:
 | 
			
		||||
| Port  | Description                                | Configurable |
 | 
			
		||||
|:------|:-------------------------------------------|:------------:|
 | 
			
		||||
| 16001 | Default port from the devices to the OWSEC |     yes      |
 | 
			
		||||
 | 
			
		||||
- Security
 | 
			
		||||
  - Properties file: owsec.properties
 | 
			
		||||
  - Ports
 | 
			
		||||
    - Public: 16001
 | 
			
		||||
    - Private: 17001
 | 
			
		||||
    - ALB: 16101
 | 
			
		||||
### Environment variables
 | 
			
		||||
The following environment variables should be set from the root directory of the service. They tell the OWGW process where to find
 | 
			
		||||
the configuration and the root directory.
 | 
			
		||||
```bash
 | 
			
		||||
export OWGW_ROOT=`pwd`
 | 
			
		||||
export OWGW_CONFIG=`pwd`
 | 
			
		||||
```
 | 
			
		||||
You can run the shell script `set_env.sh` from the microservice root.
 | 
			
		||||
 | 
			
		||||
- Gateway:
 | 
			
		||||
  - Properties file: owgw.properties
 | 
			
		||||
  - Ports
 | 
			
		||||
    - Public: 16002
 | 
			
		||||
    - Private: 17002
 | 
			
		||||
    - ALB: 16102
 | 
			
		||||
 | 
			
		||||
- Firmware:
 | 
			
		||||
  - Properties file: owfms.properties
 | 
			
		||||
  - Ports
 | 
			
		||||
    - Public: 16004
 | 
			
		||||
    - Private: 17004
 | 
			
		||||
    - ALB: 16104
 | 
			
		||||
 | 
			
		||||
- Provisioning:
 | 
			
		||||
  - Properties file: owprov.properties
 | 
			
		||||
  - Ports
 | 
			
		||||
    - Public: 16004
 | 
			
		||||
    - Private: 17004
 | 
			
		||||
    - ALB: 16104
 | 
			
		||||
 | 
			
		||||
## Security Configuration
 | 
			
		||||
The service relies on a properties configuration file called `owsec.properties`. In this file, you should configure several entries. Many values are optional 
 | 
			
		||||
and you can rely on the defaults. Here are some values of note:
 | 
			
		||||
 | 
			
		||||
### `authentication.default.password`
 | 
			
		||||
Set the hash of the default username and password. Please look below on how to do this. 
 | 
			
		||||
 | 
			
		||||
### `authentication.default.username`
 | 
			
		||||
Set the default username to use to login.
 | 
			
		||||
### OWSEC Service Configuration
 | 
			
		||||
The configuration is kept in a file called `owsec.properties`. To understand the content of this file,
 | 
			
		||||
please look [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/CONFIGURATION.md)
 | 
			
		||||
 | 
			
		||||
### Default username and password
 | 
			
		||||
The default username and password are set in `owsec.properties` file. The following entries manage the username and password
 | 
			
		||||
```text
 | 
			
		||||
```properties
 | 
			
		||||
authentication.default.username = tip@ucentral.com
 | 
			
		||||
authentication.default.password = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 | 
			
		||||
```
 | 
			
		||||
@@ -75,36 +109,17 @@ echo -n "weLoveWifiroot@system.com" | shasum -a 256
 | 
			
		||||
b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c  -
 | 
			
		||||
```
 | 
			
		||||
Then you need to modify your properties file like this
 | 
			
		||||
```text
 | 
			
		||||
```properties
 | 
			
		||||
authentication.default.username = root@system.com
 | 
			
		||||
authentication.default.password = b5bfed31e2a272e52973a57b95042ab842db3999475f3d79f1ce0f45f465e34c
 | 
			
		||||
```
 | 
			
		||||
Remember, when you login, use `root@system.com` with the password `weLoveWifi`, not this monster digit sequence.
 | 
			
		||||
 | 
			
		||||
#### Is this safe?
 | 
			
		||||
Is this safe to show the hash in a text file? Let me put it this way, if you can find a way to break this encryption, you
 | 
			
		||||
would have control over the entire internet. It's incredibly safe. If you love math, you can find a lot of videos explaining
 | 
			
		||||
how hashes work and why they are safe.
 | 
			
		||||
 | 
			
		||||
### `authentication.validation.expression`
 | 
			
		||||
This is a regular expression (regex) to verify the incoming password. You can find many examples on the internet on how to create these expressions. I suggest 
 | 
			
		||||
that using Google is your friend. Someone has figured out what you want to do already. Click [here](https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a)
 | 
			
		||||
to get a sample. The default is
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### `authentication.oldpasswords`
 | 
			
		||||
The number of older passwords to keep. Default is 5.
 | 
			
		||||
 | 
			
		||||
### Changing default password
 | 
			
		||||
 | 
			
		||||
On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
 | 
			
		||||
 | 
			
		||||
You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```bash
 | 
			
		||||
export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
 | 
			
		||||
#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
 | 
			
		||||
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
 | 
			
		||||
@@ -115,7 +130,7 @@ test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD
 | 
			
		||||
 | 
			
		||||
CLI is also included in Docker image if you want to run it this way:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
```bash
 | 
			
		||||
export OWSEC=openwifi.wlan.local:16001
 | 
			
		||||
#export FLAGS="-k"
 | 
			
		||||
export OWSEC_DEFAULT_USERNAME=root@system.com
 | 
			
		||||
@@ -132,136 +147,25 @@ docker run --rm -ti \
 | 
			
		||||
  /cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Kafka integration
 | 
			
		||||
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
 | 
			
		||||
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
openwifi.kafka.group.id = security
 | 
			
		||||
openwifi.kafka.client.id = security1
 | 
			
		||||
openwifi.kafka.enable = true
 | 
			
		||||
openwifi.kafka.brokerlist = my.kafkaserver.arilia.com:9092
 | 
			
		||||
openwifi.kafka.auto.commit = false
 | 
			
		||||
openwifi.kafka.queue.buffering.max.ms = 50
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### `openwifi.kafka.brokerlist`
 | 
			
		||||
This is the list of your kafka brokers. This is a comma separated list. You should use IP addresses or FQDNs and the relevant ports, usually 9092 is the 
 | 
			
		||||
default.
 | 
			
		||||
 | 
			
		||||
#### `openwifi.kafka.group.id`
 | 
			
		||||
Every service on the Kafka bux must have a unique value (at least in our case). This should be a string. We suggest using a name corresponding to the 
 | 
			
		||||
function provided. In this case, security.
 | 
			
		||||
 | 
			
		||||
### Certificates
 | 
			
		||||
Of course we need certificates. In our case, we already have existing certificates we have. You should find out how your file name correspond
 | 
			
		||||
to our names. We suggest reusing the same names we use so it is easier to use our default configuration files. We suggest using proper certificates 
 | 
			
		||||
for the publicly visible interfaces. For private interfaces, self-signed certificates are OK. We will not describe how to use/create private certificates 
 | 
			
		||||
here.
 | 
			
		||||
 | 
			
		||||
#### The public interface
 | 
			
		||||
Here are the parameters for the public interface. The important files are:
 | 
			
		||||
- `restapi-ca.pem` : the CA of your certificate
 | 
			
		||||
- `restapi-cert.pem` : the certificate for the public interface
 | 
			
		||||
- `restapi-key.pem` : the key associated with this certificate
 | 
			
		||||
- `openwifi.restapi.host.0.key.password` : if you key is password protected, you may supply that password here.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
openwifi.restapi.host.0.backlog = 100
 | 
			
		||||
openwifi.restapi.host.0.security = relaxed
 | 
			
		||||
openwifi.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
 | 
			
		||||
openwifi.restapi.host.0.address = *
 | 
			
		||||
openwifi.restapi.host.0.port = 16001
 | 
			
		||||
openwifi.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
 | 
			
		||||
openwifi.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
			
		||||
openwifi.restapi.host.0.key.password = mypassword
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### The private interface
 | 
			
		||||
The private interface is used for service-to-service communication. You can use self-signed certificates here or letsencrypt. The file names are similar 
 | 
			
		||||
to the filenames used in the previous section.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
openwifi.internal.restapi.host.0.backlog = 100
 | 
			
		||||
openwifi.internal.restapi.host.0.security = relaxed
 | 
			
		||||
openwifi.internal.restapi.host.0.rootca = $OWSEC_ROOT/certs/restapi-ca.pem
 | 
			
		||||
openwifi.internal.restapi.host.0.address = *
 | 
			
		||||
openwifi.internal.restapi.host.0.port = 17001
 | 
			
		||||
openwifi.internal.restapi.host.0.cert = $OWSEC_ROOT/certs/restapi-cert.pem
 | 
			
		||||
openwifi.internal.restapi.host.0.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
			
		||||
openwifi.internal.restapi.host.0.key.password = mypassword
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Other important values
 | 
			
		||||
Here are other important values you must set.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
openwifi.system.data = $OWSEC_ROOT/data
 | 
			
		||||
openwifi.system.uri.private = https://localhost:17001
 | 
			
		||||
openwifi.system.uri.public = https://openwifi.dpaas.arilia.com:16001
 | 
			
		||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
 | 
			
		||||
openwifi.system.commandchannel = /tmp/app.ucentralsec
 | 
			
		||||
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
 | 
			
		||||
openwifi.service.key.password = mypassword
 | 
			
		||||
```
 | 
			
		||||
#### `openwifi.system.data`
 | 
			
		||||
The location of some important data files including the user name database.
 | 
			
		||||
 | 
			
		||||
#### `openwifi.system.uri.private`
 | 
			
		||||
This is the FQDN used internally between services.
 | 
			
		||||
 | 
			
		||||
#### `openwifi.system.uri.public`
 | 
			
		||||
This is the FQDN used externally serving the OpenAPI interface.
 | 
			
		||||
 | 
			
		||||
### Sending SMS for Multifactor Aithentication
 | 
			
		||||
`owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so,
 | 
			
		||||
an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS
 | 
			
		||||
 | 
			
		||||
#### AWS SMS
 | 
			
		||||
For SNS you must create an IAM ID that has sns:sendmessage rights.  
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
smssender.enabled = true
 | 
			
		||||
smssender.provider = aws
 | 
			
		||||
smssender.aws.secretkey = ***************************************
 | 
			
		||||
smssender.aws.accesskey = ***************************************
 | 
			
		||||
smssender.aws.region = **************
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Twilio
 | 
			
		||||
For Twilio, you must provide the following
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
smssender.enabled = true
 | 
			
		||||
smssender.provider = twilio
 | 
			
		||||
smssender.twilio.sid = ***********************
 | 
			
		||||
smssender.twilio.token = **********************
 | 
			
		||||
smssender.twilio.phonenumber = +18888888888
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### `owsec` Messaging Configuration
 | 
			
		||||
`owsec` nay require to send e-mails. In order to do so, you must configure an email sender. We have run tests 
 | 
			
		||||
with GMail and AWS SES. For each, you must obtain the proper credentials and insert them in this configuration as well
 | 
			
		||||
as the proper mail host.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
mailer.enabled = true
 | 
			
		||||
mailer.hostname = smtp.gmail.com
 | 
			
		||||
mailer.username = ************************
 | 
			
		||||
mailer.password = ************************
 | 
			
		||||
mailer.sender = OpenWIFI
 | 
			
		||||
mailer.loginmethod = login
 | 
			
		||||
mailer.port = 587
 | 
			
		||||
mailer.templates = $OWSEC_ROOT/templates
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Google Authenticator
 | 
			
		||||
In order to use the Google Time-based One-Time Password (TOTP), the user must download the Google Authenticator 
 | 
			
		||||
on any other app that support the TOTP protocol. You should include the following in your configuration
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
totp.issuer = OrgName
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It is very important that you not use spaces in your OrgName.
 | 
			
		||||
## Kafka topics
 | 
			
		||||
Toe read more about Kafka, follow the [document](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/KAFKA.md)
 | 
			
		||||
 | 
			
		||||
## Contributions
 | 
			
		||||
We need more contributors. Should you wish to contribute,
 | 
			
		||||
please follow the [contributions](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/CONTRIBUTING.md) document.
 | 
			
		||||
 | 
			
		||||
## Pull Requests
 | 
			
		||||
Please create a branch with the Jira addressing the issue you are fixing or the feature you are implementing.
 | 
			
		||||
Create a pull-request from the branch into master.
 | 
			
		||||
 | 
			
		||||
## Additional OWSDK Microservices
 | 
			
		||||
Here is a list of additional OWSDK microservices
 | 
			
		||||
| Name | Description | Link | OpenAPI |
 | 
			
		||||
| :--- | :--- | :---: | :---: |
 | 
			
		||||
| OWSEC | Security Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml) |
 | 
			
		||||
| OWGW | Controller Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/openapi/owgw.yaml) |
 | 
			
		||||
| OWFMS | Firmware Management Service | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms) | [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralfms/blob/main/openapi/owfms.yaml) |
 | 
			
		||||
| OWPROV | Provisioning Service | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov) | [here](https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/owprov.yaml) |
 | 
			
		||||
| OWANALYTICS | Analytics Service | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics) | [here](https://github.com/Telecominfraproject/wlan-cloud-analytics/blob/main/openapi/owanalytics.yaml) |
 | 
			
		||||
| OWSUB | Subscriber Service | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal) | [here](https://github.com/Telecominfraproject/wlan-cloud-userportal/blob/main/openapi/userportal.yaml) |
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
 | 
			
		||||
@@ -85,7 +85,7 @@ if [ "$1" = '/openwifi/owsec' -a "$(id -u)" = '0' ]; then
 | 
			
		||||
    if [ "$RUN_CHOWN" = 'true' ]; then
 | 
			
		||||
      chown -R "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
 | 
			
		||||
    fi
 | 
			
		||||
    exec su-exec "$OWSEC_USER" "$@"
 | 
			
		||||
    exec gosu "$OWSEC_USER" "$@"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
exec "$@"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
			
		||||
images:
 | 
			
		||||
  owsec:
 | 
			
		||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
 | 
			
		||||
    tag: v2.7.0-RC3
 | 
			
		||||
    tag: v2.9.0
 | 
			
		||||
    pullPolicy: Always
 | 
			
		||||
#    regcred:
 | 
			
		||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
			
		||||
@@ -92,7 +92,7 @@ resources: {}
 | 
			
		||||
  #  memory: 128Mi
 | 
			
		||||
 | 
			
		||||
securityContext:
 | 
			
		||||
  fsGroup: 101
 | 
			
		||||
  fsGroup: 1000
 | 
			
		||||
 | 
			
		||||
nodeSelector: {}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf160d.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 104 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf188.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf188n.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf194c.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 75 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf194c4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 75 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf808.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 218 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/cig_wf809.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 158 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_eap101.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 140 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_eap102.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 121 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecs4100-12ph.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 44 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecw5211.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 192 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ecw5410.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 197 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_oap100.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 50 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_spw2ac1200-lan-poe.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_spw2ac1200.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/edgecore_ssw2ac2600.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 51 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/hfcl_ion4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 72 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/hfcl_ion4.yml.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 72 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/indio_um-305ac.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_e8450-ubi.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 98 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea6350-v4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 89 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea6350.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 89 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/linksys_ea8300.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 204 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tp-link_ec420-g1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 159 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ec420.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 159 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex227.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 103 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex228.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 103 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/tplink_ex447.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 103 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr40x9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 59 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr6018.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								images/device_types/wallys_dr6018_v4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 80 KiB  | 
| 
		 Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB  | 
							
								
								
									
										165
									
								
								images/project/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,165 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
			
		||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
			
		||||
	 viewBox="0 0 141.5 185.6" style="enable-background:new 0 0 141.5 185.6;" xml:space="preserve">
 | 
			
		||||
<style type="text/css">
 | 
			
		||||
	.st0{fill:#414141;}
 | 
			
		||||
	.st1{fill:#FFFFFF;}
 | 
			
		||||
	.st2{fill:#FED206;}
 | 
			
		||||
	.st3{fill:#EB6F53;}
 | 
			
		||||
	.st4{fill:#3BA9B6;}
 | 
			
		||||
</style>
 | 
			
		||||
<g>
 | 
			
		||||
	<g>
 | 
			
		||||
		<path class="st0" d="M120.7,183.9H21.5c-10.8,0-19.5-8.7-19.5-19.5V20.5c0-10.8,8.7-19.5,19.5-19.5h99.2
 | 
			
		||||
			c10.8,0,19.5,8.7,19.5,19.5v143.9C140.2,175.2,131.5,183.9,120.7,183.9z"/>
 | 
			
		||||
		<g>
 | 
			
		||||
			<g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M46.3,166.2v-3.4h-1.2v-0.6h3.1v0.6H47v3.4H46.3z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M49,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H49z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M52.6,166.2v-4h0.7v3.4h1.8v0.6H52.6z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M55.7,166.2v-4h2.7v0.6h-2v1h2v0.6h-2v1.1h2v0.6H55.7z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M59.1,164.2c0-1.2,0.9-2.1,2.1-2.1c0.8,0,1.3,0.4,1.6,0.9l-0.6,0.3c-0.2-0.3-0.6-0.6-1-0.6
 | 
			
		||||
						c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.4,0,0.8-0.3,1-0.6l0.6,0.3c-0.3,0.5-0.8,0.9-1.6,0.9
 | 
			
		||||
						C60,166.3,59.1,165.5,59.1,164.2z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M63.2,164.2c0-1.2,0.8-2.1,2-2.1c1.2,0,2,0.9,2,2.1c0,1.2-0.8,2.1-2,2.1C64,166.3,63.2,165.4,63.2,164.2z
 | 
			
		||||
						 M66.5,164.2c0-0.8-0.5-1.4-1.3-1.4c-0.8,0-1.3,0.6-1.3,1.4c0,0.8,0.5,1.4,1.3,1.4C66,165.7,66.5,165,66.5,164.2z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M71.3,166.2v-3.1l-1.2,3.1h-0.3l-1.2-3.1v3.1h-0.7v-4h1l1.1,2.7l1.1-2.7h1v4H71.3z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M75.7,166.2v-4h0.7v4H75.7z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M80.4,166.2l-2.1-2.8v2.8h-0.7v-4h0.7l2,2.8v-2.8h0.7v4H80.4z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M82.3,166.2v-4H85v0.6h-2v1h2v0.6h-2v1.7H82.3z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M87.9,166.2l-0.9-1.5h-0.7v1.5h-0.7v-4h1.7c0.8,0,1.3,0.5,1.3,1.2c0,0.7-0.5,1.1-0.9,1.2l1,1.6H87.9z
 | 
			
		||||
						 M88,163.5c0-0.4-0.3-0.6-0.7-0.6h-1v1.3h1C87.7,164.1,88,163.9,88,163.5z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M92.4,166.2l-0.3-0.8h-1.8l-0.3,0.8h-0.8l1.6-4h0.9l1.6,4H92.4z M91.2,162.9l-0.7,1.9h1.4L91.2,162.9z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M95.8,166.2v-4h1.5c0.8,0,1.2,0.5,1.2,1.2c0,0.6-0.4,1.2-1.2,1.2h-1.2v1.7H95.8z M98.2,163.4
 | 
			
		||||
						c0-0.5-0.3-0.9-0.9-0.9h-1.1v1.7h1.1C97.8,164.3,98.2,163.9,98.2,163.4z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M101.5,166.2l-1.1-1.6h-0.9v1.6h-0.3v-4h1.5c0.7,0,1.2,0.4,1.2,1.2c0,0.7-0.5,1.1-1.1,1.1l1.2,1.7H101.5z
 | 
			
		||||
						 M101.6,163.4c0-0.5-0.4-0.9-0.9-0.9h-1.1v1.7h1.1C101.2,164.3,101.6,163.9,101.6,163.4z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M102.8,164.2c0-1.2,0.8-2.1,1.9-2.1c1.2,0,1.9,0.9,1.9,2.1c0,1.2-0.8,2.1-1.9,2.1
 | 
			
		||||
						C103.6,166.3,102.8,165.4,102.8,164.2z M106.3,164.2c0-1-0.6-1.7-1.6-1.7c-1,0-1.6,0.7-1.6,1.7c0,1,0.6,1.7,1.6,1.7
 | 
			
		||||
						C105.7,166,106.3,165.2,106.3,164.2z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M106.9,165.8l0.2-0.3c0.2,0.2,0.4,0.4,0.8,0.4c0.5,0,0.9-0.4,0.9-0.9v-2.8h0.3v2.8c0,0.8-0.5,1.2-1.2,1.2
 | 
			
		||||
						C107.5,166.3,107.2,166.1,106.9,165.8z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M110.4,166.2v-4h2.5v0.3h-2.2v1.5h2.1v0.3h-2.1v1.6h2.2v0.3H110.4z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M113.5,164.2c0-1.2,0.9-2.1,2-2.1c0.6,0,1.1,0.3,1.5,0.7l-0.3,0.2c-0.3-0.3-0.7-0.6-1.2-0.6
 | 
			
		||||
						c-0.9,0-1.7,0.7-1.7,1.7c0,1,0.7,1.7,1.7,1.7c0.5,0,0.9-0.2,1.2-0.6l0.3,0.2c-0.4,0.4-0.8,0.7-1.5,0.7
 | 
			
		||||
						C114.4,166.3,113.5,165.5,113.5,164.2z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st1" d="M118.7,166.2v-3.7h-1.3v-0.3h2.9v0.3H119v3.7H118.7z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
			</g>
 | 
			
		||||
			<g>
 | 
			
		||||
				<polygon class="st1" points="26.3,163.8 31.6,158.5 36.9,163.8 37.7,163.8 31.6,157.6 25.5,163.8 				"/>
 | 
			
		||||
				<polygon class="st1" points="36.9,164.7 31.6,170 26.3,164.7 25.5,164.7 31.6,170.8 37.7,164.7 				"/>
 | 
			
		||||
				<polygon class="st1" points="31,163.8 36.3,158.5 41.6,163.8 42.5,163.8 36.3,157.6 30.2,163.8 				"/>
 | 
			
		||||
				<polygon class="st1" points="41.6,164.7 36.3,170 31,164.7 30.2,164.7 36.3,170.8 42.5,164.7 				"/>
 | 
			
		||||
			</g>
 | 
			
		||||
		</g>
 | 
			
		||||
		<g>
 | 
			
		||||
			<path class="st1" d="M33.2,100.7c-4.6,0-8.3,3.7-8.3,8.3s3.7,8.3,8.3,8.3s8.3-3.7,8.3-8.3S37.8,100.7,33.2,100.7z"/>
 | 
			
		||||
		</g>
 | 
			
		||||
		<g>
 | 
			
		||||
			<g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st2" d="M33.2,35.2c40.7,0,73.8,33.1,73.8,73.8c0,0.7,0,1.4,0,2.1c0,1.7,0.6,3.3,1.7,4.6c1.2,1.2,2.8,1.9,4.5,2
 | 
			
		||||
						l0.2,0c3.5,0,6.3-2.7,6.4-6.2c0-0.8,0-1.7,0-2.5c0-47.7-38.8-86.6-86.6-86.6c-0.8,0-1.7,0-2.5,0c-1.7,0-3.3,0.8-4.5,2
 | 
			
		||||
						c-1.2,1.2-1.8,2.9-1.7,4.6c0.1,3.5,3,6.3,6.6,6.2C31.8,35.2,32.5,35.2,33.2,35.2z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
			</g>
 | 
			
		||||
		</g>
 | 
			
		||||
		<g>
 | 
			
		||||
			<g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st3" d="M33.2,60.5c26.7,0,48.5,21.7,48.5,48.5c0,0.6,0,1.3,0,2c-0.1,1.7,0.5,3.3,1.7,4.6c1.2,1.3,2.7,2,4.4,2.1
 | 
			
		||||
						c1.7,0.1,3.3-0.5,4.6-1.7c1.2-1.2,2-2.7,2-4.4c0-0.9,0.1-1.8,0.1-2.6c0-33.8-27.5-61.2-61.2-61.2c-0.8,0-1.6,0-2.6,0.1
 | 
			
		||||
						c-1.7,0.1-3.3,0.8-4.4,2.1c-1.2,1.3-1.8,2.9-1.7,4.6s0.8,3.3,2.1,4.4c1.3,1.2,2.9,1.8,4.6,1.7C31.9,60.5,32.6,60.5,33.2,60.5z"
 | 
			
		||||
						/>
 | 
			
		||||
				</g>
 | 
			
		||||
			</g>
 | 
			
		||||
		</g>
 | 
			
		||||
		<g>
 | 
			
		||||
			<g>
 | 
			
		||||
				<g>
 | 
			
		||||
					<path class="st4" d="M33.2,86.7c12.3,0,22.3,10,22.3,22.3c0,0.5,0,1.1-0.1,1.8c-0.3,3.5,2.3,6.6,5.8,6.9
 | 
			
		||||
						c3.5,0.3,6.6-2.3,6.9-5.8c0.1-1,0.1-1.9,0.1-2.8c0-19.3-15.7-35.1-35.1-35.1c-0.9,0-1.8,0-2.8,0.1c-1.7,0.1-3.2,0.9-4.3,2.2
 | 
			
		||||
						c-1.1,1.3-1.6,2.9-1.5,4.6c0.1,1.7,0.9,3.2,2.2,4.3c1.3,1.1,2.9,1.6,4.6,1.5C32.1,86.7,32.7,86.7,33.2,86.7z"/>
 | 
			
		||||
				</g>
 | 
			
		||||
			</g>
 | 
			
		||||
		</g>
 | 
			
		||||
	</g>
 | 
			
		||||
	<g>
 | 
			
		||||
		<path class="st1" d="M35.8,130.4c1.1,0.6,2.1,1.5,2.7,2.6c0.7,1.1,1,2.3,1,3.7s-0.3,2.6-1,3.7c-0.7,1.1-1.6,2-2.7,2.6
 | 
			
		||||
			c-1.1,0.6-2.4,1-3.8,1s-2.7-0.3-3.8-1c-1.1-0.6-2.1-1.5-2.7-2.6c-0.7-1.1-1-2.3-1-3.7c0-1.3,0.3-2.6,1-3.7c0.7-1.1,1.6-2,2.7-2.6
 | 
			
		||||
			c1.1-0.6,2.4-0.9,3.8-0.9C33.4,129.5,34.7,129.8,35.8,130.4z M29.9,132.9c-0.7,0.4-1.2,0.9-1.6,1.6s-0.6,1.4-0.6,2.2
 | 
			
		||||
			c0,0.8,0.2,1.6,0.6,2.3c0.4,0.7,0.9,1.2,1.6,1.6c0.7,0.4,1.4,0.6,2.1,0.6c0.8,0,1.5-0.2,2.1-0.6c0.6-0.4,1.2-0.9,1.5-1.6
 | 
			
		||||
			c0.4-0.7,0.6-1.4,0.6-2.3c0-0.8-0.2-1.6-0.6-2.2s-0.9-1.2-1.5-1.6c-0.6-0.4-1.4-0.6-2.1-0.6C31.3,132.3,30.6,132.5,29.9,132.9z"/>
 | 
			
		||||
		<path class="st1" d="M50.6,133.6c0.8,0.5,1.4,1.1,1.8,2c0.4,0.8,0.6,1.8,0.6,2.9c0,1.1-0.2,2-0.6,2.8c-0.4,0.8-1,1.5-1.8,1.9
 | 
			
		||||
			c-0.8,0.5-1.6,0.7-2.6,0.7c-0.7,0-1.4-0.1-2-0.4s-1.1-0.7-1.5-1.2v5.4h-3.1V133h3.1v1.6c0.4-0.5,0.9-1,1.4-1.2s1.2-0.4,2-0.4
 | 
			
		||||
			C48.9,132.9,49.8,133.1,50.6,133.6z M49.1,140.5c0.5-0.6,0.7-1.3,0.7-2.2c0-0.9-0.2-1.6-0.7-2.1c-0.5-0.6-1.1-0.8-1.9-0.8
 | 
			
		||||
			s-1.4,0.3-1.9,0.8c-0.5,0.6-0.8,1.3-0.8,2.1c0,0.9,0.2,1.6,0.8,2.2s1.1,0.8,1.9,0.8S48.6,141,49.1,140.5z"/>
 | 
			
		||||
		<path class="st1" d="M63.4,134.4c0.9,1,1.4,2.4,1.4,4.2c0,0.3,0,0.6,0,0.7H57c0.2,0.7,0.5,1.2,1,1.6c0.5,0.4,1.1,0.6,1.8,0.6
 | 
			
		||||
			c0.5,0,1-0.1,1.5-0.3s0.9-0.5,1.3-0.9l1.6,1.6c-0.5,0.6-1.2,1.1-2,1.4c-0.8,0.3-1.6,0.5-2.6,0.5c-1.1,0-2.1-0.2-3-0.7
 | 
			
		||||
			s-1.5-1.1-2-1.9c-0.5-0.8-0.7-1.8-0.7-2.9c0-1.1,0.2-2.1,0.7-2.9s1.1-1.5,2-1.9c0.8-0.5,1.8-0.7,2.9-0.7
 | 
			
		||||
			C61.2,132.9,62.5,133.4,63.4,134.4z M61.8,137.5c0-0.7-0.3-1.3-0.7-1.7s-1-0.6-1.7-0.6c-0.7,0-1.2,0.2-1.7,0.6
 | 
			
		||||
			c-0.4,0.4-0.7,1-0.9,1.7H61.8z"/>
 | 
			
		||||
		<path class="st1" d="M76.2,134c0.7,0.7,1.1,1.7,1.1,3v6.8h-3.1v-5.9c0-0.7-0.2-1.2-0.6-1.6s-0.9-0.6-1.5-0.6
 | 
			
		||||
			c-0.8,0-1.4,0.3-1.8,0.8c-0.4,0.5-0.7,1.2-0.7,2v5.3h-3.1V133h3.1v1.9c0.7-1.3,2-2,3.7-2C74.6,132.8,75.5,133.2,76.2,134z"/>
 | 
			
		||||
		<path class="st1" d="M96,129.7h3.3l-4.7,14h-3.3l-2.9-10.1l-3,10.1h-3.2l-4.7-14h3.4l3,10.7l3-10.7H90l3.1,10.7L96,129.7z"/>
 | 
			
		||||
		<path class="st1" d="M103.3,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
 | 
			
		||||
			c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C102.6,128.2,103,128.3,103.3,128.7z M100.6,133h3.1
 | 
			
		||||
			v10.8h-3.1V133z"/>
 | 
			
		||||
		<path class="st1" d="M106.5,129.7h10.1l0,2.6h-6.9v3.4h6.3v2.6h-6.3v5.3h-3.2V129.7z"/>
 | 
			
		||||
		<path class="st1" d="M120.9,128.7c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2c-0.3,0.3-0.7,0.5-1.2,0.5c-0.5,0-0.9-0.2-1.2-0.5
 | 
			
		||||
			c-0.3-0.3-0.5-0.7-0.5-1.2c0-0.5,0.2-0.9,0.5-1.2c0.3-0.3,0.7-0.5,1.2-0.5C120.1,128.2,120.5,128.3,120.9,128.7z M118.1,133h3.1
 | 
			
		||||
			v10.8h-3.1V133z"/>
 | 
			
		||||
	</g>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
</g>
 | 
			
		||||
<g>
 | 
			
		||||
</g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 8.0 KiB  | 
@@ -17,6 +17,7 @@ servers:
 | 
			
		||||
security:
 | 
			
		||||
  - bearerAuth: []
 | 
			
		||||
  - ApiKeyAuth: []
 | 
			
		||||
  - ApiToken: []
 | 
			
		||||
 | 
			
		||||
components:
 | 
			
		||||
  securitySchemes:
 | 
			
		||||
@@ -28,6 +29,10 @@ components:
 | 
			
		||||
      type: http
 | 
			
		||||
      scheme: bearer
 | 
			
		||||
      bearerFormat: JWT
 | 
			
		||||
    ApiToken:
 | 
			
		||||
      type: apiKey
 | 
			
		||||
      in: header
 | 
			
		||||
      name: X-API-TOKEN
 | 
			
		||||
 | 
			
		||||
  responses:
 | 
			
		||||
    NotFound:
 | 
			
		||||
@@ -66,7 +71,8 @@ components:
 | 
			
		||||
                  - 11    # BAD_MFA_TRANSACTION
 | 
			
		||||
                  - 12    # MFA_FAILURE
 | 
			
		||||
                  - 13    # SECURITY_SERVICE_UNREACHABLE
 | 
			
		||||
                  - 14    # CANNOT REFRESH TOKEN
 | 
			
		||||
                  - 14    # CANNOT_REFRESH_TOKEN
 | 
			
		||||
                  - 15    # ACCOUNT_SUSPENDED
 | 
			
		||||
              ErrorDetails:
 | 
			
		||||
                type: string
 | 
			
		||||
              ErrorDescription:
 | 
			
		||||
@@ -164,18 +170,61 @@ components:
 | 
			
		||||
        aclTemplate:
 | 
			
		||||
          $ref: '#/components/schemas/AclTemplate'
 | 
			
		||||
 | 
			
		||||
    ApiKeyCreationRequest:
 | 
			
		||||
    ApiKeyAccessRight:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        service:
 | 
			
		||||
          type: string
 | 
			
		||||
        access:
 | 
			
		||||
          type: string
 | 
			
		||||
          enum:
 | 
			
		||||
            - read
 | 
			
		||||
            - modify
 | 
			
		||||
            - create
 | 
			
		||||
            - delete
 | 
			
		||||
            - noaccess
 | 
			
		||||
 | 
			
		||||
    ApiKeyAccessRightList:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        acls:
 | 
			
		||||
          type: array
 | 
			
		||||
          items:
 | 
			
		||||
            $ref: '#/components/schemas/ApiKeyAccessRight'
 | 
			
		||||
 | 
			
		||||
    ApiKeyEntry:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        id:
 | 
			
		||||
          type: string
 | 
			
		||||
          format: uuid
 | 
			
		||||
        userUuid:
 | 
			
		||||
          type: string
 | 
			
		||||
          format: uuid
 | 
			
		||||
        name:
 | 
			
		||||
          type: string
 | 
			
		||||
        description:
 | 
			
		||||
          type: string
 | 
			
		||||
        apiKey:
 | 
			
		||||
          type: string
 | 
			
		||||
        salt:
 | 
			
		||||
          type: string
 | 
			
		||||
        expiresOn:
 | 
			
		||||
          type: integer
 | 
			
		||||
          format: int64
 | 
			
		||||
        lastUse:
 | 
			
		||||
          type: integer
 | 
			
		||||
          format: int64
 | 
			
		||||
        rights:
 | 
			
		||||
          $ref: '#/components/schemas/AclTemplate'
 | 
			
		||||
          $ref: '#/components/schemas/ApiKeyAccessRightList'
 | 
			
		||||
 | 
			
		||||
    ApiKeyEntryList:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        apiKeys:
 | 
			
		||||
          type: array
 | 
			
		||||
          items:
 | 
			
		||||
            $ref: '#/components/schemas/ApiKeyEntry'
 | 
			
		||||
 | 
			
		||||
    ApiKeyCreationAnswer:
 | 
			
		||||
      type: object
 | 
			
		||||
@@ -194,7 +243,7 @@ components:
 | 
			
		||||
        apiKey:
 | 
			
		||||
          type: string
 | 
			
		||||
        rights:
 | 
			
		||||
          $ref: '#/components/schemas/AclTemplate'
 | 
			
		||||
          $ref: '#/components/schemas/ApiKeyAccessRightList'
 | 
			
		||||
 | 
			
		||||
    AclTemplate:
 | 
			
		||||
      type: object
 | 
			
		||||
@@ -444,6 +493,16 @@ components:
 | 
			
		||||
        sms:
 | 
			
		||||
          type: string
 | 
			
		||||
 | 
			
		||||
    ExtraSystemConfiguration:
 | 
			
		||||
      type: array
 | 
			
		||||
      items:
 | 
			
		||||
        type: object
 | 
			
		||||
        properties:
 | 
			
		||||
          parameterName:
 | 
			
		||||
            type: string
 | 
			
		||||
          parameterValue:
 | 
			
		||||
            type: string
 | 
			
		||||
 | 
			
		||||
    #########################################################################################
 | 
			
		||||
    ##
 | 
			
		||||
    ## These are endpoints that all services in the uCentral stack must provide
 | 
			
		||||
@@ -704,6 +763,23 @@ components:
 | 
			
		||||
              value:
 | 
			
		||||
                type: string
 | 
			
		||||
 | 
			
		||||
    SystemSecretEntry:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        name:
 | 
			
		||||
          type: string
 | 
			
		||||
        value:
 | 
			
		||||
          type: string
 | 
			
		||||
 | 
			
		||||
    SystemSecretEntryList:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        secrets:
 | 
			
		||||
          type: array
 | 
			
		||||
          items:
 | 
			
		||||
            $ref: '#/components/schemas/SystemSecretEntry'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    #########################################################################################
 | 
			
		||||
    ##
 | 
			
		||||
    ## End of uCentral system wide values
 | 
			
		||||
@@ -894,7 +970,7 @@ paths:
 | 
			
		||||
  /systemEndpoints:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Authentication
 | 
			
		||||
        - System Commands
 | 
			
		||||
      summary: Retrieve the system layout.
 | 
			
		||||
      operationId: getSystemInfo
 | 
			
		||||
      responses:
 | 
			
		||||
@@ -1348,7 +1424,7 @@ paths:
 | 
			
		||||
  /email:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Email
 | 
			
		||||
        - Messaging
 | 
			
		||||
      summary: Send test email with the system.
 | 
			
		||||
      operationId: Send a test email
 | 
			
		||||
      requestBody:
 | 
			
		||||
@@ -1379,7 +1455,7 @@ paths:
 | 
			
		||||
  /sms:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Email
 | 
			
		||||
        - Messaging
 | 
			
		||||
      summary: Send test email with the system.
 | 
			
		||||
      operationId: Send a test SMS
 | 
			
		||||
      parameters:
 | 
			
		||||
@@ -1634,7 +1710,103 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /apiKey/{uuid}:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - API Tokens
 | 
			
		||||
      summary: Retrieve all the APIKeys for a given user UUID
 | 
			
		||||
      operationId: getApiKeyList
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: uuid
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
            format: uuid
 | 
			
		||||
          required: true
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/ApiKeyEntryList'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
    delete:
 | 
			
		||||
      tags:
 | 
			
		||||
        - API Tokens
 | 
			
		||||
      summary: Retrieve all the APIKeys for a given user UUID
 | 
			
		||||
      operationId: deleteApiKey
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: uuid
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
            format: uuid
 | 
			
		||||
          required: true
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: keyUuid
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
          required: true
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/responses/Success'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - API Tokens
 | 
			
		||||
      summary: Retrieve all the APIKeys for a given user UUID
 | 
			
		||||
      operationId: createApiKey
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: uuid
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
            format: uuid
 | 
			
		||||
          required: true
 | 
			
		||||
      requestBody:
 | 
			
		||||
        content:
 | 
			
		||||
          application/json:
 | 
			
		||||
            schema:
 | 
			
		||||
              $ref: '#/components/schemas/ApiKeyEntry'
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/ApiKeyEntry'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
    put:
 | 
			
		||||
      tags:
 | 
			
		||||
        - API Tokens
 | 
			
		||||
      summary: Retrieve all the APIKeys for a given user UUID
 | 
			
		||||
      operationId: modifyApiKey
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: uuid
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
            format: uuid
 | 
			
		||||
          required: true
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: name
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
          required: true
 | 
			
		||||
      requestBody:
 | 
			
		||||
        content:
 | 
			
		||||
          application/json:
 | 
			
		||||
            schema:
 | 
			
		||||
              $ref: '#/components/schemas/ApiKeyEntry'
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/ApiKeyEntry'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  #########################################################################################
 | 
			
		||||
  ##
 | 
			
		||||
@@ -1732,6 +1904,26 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /validateApiKey:
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Security
 | 
			
		||||
      summary: Allows an application to validate an API Key.
 | 
			
		||||
      operationId: validateApiKey
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: query
 | 
			
		||||
          name: token
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
          required: true
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/schemas/TokenValidationResult'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /system:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
@@ -1791,6 +1983,152 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /systemSecret/{secret}:
 | 
			
		||||
    get:
 | 
			
		||||
      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:
 | 
			
		||||
      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"
 | 
			
		||||
}
 | 
			
		||||
@@ -11,80 +11,122 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class ACLProcessor {
 | 
			
		||||
	  public:
 | 
			
		||||
        enum ACL_OPS {
 | 
			
		||||
            READ,
 | 
			
		||||
            MODIFY,
 | 
			
		||||
            DELETE,
 | 
			
		||||
            CREATE
 | 
			
		||||
        };
 | 
			
		||||
		enum ACL_OPS { READ, MODIFY, DELETE, CREATE };
 | 
			
		||||
		/*
 | 
			
		||||
		 *  0) You can only delete yourself if you are a subscriber
 | 
			
		||||
			1) You cannot delete yourself
 | 
			
		||||
			2) If you are root, you can do anything.
 | 
			
		||||
			3) You can do anything to yourself
 | 
			
		||||
    4) Nobody can touch a root, unless they are a root, unless it is to get information on a ROOT
 | 
			
		||||
    5) Creation rules:
 | 
			
		||||
        ROOT -> create anything
 | 
			
		||||
        PARTNER -> (multi-tenant owner) admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning
 | 
			
		||||
        ADMIN -> admin-subs-csr-installer-noc-accounting
 | 
			
		||||
        ACCOUNTING -> subs-installer-csr
 | 
			
		||||
			4) Nobody can touch a root, unless they are a root, unless it is to get information on a
 | 
			
		||||
		 ROOT 5) Creation rules: ROOT -> create anything PARTNER -> (multi-tenant owner)
 | 
			
		||||
		 admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning ADMIN ->
 | 
			
		||||
		 admin-subs-csr-installer-noc-accounting ACCOUNTING -> subs-installer-csr
 | 
			
		||||
 | 
			
		||||
		 */
 | 
			
		||||
        static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) {
 | 
			
		||||
		static inline bool Can(const SecurityObjects::UserInfo &User,
 | 
			
		||||
							   const SecurityObjects::UserInfo &Target, ACL_OPS Op) {
 | 
			
		||||
 | 
			
		||||
            // rule 0
 | 
			
		||||
            if(User.id == Target.id && User.userRole == SecurityObjects::SUBSCRIBER && Op == DELETE)
 | 
			
		||||
			switch (Op) {
 | 
			
		||||
			case DELETE: {
 | 
			
		||||
				//  can a user delete themselves - yes - only if not root. We do not want a system
 | 
			
		||||
				//  to end up rootless
 | 
			
		||||
				if (User.id == Target.id) {
 | 
			
		||||
					return User.userRole != SecurityObjects::ROOT;
 | 
			
		||||
				}
 | 
			
		||||
				//  Root can delete anyone
 | 
			
		||||
				switch (User.userRole) {
 | 
			
		||||
				case SecurityObjects::ROOT:
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
            //  rule 1
 | 
			
		||||
            if(User.id == Target.id && Op==DELETE)
 | 
			
		||||
				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;
 | 
			
		||||
 | 
			
		||||
            //  rule 2
 | 
			
		||||
            if(User.userRole==SecurityObjects::ROOT)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            //  rule 3
 | 
			
		||||
            if(User.id == Target.id)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            //  rule 4
 | 
			
		||||
            if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            if(Op==CREATE) {
 | 
			
		||||
                if(User.userRole==SecurityObjects::ROOT)
 | 
			
		||||
                    return true;
 | 
			
		||||
                if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::CSR ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::NOC ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::ACCOUNTING))
 | 
			
		||||
                    return true;
 | 
			
		||||
                if(User.userRole==SecurityObjects::ADMIN &&
 | 
			
		||||
                    (Target.userRole==SecurityObjects::ADMIN ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::CSR ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::NOC ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::ACCOUNTING))
 | 
			
		||||
                    return true;
 | 
			
		||||
                if(User.userRole==SecurityObjects::ACCOUNTING &&
 | 
			
		||||
                    (Target.userRole==SecurityObjects::SUBSCRIBER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::INSTALLER ||
 | 
			
		||||
                    Target.userRole==SecurityObjects::CSR))
 | 
			
		||||
                    return true;
 | 
			
		||||
				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;
 | 
			
		||||
 | 
			
		||||
			case READ: {
 | 
			
		||||
				return User.userRole == SecurityObjects::ROOT ||
 | 
			
		||||
					   User.userRole == SecurityObjects::ADMIN ||
 | 
			
		||||
					   User.userRole == SecurityObjects::PARTNER;
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case CREATE: {
 | 
			
		||||
				switch (User.userRole) {
 | 
			
		||||
				case SecurityObjects::ROOT:
 | 
			
		||||
					return true;
 | 
			
		||||
				case SecurityObjects::ADMIN:
 | 
			
		||||
					return Target.userRole != SecurityObjects::ROOT &&
 | 
			
		||||
						   Target.userRole != SecurityObjects::PARTNER;
 | 
			
		||||
				case SecurityObjects::SUBSCRIBER:
 | 
			
		||||
					return false;
 | 
			
		||||
				case SecurityObjects::CSR:
 | 
			
		||||
					return Target.userRole == SecurityObjects::CSR;
 | 
			
		||||
				case SecurityObjects::SYSTEM:
 | 
			
		||||
					return Target.userRole != SecurityObjects::ROOT &&
 | 
			
		||||
						   Target.userRole != SecurityObjects::PARTNER;
 | 
			
		||||
				case SecurityObjects::INSTALLER:
 | 
			
		||||
					return Target.userRole == SecurityObjects::INSTALLER;
 | 
			
		||||
				case SecurityObjects::NOC:
 | 
			
		||||
					return Target.userRole == SecurityObjects::NOC;
 | 
			
		||||
				case SecurityObjects::ACCOUNTING:
 | 
			
		||||
					return Target.userRole == SecurityObjects::ACCOUNTING;
 | 
			
		||||
				case SecurityObjects::PARTNER:
 | 
			
		||||
					return Target.userRole != SecurityObjects::ROOT;
 | 
			
		||||
				default:
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case MODIFY: {
 | 
			
		||||
				switch (User.userRole) {
 | 
			
		||||
				case SecurityObjects::ROOT:
 | 
			
		||||
					return true;
 | 
			
		||||
				case SecurityObjects::ADMIN:
 | 
			
		||||
					return Target.userRole != SecurityObjects::ROOT &&
 | 
			
		||||
						   Target.userRole != SecurityObjects::PARTNER;
 | 
			
		||||
				case SecurityObjects::SUBSCRIBER:
 | 
			
		||||
					return User.id == Target.id;
 | 
			
		||||
				case SecurityObjects::CSR:
 | 
			
		||||
					return Target.userRole == SecurityObjects::CSR;
 | 
			
		||||
				case SecurityObjects::SYSTEM:
 | 
			
		||||
					return Target.userRole != SecurityObjects::ROOT &&
 | 
			
		||||
						   Target.userRole != SecurityObjects::PARTNER;
 | 
			
		||||
				case SecurityObjects::INSTALLER:
 | 
			
		||||
					return Target.userRole == SecurityObjects::INSTALLER;
 | 
			
		||||
				case SecurityObjects::NOC:
 | 
			
		||||
					return Target.userRole == SecurityObjects::NOC;
 | 
			
		||||
				case SecurityObjects::ACCOUNTING:
 | 
			
		||||
					return Target.userRole == SecurityObjects::ACCOUNTING;
 | 
			
		||||
				case SecurityObjects::PARTNER:
 | 
			
		||||
					return Target.userRole != SecurityObjects::ROOT;
 | 
			
		||||
				default:
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			} break;
 | 
			
		||||
			default:
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 | 
			
		||||
#endif // OWSEC_ACLPROCESSOR_H
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,11 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "ActionLinkManager.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
#include "MessagingTemplates.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "fmt/format.h"
 | 
			
		||||
#include "framework/utils.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -49,12 +51,15 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
				SecurityObjects::UserInfo UInfo;
 | 
			
		||||
				if ((i.action == OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
 | 
			
		||||
                    i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) {
 | 
			
		||||
					 i.action == OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) &&
 | 
			
		||||
					!StorageService()->UserDB().GetUserById(i.userId, UInfo)) {
 | 
			
		||||
					StorageService()->ActionLinksDB().CancelAction(i.id);
 | 
			
		||||
					continue;
 | 
			
		||||
                } else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
 | 
			
		||||
				} 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)) {
 | 
			
		||||
							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) &&
 | 
			
		||||
@@ -65,55 +70,69 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
				switch (i.action) {
 | 
			
		||||
				case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
 | 
			
		||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::FORGOT_PASSWORD)) {
 | 
			
		||||
                                poco_information(Logger(),fmt::format("Send password reset link to {}",UInfo.email));
 | 
			
		||||
					if (AuthService()->SendEmailToUser(i.id, UInfo.email,
 | 
			
		||||
													   MessagingTemplates::FORGOT_PASSWORD)) {
 | 
			
		||||
						poco_information(
 | 
			
		||||
							Logger(), fmt::format("Send password reset link to {}", UInfo.email));
 | 
			
		||||
					}
 | 
			
		||||
					StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
				} break;
 | 
			
		||||
 | 
			
		||||
				case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
 | 
			
		||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_VERIFICATION)) {
 | 
			
		||||
                                poco_information(Logger(),fmt::format("Send email verification link to {}",UInfo.email));
 | 
			
		||||
					if (AuthService()->SendEmailToUser(i.id, UInfo.email,
 | 
			
		||||
													   MessagingTemplates::EMAIL_VERIFICATION)) {
 | 
			
		||||
						poco_information(Logger(), fmt::format("Send email verification link to {}",
 | 
			
		||||
															   UInfo.email));
 | 
			
		||||
					}
 | 
			
		||||
					StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
				} break;
 | 
			
		||||
 | 
			
		||||
				case OpenWifi::SecurityObjects::LinkActions::EMAIL_INVITATION: {
 | 
			
		||||
                            if(AuthService::SendEmailToUser(i.id, UInfo.email, MessagingTemplates::EMAIL_INVITATION)) {
 | 
			
		||||
                                poco_information(Logger(),fmt::format("Send new subscriber email invitation link to {}",UInfo.email));
 | 
			
		||||
					if (AuthService()->SendEmailToUser(i.id, UInfo.email,
 | 
			
		||||
													   MessagingTemplates::EMAIL_INVITATION)) {
 | 
			
		||||
						poco_information(
 | 
			
		||||
							Logger(), fmt::format("Send new subscriber email invitation link to {}",
 | 
			
		||||
												  UInfo.email));
 | 
			
		||||
					}
 | 
			
		||||
					StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
				} break;
 | 
			
		||||
 | 
			
		||||
				case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
 | 
			
		||||
					auto Signup = Poco::StringTokenizer(UInfo.signingUp, ":");
 | 
			
		||||
                            if(AuthService::SendEmailToSubUser(i.id, UInfo.email,MessagingTemplates::SUB_FORGOT_PASSWORD, Signup.count()==1 ? "" : Signup[0])) {
 | 
			
		||||
                                poco_information(Logger(),fmt::format("Send subscriber password reset link to {}",UInfo.email));
 | 
			
		||||
					if (AuthService()->SendEmailToSubUser(i.id, UInfo.email,
 | 
			
		||||
														  MessagingTemplates::SUB_FORGOT_PASSWORD,
 | 
			
		||||
														  Signup.count() == 1 ? "" : Signup[0])) {
 | 
			
		||||
						poco_information(
 | 
			
		||||
							Logger(),
 | 
			
		||||
							fmt::format("Send subscriber password reset link to {}", UInfo.email));
 | 
			
		||||
					}
 | 
			
		||||
					StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
				} break;
 | 
			
		||||
 | 
			
		||||
				case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
 | 
			
		||||
					auto Signup = Poco::StringTokenizer(UInfo.signingUp, ":");
 | 
			
		||||
                            if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
 | 
			
		||||
                                poco_information(Logger(),fmt::format("Send subscriber email verification link to {}",UInfo.email));
 | 
			
		||||
					if (AuthService()->SendEmailToSubUser(
 | 
			
		||||
							i.id, UInfo.email, MessagingTemplates::SUB_EMAIL_VERIFICATION,
 | 
			
		||||
							Signup.count() == 1 ? "" : Signup[0])) {
 | 
			
		||||
						poco_information(
 | 
			
		||||
							Logger(), fmt::format("Send subscriber email verification link to {}",
 | 
			
		||||
												  UInfo.email));
 | 
			
		||||
					}
 | 
			
		||||
					StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
				} break;
 | 
			
		||||
 | 
			
		||||
				case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
 | 
			
		||||
					auto Signup = Poco::StringTokenizer(UInfo.signingUp, ":");
 | 
			
		||||
                        if(AuthService::SendEmailToSubUser(i.id, UInfo.email, MessagingTemplates::SIGNUP_VERIFICATION, Signup.count()==1 ? "" : Signup[0])) {
 | 
			
		||||
                            poco_information(Logger(),fmt::format("Send new subscriber email verification link to {}",UInfo.email));
 | 
			
		||||
					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;
 | 
			
		||||
				} break;
 | 
			
		||||
 | 
			
		||||
				default: {
 | 
			
		||||
					StorageService()->ActionLinksDB().SentAction(i.id);
 | 
			
		||||
@@ -123,4 +142,4 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -2,16 +2,14 @@
 | 
			
		||||
// Created by stephane bourque on 2021-11-08.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifndef OWSEC_ACTIONLINKMANAGER_H
 | 
			
		||||
#define OWSEC_ACTIONLINKMANAGER_H
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/SubSystemServer.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class ActionLinkManager : public SubSystemServer, Poco::Runnable {
 | 
			
		||||
	  public:
 | 
			
		||||
 | 
			
		||||
		static ActionLinkManager *instance() {
 | 
			
		||||
			static auto instance_ = new ActionLinkManager;
 | 
			
		||||
			return instance_;
 | 
			
		||||
@@ -25,12 +23,8 @@ namespace OpenWifi {
 | 
			
		||||
		Poco::Thread Thr_;
 | 
			
		||||
		std::atomic_bool Running_ = false;
 | 
			
		||||
 | 
			
		||||
        ActionLinkManager() noexcept:
 | 
			
		||||
            SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server")
 | 
			
		||||
                {
 | 
			
		||||
                }
 | 
			
		||||
		ActionLinkManager() noexcept
 | 
			
		||||
			: SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server") {}
 | 
			
		||||
	};
 | 
			
		||||
	inline ActionLinkManager *ActionLinkManager() { return ActionLinkManager::instance(); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //OWSEC_ACTIONLINKMANAGER_H
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -8,29 +8,32 @@
 | 
			
		||||
 | 
			
		||||
#include <ctime>
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/KafkaManager.h"
 | 
			
		||||
#include "framework/KafkaTopics.h"
 | 
			
		||||
 | 
			
		||||
#include "Poco/Net/OAuth20Credentials.h"
 | 
			
		||||
#include "Poco/JWT/Token.h"
 | 
			
		||||
#include "Poco/JWT/Signer.h"
 | 
			
		||||
#include "Poco/JWT/Token.h"
 | 
			
		||||
#include "Poco/Net/OAuth20Credentials.h"
 | 
			
		||||
#include "Poco/StringTokenizer.h"
 | 
			
		||||
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "MessagingTemplates.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
 | 
			
		||||
		switch (C) {
 | 
			
		||||
		case 1: return USERNAME;
 | 
			
		||||
		case 2: return SERVER;
 | 
			
		||||
		case 3: return CUSTOM;
 | 
			
		||||
		case 1:
 | 
			
		||||
			return USERNAME;
 | 
			
		||||
		case 2:
 | 
			
		||||
			return SERVER;
 | 
			
		||||
		case 3:
 | 
			
		||||
			return CUSTOM;
 | 
			
		||||
		default:
 | 
			
		||||
			return USERNAME;
 | 
			
		||||
		}
 | 
			
		||||
@@ -38,28 +41,70 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	int AuthService::AccessTypeToInt(ACCESS_TYPE T) {
 | 
			
		||||
		switch (T) {
 | 
			
		||||
		case USERNAME: return 1;
 | 
			
		||||
		case SERVER: return 2;
 | 
			
		||||
		case CUSTOM: return 3;
 | 
			
		||||
		case USERNAME:
 | 
			
		||||
			return 1;
 | 
			
		||||
		case SERVER:
 | 
			
		||||
			return 2;
 | 
			
		||||
		case CUSTOM:
 | 
			
		||||
			return 3;
 | 
			
		||||
		}
 | 
			
		||||
		return 1; // some compilers complain...
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    static const std::string DefaultPassword_8_u_l_n_1{"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\.\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{8,}$"};
 | 
			
		||||
#if defined(TIP_CERT_SERVICE)
 | 
			
		||||
	static const std::string DefaultPasswordRule{
 | 
			
		||||
		"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\."
 | 
			
		||||
		"\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{12,}$"};
 | 
			
		||||
#else
 | 
			
		||||
	static const std::string DefaultPasswordRule{
 | 
			
		||||
		"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[\\{\\}\\(\\)~_\\+\\|\\\\\\[\\]\\;\\:\\<\\>\\."
 | 
			
		||||
		"\\,\\/\\?\\\"\\'\\`\\=#?!@$%^&*-]).{8,}$"};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	int AuthService::Start() {
 | 
			
		||||
		poco_information(Logger(), "Starting...");
 | 
			
		||||
        TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
 | 
			
		||||
        RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600);
 | 
			
		||||
        HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
 | 
			
		||||
		TokenAging_ =
 | 
			
		||||
			(uint64_t)MicroServiceConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
 | 
			
		||||
		RefreshTokenLifeSpan_ = (uint64_t)MicroServiceConfigGetInt(
 | 
			
		||||
			"authentication.refresh_token.lifespan", 90 * 24 * 60 * 600);
 | 
			
		||||
		HowManyOldPassword_ = MicroServiceConfigGetInt("authentication.oldpasswords", 5);
 | 
			
		||||
 | 
			
		||||
        AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html");
 | 
			
		||||
        PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html");
 | 
			
		||||
        PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression",DefaultPassword_8_u_l_n_1);
 | 
			
		||||
		AccessPolicy_ = MicroServiceConfigGetString("openwifi.document.policy.access",
 | 
			
		||||
													"/wwwassets/access_policy.html");
 | 
			
		||||
		PasswordPolicy_ = MicroServiceConfigGetString("openwifi.document.policy.password",
 | 
			
		||||
													  "/wwwassets/password_policy.html");
 | 
			
		||||
		PasswordValidation_ = PasswordValidationStr_ = MicroServiceConfigGetString(
 | 
			
		||||
			"authentication.validation.expression", DefaultPasswordRule);
 | 
			
		||||
 | 
			
		||||
        SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression",DefaultPassword_8_u_l_n_1);
 | 
			
		||||
        SubAccessPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.access", "/wwwassets/access_policy.html");
 | 
			
		||||
        SubPasswordPolicy_ = MicroService::instance().ConfigGetString("subscriber.policy.password", "/wwwassets/password_policy.html");
 | 
			
		||||
		SubPasswordValidation_ = SubPasswordValidationStr_ =
 | 
			
		||||
			MicroServiceConfigGetString("subscriber.validation.expression", DefaultPasswordRule);
 | 
			
		||||
		SubAccessPolicy_ = MicroServiceConfigGetString("subscriber.policy.access",
 | 
			
		||||
													   "/wwwassets/access_policy.html");
 | 
			
		||||
		SubPasswordPolicy_ = MicroServiceConfigGetString("subscriber.policy.password",
 | 
			
		||||
														 "/wwwassets/password_policy.html");
 | 
			
		||||
 | 
			
		||||
		HelperEmail_ =
 | 
			
		||||
			MicroServiceConfigGetString("helper.user.email", "openwifi@telecominfraproject.com");
 | 
			
		||||
		SubHelperEmail_ =
 | 
			
		||||
			MicroServiceConfigGetString("helper.sub.email", "openwifi@telecominfraproject.com");
 | 
			
		||||
 | 
			
		||||
		GlobalHelperEmail_ = MicroServiceConfigGetString("helper.user.global.email",
 | 
			
		||||
														 "openwifi@telecominfraproject.com");
 | 
			
		||||
		GlobalSubHelperEmail_ = MicroServiceConfigGetString("helper.sub.global.email",
 | 
			
		||||
															"openwifi@telecominfraproject.com");
 | 
			
		||||
 | 
			
		||||
		HelperSite_ = MicroServiceConfigGetString("helper.user.site", "telecominfraproject.com");
 | 
			
		||||
		SubHelperSite_ = MicroServiceConfigGetString("helper.sub.site", "telecominfraproject.com");
 | 
			
		||||
 | 
			
		||||
		SystemLoginSite_ =
 | 
			
		||||
			MicroServiceConfigGetString("helper.user.login", "telecominfraproject.com");
 | 
			
		||||
		SubSystemLoginSite_ =
 | 
			
		||||
			MicroServiceConfigGetString("helper.sub.login", "telecominfraproject.com");
 | 
			
		||||
 | 
			
		||||
		UserSignature_ =
 | 
			
		||||
			MicroServiceConfigGetString("helper.user.signature", "Telecom Infra Project");
 | 
			
		||||
		SubSignature_ =
 | 
			
		||||
			MicroServiceConfigGetString("helper.sub.signature", "Telecom Infra Project");
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -69,7 +114,9 @@ namespace OpenWifi {
 | 
			
		||||
		poco_information(Logger(), "Stopped...");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
 | 
			
		||||
	bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest &Request,
 | 
			
		||||
									   const std::string &RefreshToken,
 | 
			
		||||
									   SecurityObjects::UserInfoAndPolicy &UI) {
 | 
			
		||||
		try {
 | 
			
		||||
			std::string CallToken;
 | 
			
		||||
			Poco::Net::OAuth20Credentials Auth(Request);
 | 
			
		||||
@@ -83,8 +130,10 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
			uint64_t RevocationDate = 0;
 | 
			
		||||
			std::string UserId;
 | 
			
		||||
            if(StorageService()->UserTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) {
 | 
			
		||||
                auto now = OpenWifi::Now();
 | 
			
		||||
			if (StorageService()->UserTokenDB().GetToken(CallToken, UI.webtoken, UserId,
 | 
			
		||||
														 RevocationDate) &&
 | 
			
		||||
				UI.webtoken.refresh_token_ == RefreshToken) {
 | 
			
		||||
				auto now = Utils::Now();
 | 
			
		||||
 | 
			
		||||
				//  Create a new token
 | 
			
		||||
				auto NewToken = GenerateTokenHMAC(UI.webtoken.access_token_, CUSTOM);
 | 
			
		||||
@@ -94,7 +143,8 @@ namespace OpenWifi {
 | 
			
		||||
					UI.webtoken.lastRefresh_ = now;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
                StorageService()->UserTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ );
 | 
			
		||||
				StorageService()->UserTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken,
 | 
			
		||||
															 UI.webtoken.lastRefresh_);
 | 
			
		||||
				UI.webtoken.access_token_ = NewToken;
 | 
			
		||||
				UI.webtoken.refresh_token_ = NewRefreshToken;
 | 
			
		||||
				return true;
 | 
			
		||||
@@ -102,12 +152,13 @@ namespace OpenWifi {
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		} catch (...) {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
 | 
			
		||||
	bool AuthService::RefreshSubToken(Poco::Net::HTTPServerRequest &Request,
 | 
			
		||||
									  const std::string &RefreshToken,
 | 
			
		||||
									  SecurityObjects::UserInfoAndPolicy &UI) {
 | 
			
		||||
		try {
 | 
			
		||||
			std::string CallToken;
 | 
			
		||||
			Poco::Net::OAuth20Credentials Auth(Request);
 | 
			
		||||
@@ -121,8 +172,10 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
			uint64_t RevocationDate = 0;
 | 
			
		||||
			std::string UserId;
 | 
			
		||||
            if(StorageService()->SubTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) {
 | 
			
		||||
                auto now = OpenWifi::Now();
 | 
			
		||||
			if (StorageService()->SubTokenDB().GetToken(CallToken, UI.webtoken, UserId,
 | 
			
		||||
														RevocationDate) &&
 | 
			
		||||
				UI.webtoken.refresh_token_ == RefreshToken) {
 | 
			
		||||
				auto now = Utils::Now();
 | 
			
		||||
 | 
			
		||||
				//  Create a new token
 | 
			
		||||
				auto NewToken = GenerateTokenHMAC(UI.webtoken.access_token_, CUSTOM);
 | 
			
		||||
@@ -132,7 +185,8 @@ namespace OpenWifi {
 | 
			
		||||
					UI.webtoken.lastRefresh_ = now;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
                StorageService()->SubTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ );
 | 
			
		||||
				StorageService()->SubTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken,
 | 
			
		||||
															UI.webtoken.lastRefresh_);
 | 
			
		||||
				UI.webtoken.access_token_ = NewToken;
 | 
			
		||||
				UI.webtoken.refresh_token_ = NewRefreshToken;
 | 
			
		||||
				return true;
 | 
			
		||||
@@ -140,54 +194,75 @@ namespace OpenWifi {
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		} catch (...) {
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired )
 | 
			
		||||
    {
 | 
			
		||||
	[[nodiscard]] bool AuthService::IsAuthorized(const std::string &SessionToken,
 | 
			
		||||
												 SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
												 std::uint64_t TID, bool &Expired) {
 | 
			
		||||
		// std::lock_guard	Guard(Mutex_);
 | 
			
		||||
        std::string CallToken;
 | 
			
		||||
		std::string CallToken{SessionToken};
 | 
			
		||||
		Expired = false;
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
		    Poco::Net::OAuth20Credentials Auth(Request);
 | 
			
		||||
		    if (Auth.getScheme() == "Bearer") {
 | 
			
		||||
		        CallToken = Auth.getBearerToken();
 | 
			
		||||
		    }
 | 
			
		||||
 | 
			
		||||
            if(CallToken.empty()) {
 | 
			
		||||
                poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
			SecurityObjects::WebToken WT;
 | 
			
		||||
			uint64_t RevocationDate = 0;
 | 
			
		||||
			std::string UserId;
 | 
			
		||||
			if (StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
				if (RevocationDate != 0) {
 | 
			
		||||
                    poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
 | 
			
		||||
					poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}",
 | 
			
		||||
													 TID, Utils::SanitizeToken(CallToken)));
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
                auto now=OpenWifi::Now();
 | 
			
		||||
				auto now = Utils::Now();
 | 
			
		||||
				Expired = (WT.created_ + WT.expires_in_) < now;
 | 
			
		||||
				if (StorageService()->UserDB().GetUserById(UserId, UInfo.userinfo)) {
 | 
			
		||||
					UInfo.webtoken = WT;
 | 
			
		||||
                    SessionToken = CallToken;
 | 
			
		||||
                    poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken));
 | 
			
		||||
					poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}",
 | 
			
		||||
													 TID, Utils::SanitizeToken(CallToken)));
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
			Logger().log(E);
 | 
			
		||||
		}
 | 
			
		||||
        poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
 | 
			
		||||
		poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID,
 | 
			
		||||
										 Utils::SanitizeToken(CallToken)));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired )
 | 
			
		||||
    {
 | 
			
		||||
	bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest &Request, std::string &SessionToken,
 | 
			
		||||
								   SecurityObjects::UserInfoAndPolicy &UInfo, std::uint64_t TID,
 | 
			
		||||
								   bool &Expired) {
 | 
			
		||||
		// std::lock_guard	Guard(Mutex_);
 | 
			
		||||
		std::string CallToken;
 | 
			
		||||
		Expired = false;
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			Poco::Net::OAuth20Credentials Auth(Request);
 | 
			
		||||
			if (Auth.getScheme() == "Bearer") {
 | 
			
		||||
				CallToken = Auth.getBearerToken();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (CallToken.empty()) {
 | 
			
		||||
				poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID,
 | 
			
		||||
												 Utils::SanitizeToken(CallToken)));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			SessionToken = CallToken;
 | 
			
		||||
			return IsAuthorized(SessionToken, UInfo, TID, Expired);
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
			Logger().log(E);
 | 
			
		||||
		}
 | 
			
		||||
		poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID,
 | 
			
		||||
										 Utils::SanitizeToken(CallToken)));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest &Request,
 | 
			
		||||
									  std::string &SessionToken,
 | 
			
		||||
									  SecurityObjects::UserInfoAndPolicy &UInfo, std::uint64_t TID,
 | 
			
		||||
									  bool &Expired) {
 | 
			
		||||
		// std::lock_guard	Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		std::string CallToken;
 | 
			
		||||
@@ -199,7 +274,8 @@ namespace OpenWifi {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (CallToken.empty()) {
 | 
			
		||||
                poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
 | 
			
		||||
				poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID,
 | 
			
		||||
												 Utils::SanitizeToken(CallToken)));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -208,22 +284,25 @@ namespace OpenWifi {
 | 
			
		||||
			std::string UserId;
 | 
			
		||||
			if (StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
				if (RevocationDate != 0) {
 | 
			
		||||
                    poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
 | 
			
		||||
					poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}",
 | 
			
		||||
													 TID, Utils::SanitizeToken(CallToken)));
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
                auto now=OpenWifi::Now();
 | 
			
		||||
				auto now = Utils::Now();
 | 
			
		||||
				Expired = (WT.created_ + WT.expires_in_) < now;
 | 
			
		||||
				if (StorageService()->SubDB().GetUserById(UserId, UInfo.userinfo)) {
 | 
			
		||||
					UInfo.webtoken = WT;
 | 
			
		||||
					SessionToken = CallToken;
 | 
			
		||||
                    poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}", TID, CallToken));
 | 
			
		||||
					poco_debug(Logger(), fmt::format("TokenValidation success for TID={} Token={}",
 | 
			
		||||
													 TID, Utils::SanitizeToken(CallToken)));
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
			Logger().log(E);
 | 
			
		||||
		}
 | 
			
		||||
        poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID, CallToken));
 | 
			
		||||
		poco_debug(Logger(), fmt::format("TokenValidation failed for TID={} Token={}", TID,
 | 
			
		||||
										 Utils::SanitizeToken(CallToken)));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -244,7 +323,8 @@ namespace OpenWifi {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
			
		||||
        return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer::MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method));
 | 
			
		||||
		return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled &&
 | 
			
		||||
				MFAServer::MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool AuthService::ValidatePassword(const std::string &Password) {
 | 
			
		||||
@@ -260,13 +340,12 @@ namespace OpenWifi {
 | 
			
		||||
			if (KafkaManager()->Enabled()) {
 | 
			
		||||
				Poco::JSON::Object Obj;
 | 
			
		||||
				Obj.set("event", "remove-token");
 | 
			
		||||
                Obj.set("id", MicroService::instance().ID());
 | 
			
		||||
				Obj.set("id", MicroServiceID());
 | 
			
		||||
				Obj.set("token", token);
 | 
			
		||||
				std::stringstream ResultText;
 | 
			
		||||
				Poco::JSON::Stringifier::stringify(Obj, ResultText);
 | 
			
		||||
                KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(),
 | 
			
		||||
                                            ResultText.str(),
 | 
			
		||||
                                            false);
 | 
			
		||||
				KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,
 | 
			
		||||
											MicroServicePrivateEndPoint(), ResultText.str(), false);
 | 
			
		||||
			}
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
			Logger().log(E);
 | 
			
		||||
@@ -297,8 +376,10 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, [[maybe_unused]] ACCESS_TYPE Type) {
 | 
			
		||||
        std::string Identity(UserName + ":" + fmt::format("{}",OpenWifi::Now()) + ":" + std::to_string(rand()));
 | 
			
		||||
	[[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string &UserName,
 | 
			
		||||
															 [[maybe_unused]] ACCESS_TYPE Type) {
 | 
			
		||||
		std::string Identity(UserName + ":" + fmt::format("{}", Utils::Now()) + ":" +
 | 
			
		||||
							 std::to_string(rand()));
 | 
			
		||||
		HMAC_.update(Identity);
 | 
			
		||||
		return Poco::DigestEngine::digestToHex(HMAC_.digest());
 | 
			
		||||
	}
 | 
			
		||||
@@ -310,21 +391,27 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		T.setType("JWT");
 | 
			
		||||
		switch (Type) {
 | 
			
		||||
			case USERNAME:	T.setSubject("usertoken"); break;
 | 
			
		||||
			case SERVER: 	T.setSubject("servertoken"); break;
 | 
			
		||||
			case CUSTOM:	T.setSubject("customtoken"); break;
 | 
			
		||||
		case USERNAME:
 | 
			
		||||
			T.setSubject("usertoken");
 | 
			
		||||
			break;
 | 
			
		||||
		case SERVER:
 | 
			
		||||
			T.setSubject("servertoken");
 | 
			
		||||
			break;
 | 
			
		||||
		case CUSTOM:
 | 
			
		||||
			T.setSubject("customtoken");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		T.payload().set("identity", Identity);
 | 
			
		||||
		T.setIssuedAt(Poco::Timestamp());
 | 
			
		||||
		T.setExpiration(Poco::Timestamp() + (long long)TokenAging_);
 | 
			
		||||
		std::string JWT = MicroService::instance().Sign(T,Poco::JWT::Signer::ALGO_RS256);
 | 
			
		||||
		std::string JWT = MicroServiceSign(T, Poco::JWT::Signer::ALGO_RS256);
 | 
			
		||||
 | 
			
		||||
		return JWT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
 | 
			
		||||
    {
 | 
			
		||||
	void AuthService::CreateToken(const std::string &UserName,
 | 
			
		||||
								  SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
			
		||||
		std::lock_guard Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		SecurityObjects::AclTemplate ACL;
 | 
			
		||||
@@ -341,14 +428,15 @@ namespace OpenWifi {
 | 
			
		||||
		UInfo.webtoken.errorCode = 0;
 | 
			
		||||
		UInfo.webtoken.userMustChangePassword = false;
 | 
			
		||||
		StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
        StorageService()->UserTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
 | 
			
		||||
                            UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
 | 
			
		||||
                                UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
 | 
			
		||||
        StorageService()->LoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ );
 | 
			
		||||
		StorageService()->UserTokenDB().AddToken(
 | 
			
		||||
			UInfo.userinfo.id, UInfo.webtoken.access_token_, UInfo.webtoken.refresh_token_,
 | 
			
		||||
			UInfo.webtoken.token_type_, UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
 | 
			
		||||
		StorageService()->LoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,
 | 
			
		||||
											 UInfo.webtoken.access_token_);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void AuthService::CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
 | 
			
		||||
    {
 | 
			
		||||
	void AuthService::CreateSubToken(const std::string &UserName,
 | 
			
		||||
									 SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
			
		||||
		std::lock_guard Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		SecurityObjects::AclTemplate ACL;
 | 
			
		||||
@@ -365,13 +453,15 @@ namespace OpenWifi {
 | 
			
		||||
		UInfo.webtoken.errorCode = 0;
 | 
			
		||||
		UInfo.webtoken.userMustChangePassword = false;
 | 
			
		||||
		StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
        StorageService()->SubTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
 | 
			
		||||
                                   UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
 | 
			
		||||
                                   UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
 | 
			
		||||
        StorageService()->SubLoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ );
 | 
			
		||||
		StorageService()->SubTokenDB().AddToken(
 | 
			
		||||
			UInfo.userinfo.id, UInfo.webtoken.access_token_, UInfo.webtoken.refresh_token_,
 | 
			
		||||
			UInfo.webtoken.token_type_, UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
 | 
			
		||||
		StorageService()->SubLoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,
 | 
			
		||||
												UInfo.webtoken.access_token_);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
 | 
			
		||||
	bool AuthService::SetPassword(const std::string &NewPassword,
 | 
			
		||||
								  SecurityObjects::UserInfo &UInfo) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		Poco::toLowerInPlace(UInfo.email);
 | 
			
		||||
@@ -405,7 +495,8 @@ namespace OpenWifi {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SetSubPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
 | 
			
		||||
	bool AuthService::SetSubPassword(const std::string &NewPassword,
 | 
			
		||||
									 SecurityObjects::UserInfo &UInfo) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		Poco::toLowerInPlace(UInfo.email);
 | 
			
		||||
@@ -444,14 +535,16 @@ namespace OpenWifi {
 | 
			
		||||
		return std::to_string(start.time_since_epoch().count());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    std::string AuthService::ComputeNewPasswordHash(const std::string &UserName, const std::string &Password) {
 | 
			
		||||
	std::string AuthService::ComputeNewPasswordHash(const std::string &UserName,
 | 
			
		||||
													const std::string &Password) {
 | 
			
		||||
		std::string UName = Poco::trim(Poco::toLower(UserName));
 | 
			
		||||
		auto Salt = GetMeSomeSalt();
 | 
			
		||||
		SHA2_.update(Salt + Password + UName);
 | 
			
		||||
		return Salt + "|" + Utils::ToHex(SHA2_.digest());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
 | 
			
		||||
	bool AuthService::ValidatePasswordHash(const std::string &UserName, const std::string &Password,
 | 
			
		||||
										   const std::string &StoredPassword) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		std::string UName = Poco::trim(Poco::toLower(UserName));
 | 
			
		||||
@@ -468,7 +561,9 @@ namespace OpenWifi {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
 | 
			
		||||
	bool AuthService::ValidateSubPasswordHash(const std::string &UserName,
 | 
			
		||||
											  const std::string &Password,
 | 
			
		||||
											  const std::string &StoredPassword) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		std::string UName = Poco::trim(Poco::toLower(UserName));
 | 
			
		||||
@@ -485,13 +580,20 @@ namespace OpenWifi {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired )
 | 
			
		||||
    {
 | 
			
		||||
	UNAUTHORIZED_REASON AuthService::Authorize(std::string &UserName, const std::string &Password,
 | 
			
		||||
											   const std::string &NewPassword,
 | 
			
		||||
											   SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
											   [[maybe_unused]] bool &Expired) {
 | 
			
		||||
		std::lock_guard Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		Poco::toLowerInPlace(UserName);
 | 
			
		||||
 | 
			
		||||
		if (StorageService()->UserDB().GetUserByEmail(UserName, UInfo.userinfo)) {
 | 
			
		||||
 | 
			
		||||
			if (UInfo.userinfo.suspended) {
 | 
			
		||||
				return ACCOUNT_SUSPENDED;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (UInfo.userinfo.waitingForEmailCheck) {
 | 
			
		||||
				return USERNAME_PENDING_VERIFICATION;
 | 
			
		||||
			}
 | 
			
		||||
@@ -514,14 +616,16 @@ namespace OpenWifi {
 | 
			
		||||
					UInfo.webtoken.errorCode = 1;
 | 
			
		||||
					return PASSWORD_ALREADY_USED;
 | 
			
		||||
				}
 | 
			
		||||
                UInfo.userinfo.lastPasswordChange = OpenWifi::Now();
 | 
			
		||||
				UInfo.userinfo.lastPasswordChange = Utils::Now();
 | 
			
		||||
				UInfo.userinfo.changePassword = false;
 | 
			
		||||
                UInfo.userinfo.modified = OpenWifi::Now();
 | 
			
		||||
                StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo);
 | 
			
		||||
				UInfo.userinfo.modified = Utils::Now();
 | 
			
		||||
				StorageService()->UserDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,
 | 
			
		||||
														  UInfo.userinfo);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
            //  so we have a good password, password up date has taken place if need be, now generate the token.
 | 
			
		||||
            UInfo.userinfo.lastLogin=OpenWifi::Now();
 | 
			
		||||
			//  so we have a good password, password up date has taken place if need be, now
 | 
			
		||||
			//  generate the token.
 | 
			
		||||
			UInfo.userinfo.lastLogin = Utils::Now();
 | 
			
		||||
			StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
			CreateToken(UserName, UInfo);
 | 
			
		||||
 | 
			
		||||
@@ -530,13 +634,21 @@ namespace OpenWifi {
 | 
			
		||||
		return INVALID_CREDENTIALS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , [[maybe_unused]] bool & Expired )
 | 
			
		||||
    {
 | 
			
		||||
	UNAUTHORIZED_REASON AuthService::AuthorizeSub(std::string &UserName,
 | 
			
		||||
												  const std::string &Password,
 | 
			
		||||
												  const std::string &NewPassword,
 | 
			
		||||
												  SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
												  [[maybe_unused]] bool &Expired) {
 | 
			
		||||
		std::lock_guard Guard(Mutex_);
 | 
			
		||||
 | 
			
		||||
		Poco::toLowerInPlace(UserName);
 | 
			
		||||
 | 
			
		||||
		if (StorageService()->SubDB().GetUserByEmail(UserName, UInfo.userinfo)) {
 | 
			
		||||
 | 
			
		||||
			if (UInfo.userinfo.suspended) {
 | 
			
		||||
				return ACCOUNT_SUSPENDED;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (UInfo.userinfo.waitingForEmailCheck) {
 | 
			
		||||
				return USERNAME_PENDING_VERIFICATION;
 | 
			
		||||
			}
 | 
			
		||||
@@ -559,14 +671,16 @@ namespace OpenWifi {
 | 
			
		||||
					UInfo.webtoken.errorCode = 1;
 | 
			
		||||
					return PASSWORD_ALREADY_USED;
 | 
			
		||||
				}
 | 
			
		||||
                UInfo.userinfo.lastPasswordChange = OpenWifi::Now();
 | 
			
		||||
				UInfo.userinfo.lastPasswordChange = Utils::Now();
 | 
			
		||||
				UInfo.userinfo.changePassword = false;
 | 
			
		||||
                UInfo.userinfo.modified = OpenWifi::Now();
 | 
			
		||||
                StorageService()->SubDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,UInfo.userinfo);
 | 
			
		||||
				UInfo.userinfo.modified = Utils::Now();
 | 
			
		||||
				StorageService()->SubDB().UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.id,
 | 
			
		||||
														 UInfo.userinfo);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
            //  so we have a good password, password update has taken place if need be, now generate the token.
 | 
			
		||||
            UInfo.userinfo.lastLogin=OpenWifi::Now();
 | 
			
		||||
			//  so we have a good password, password update has taken place if need be, now generate
 | 
			
		||||
			//  the token.
 | 
			
		||||
			UInfo.userinfo.lastLogin = Utils::Now();
 | 
			
		||||
			StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
 | 
			
		||||
			CreateSubToken(UserName, UInfo);
 | 
			
		||||
 | 
			
		||||
@@ -576,26 +690,48 @@ namespace OpenWifi {
 | 
			
		||||
		return INVALID_CREDENTIALS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Challenge) {
 | 
			
		||||
	bool AuthService::SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
											 const std::string &Challenge) {
 | 
			
		||||
		auto OperatorParts = Poco::StringTokenizer(UInfo.userinfo.signingUp, ":");
 | 
			
		||||
 | 
			
		||||
		bool IsSub = UInfo.userinfo.userRole == SecurityObjects::SUBSCRIBER;
 | 
			
		||||
 | 
			
		||||
		if (UInfo.userinfo.signingUp.empty() || OperatorParts.count() != 2) {
 | 
			
		||||
			MessageAttributes Attrs;
 | 
			
		||||
			Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
 | 
			
		||||
			Attrs[LOGO] = AuthService::GetLogoAssetURI();
 | 
			
		||||
			Attrs[SUBJECT] = "Login validation code";
 | 
			
		||||
			Attrs[CHALLENGE_CODE] = Challenge;
 | 
			
		||||
            return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs);
 | 
			
		||||
			if (!IsSub) {
 | 
			
		||||
				SMTPMailerService()->AddUserVars(Attrs);
 | 
			
		||||
			} else {
 | 
			
		||||
				SMTPMailerService()->AddSubVars(Attrs);
 | 
			
		||||
			}
 | 
			
		||||
			return SMTPMailerService()->SendMessage(
 | 
			
		||||
				UInfo.userinfo.email,
 | 
			
		||||
				MessagingTemplates::TemplateName(MessagingTemplates::VERIFICATION_CODE), Attrs,
 | 
			
		||||
				false);
 | 
			
		||||
		} else {
 | 
			
		||||
			MessageAttributes Attrs;
 | 
			
		||||
			Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
 | 
			
		||||
            Attrs[LOGO] = AuthService::GetLogoAssetURI();
 | 
			
		||||
			Attrs[LOGO] = AuthService::GetSubLogoAssetURI();
 | 
			
		||||
			Attrs[SUBJECT] = "Login validation code";
 | 
			
		||||
			Attrs[CHALLENGE_CODE] = Challenge;
 | 
			
		||||
            return SMTPMailerService()->SendMessage(UInfo.userinfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,OperatorParts[0]), Attrs);
 | 
			
		||||
			if (!IsSub) {
 | 
			
		||||
				SMTPMailerService()->AddUserVars(Attrs);
 | 
			
		||||
			} else {
 | 
			
		||||
				SMTPMailerService()->AddSubVars(Attrs);
 | 
			
		||||
			}
 | 
			
		||||
			return SMTPMailerService()->SendMessage(
 | 
			
		||||
				UInfo.userinfo.email,
 | 
			
		||||
				MessagingTemplates::TemplateName(MessagingTemplates::SUB_VERIFICATION_CODE,
 | 
			
		||||
												 OperatorParts[0]),
 | 
			
		||||
				Attrs, true);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason) {
 | 
			
		||||
	bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email,
 | 
			
		||||
									  MessagingTemplates::EMAIL_REASON Reason) {
 | 
			
		||||
		SecurityObjects::UserInfo UInfo;
 | 
			
		||||
 | 
			
		||||
		if (StorageService()->UserDB().GetUserByEmail(Email, UInfo)) {
 | 
			
		||||
@@ -606,35 +742,48 @@ namespace OpenWifi {
 | 
			
		||||
				Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
				Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
				Attrs[SUBJECT] = "Password reset link";
 | 
			
		||||
                        Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
 | 
			
		||||
				Attrs[ACTION_LINK] = MicroServiceGetPublicAPIEndPoint() +
 | 
			
		||||
									 "/actionLink?action=password_reset&id=" + LinkId;
 | 
			
		||||
				Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=password_reset&id=" + LinkId;
 | 
			
		||||
                        SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
				SMTPMailerService()->AddUserVars(Attrs);
 | 
			
		||||
				SMTPMailerService()->SendMessage(
 | 
			
		||||
					UInfo.email,
 | 
			
		||||
					MessagingTemplates::TemplateName(MessagingTemplates::FORGOT_PASSWORD), Attrs,
 | 
			
		||||
					false);
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case MessagingTemplates::EMAIL_VERIFICATION: {
 | 
			
		||||
				MessageAttributes Attrs;
 | 
			
		||||
				Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
				Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
				Attrs[SUBJECT] = "e-mail Address Verification";
 | 
			
		||||
                        Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
 | 
			
		||||
                        Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_verification&id=" + LinkId ;
 | 
			
		||||
                        SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs);
 | 
			
		||||
				Attrs[ACTION_LINK] = MicroServiceGetPublicAPIEndPoint() +
 | 
			
		||||
									 "/actionLink?action=email_verification&id=" + LinkId;
 | 
			
		||||
				Attrs[ACTION_LINK_HTML] =
 | 
			
		||||
					"/api/v1/actionLink?action=email_verification&id=" + LinkId;
 | 
			
		||||
				SMTPMailerService()->AddUserVars(Attrs);
 | 
			
		||||
				SMTPMailerService()->SendMessage(
 | 
			
		||||
					UInfo.email,
 | 
			
		||||
					MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_VERIFICATION), Attrs,
 | 
			
		||||
					false);
 | 
			
		||||
				UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case MessagingTemplates::EMAIL_INVITATION: {
 | 
			
		||||
				MessageAttributes Attrs;
 | 
			
		||||
				Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
				Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
				Attrs[SUBJECT] = "e-mail Invitation";
 | 
			
		||||
                    Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_invitation&id=" + LinkId ;
 | 
			
		||||
				Attrs[ACTION_LINK] = MicroServiceGetPublicAPIEndPoint() +
 | 
			
		||||
									 "/actionLink?action=email_invitation&id=" + LinkId;
 | 
			
		||||
				Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=email_invitation&id=" + LinkId;
 | 
			
		||||
                    SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_INVITATION), Attrs);
 | 
			
		||||
				SMTPMailerService()->AddUserVars(Attrs);
 | 
			
		||||
				SMTPMailerService()->SendMessage(
 | 
			
		||||
					UInfo.email,
 | 
			
		||||
					MessagingTemplates::TemplateName(MessagingTemplates::EMAIL_INVITATION), Attrs,
 | 
			
		||||
					false);
 | 
			
		||||
				UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				break;
 | 
			
		||||
@@ -644,7 +793,9 @@ namespace OpenWifi {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName ) {
 | 
			
		||||
	bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email,
 | 
			
		||||
										 MessagingTemplates::EMAIL_REASON Reason,
 | 
			
		||||
										 const std::string &OperatorName) {
 | 
			
		||||
		SecurityObjects::UserInfo UInfo;
 | 
			
		||||
 | 
			
		||||
		if (StorageService()->SubDB().GetUserByEmail(Email, UInfo)) {
 | 
			
		||||
@@ -653,37 +804,55 @@ namespace OpenWifi {
 | 
			
		||||
			case MessagingTemplates::SUB_FORGOT_PASSWORD: {
 | 
			
		||||
				MessageAttributes Attrs;
 | 
			
		||||
				Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
                    Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
				Attrs[LOGO] = GetSubLogoAssetURI();
 | 
			
		||||
				Attrs[SUBJECT] = "Password reset link";
 | 
			
		||||
                    Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_password_reset&id=" + LinkId ;
 | 
			
		||||
                    Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_password_reset&id=" + LinkId ;
 | 
			
		||||
                    SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD, OperatorName), Attrs);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
				Attrs[ACTION_LINK] = MicroServiceGetPublicAPIEndPoint() +
 | 
			
		||||
									 "/actionLink?action=sub_password_reset&id=" + LinkId;
 | 
			
		||||
				Attrs[ACTION_LINK_HTML] =
 | 
			
		||||
					"/api/v1/actionLink?action=sub_password_reset&id=" + LinkId;
 | 
			
		||||
				SMTPMailerService()->AddSubVars(Attrs);
 | 
			
		||||
				SMTPMailerService()->SendMessage(
 | 
			
		||||
					UInfo.email,
 | 
			
		||||
					MessagingTemplates::TemplateName(MessagingTemplates::SUB_FORGOT_PASSWORD,
 | 
			
		||||
													 OperatorName),
 | 
			
		||||
					Attrs, true);
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case MessagingTemplates::SUB_EMAIL_VERIFICATION: {
 | 
			
		||||
				MessageAttributes Attrs;
 | 
			
		||||
				Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
                    Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
				Attrs[LOGO] = GetSubLogoAssetURI();
 | 
			
		||||
				Attrs[SUBJECT] = "e-mail Address Verification";
 | 
			
		||||
                    Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=sub_email_verification&id=" + LinkId ;
 | 
			
		||||
                    Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=sub_email_verification&id=" + LinkId ;
 | 
			
		||||
                    SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION, OperatorName), Attrs);
 | 
			
		||||
				Attrs[ACTION_LINK] = MicroServiceGetPublicAPIEndPoint() +
 | 
			
		||||
									 "/actionLink?action=sub_email_verification&id=" + LinkId;
 | 
			
		||||
				Attrs[ACTION_LINK_HTML] =
 | 
			
		||||
					"/api/v1/actionLink?action=sub_email_verification&id=" + LinkId;
 | 
			
		||||
				SMTPMailerService()->AddSubVars(Attrs);
 | 
			
		||||
				SMTPMailerService()->SendMessage(
 | 
			
		||||
					UInfo.email,
 | 
			
		||||
					MessagingTemplates::TemplateName(MessagingTemplates::SUB_EMAIL_VERIFICATION,
 | 
			
		||||
													 OperatorName),
 | 
			
		||||
					Attrs, true);
 | 
			
		||||
				UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
                case MessagingTemplates::SIGNUP_VERIFICATION: {
 | 
			
		||||
			case MessagingTemplates::SUB_SIGNUP_VERIFICATION: {
 | 
			
		||||
				MessageAttributes Attrs;
 | 
			
		||||
				Attrs[RECIPIENT_EMAIL] = UInfo.email;
 | 
			
		||||
                    Attrs[LOGO] = GetLogoAssetURI();
 | 
			
		||||
				Attrs[LOGO] = GetSubLogoAssetURI();
 | 
			
		||||
				Attrs[SUBJECT] = "Signup e-mail Address Verification";
 | 
			
		||||
                    Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ;
 | 
			
		||||
                    Attrs[ACTION_LINK_HTML] = "/api/v1/actionLink?action=signup_verification&id=" + LinkId ;
 | 
			
		||||
                    SMTPMailerService()->SendMessage(UInfo.email, MessagingTemplates::TemplateName(MessagingTemplates::SIGNUP_VERIFICATION, OperatorName), Attrs);
 | 
			
		||||
				Attrs[ACTION_LINK] = MicroServiceGetPublicAPIEndPoint() +
 | 
			
		||||
									 "/actionLink?action=signup_verification&id=" + LinkId;
 | 
			
		||||
				Attrs[ACTION_LINK_HTML] =
 | 
			
		||||
					"/api/v1/actionLink?action=signup_verification&id=" + LinkId;
 | 
			
		||||
				SMTPMailerService()->AddSubVars(Attrs);
 | 
			
		||||
				SMTPMailerService()->SendMessage(
 | 
			
		||||
					UInfo.email,
 | 
			
		||||
					MessagingTemplates::TemplateName(MessagingTemplates::SUB_SIGNUP_VERIFICATION,
 | 
			
		||||
													 OperatorName),
 | 
			
		||||
					Attrs, true);
 | 
			
		||||
				UInfo.waitingForEmailCheck = true;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				break;
 | 
			
		||||
@@ -698,8 +867,8 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
 | 
			
		||||
		A.userId = UInfo.id;
 | 
			
		||||
        A.id = MicroService::CreateUUID();
 | 
			
		||||
        A.created = OpenWifi::Now();
 | 
			
		||||
		A.id = MicroServiceCreateUUID();
 | 
			
		||||
		A.created = Utils::Now();
 | 
			
		||||
		A.expires = A.created + 24 * 60 * 60;
 | 
			
		||||
		A.userAction = true;
 | 
			
		||||
		StorageService()->ActionLinksDB().CreateAction(A);
 | 
			
		||||
@@ -713,8 +882,8 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL;
 | 
			
		||||
		A.userId = UInfo.id;
 | 
			
		||||
        A.id = MicroService::CreateUUID();
 | 
			
		||||
        A.created = OpenWifi::Now();
 | 
			
		||||
		A.id = MicroServiceCreateUUID();
 | 
			
		||||
		A.created = Utils::Now();
 | 
			
		||||
		A.expires = A.created + 24 * 60 * 60;
 | 
			
		||||
		A.userAction = false;
 | 
			
		||||
		StorageService()->ActionLinksDB().CreateAction(A);
 | 
			
		||||
@@ -723,7 +892,8 @@ namespace OpenWifi {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
 | 
			
		||||
	bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken,
 | 
			
		||||
								   SecurityObjects::UserInfo &UserInfo, bool &Expired) {
 | 
			
		||||
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
		Expired = false;
 | 
			
		||||
@@ -734,18 +904,17 @@ namespace OpenWifi {
 | 
			
		||||
		if (StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
			if (RevocationDate != 0)
 | 
			
		||||
				return false;
 | 
			
		||||
            Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now();
 | 
			
		||||
			Expired = (WT.created_ + WT.expires_in_) < Utils::Now();
 | 
			
		||||
			if (StorageService()->UserDB().GetUserById(UserId, UserInfo)) {
 | 
			
		||||
				WebToken = WT;
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
            return false;
 | 
			
		||||
		}
 | 
			
		||||
        // return IsValidSubToken(Token, WebToken, UserInfo, Expired);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
 | 
			
		||||
	bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken,
 | 
			
		||||
									  SecurityObjects::UserInfo &UserInfo, bool &Expired) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
		Expired = false;
 | 
			
		||||
 | 
			
		||||
@@ -755,14 +924,42 @@ namespace OpenWifi {
 | 
			
		||||
		if (StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
 | 
			
		||||
			if (RevocationDate != 0)
 | 
			
		||||
				return false;
 | 
			
		||||
            Expired = (WT.created_ + WT.expires_in_) < OpenWifi::Now();
 | 
			
		||||
			Expired = (WT.created_ + WT.expires_in_) < Utils::Now();
 | 
			
		||||
			if (StorageService()->SubDB().GetUserById(UserId, UserInfo)) {
 | 
			
		||||
				WebToken = WT;
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
            return false;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}  // end of namespace
 | 
			
		||||
	bool AuthService::IsValidApiKey(const std::string &ApiKey, SecurityObjects::WebToken &WebToken,
 | 
			
		||||
									SecurityObjects::UserInfo &UserInfo, bool &Expired,
 | 
			
		||||
									std::uint64_t &expiresOn, bool &Suspended) {
 | 
			
		||||
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		Suspended = false;
 | 
			
		||||
		std::string UserId;
 | 
			
		||||
		SecurityObjects::WebToken WT;
 | 
			
		||||
		SecurityObjects::ApiKeyEntry ApiKeyEntry;
 | 
			
		||||
		if (StorageService()->ApiKeyDB().GetRecord("apiKey", ApiKey, ApiKeyEntry)) {
 | 
			
		||||
			expiresOn = ApiKeyEntry.expiresOn;
 | 
			
		||||
			Expired = ApiKeyEntry.expiresOn < Utils::Now();
 | 
			
		||||
			if (Expired)
 | 
			
		||||
				return false;
 | 
			
		||||
			if (StorageService()->UserDB().GetUserById(ApiKeyEntry.userUuid, UserInfo)) {
 | 
			
		||||
				if (UserInfo.suspended) {
 | 
			
		||||
					Suspended = true;
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				WebToken = WT;
 | 
			
		||||
				ApiKeyEntry.lastUse = Utils::Now();
 | 
			
		||||
				StorageService()->ApiKeyDB().UpdateRecord("id", ApiKeyEntry.id, ApiKeyEntry);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -6,24 +6,25 @@
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifndef UCENTRAL_UAUTHSERVICE_H
 | 
			
		||||
#define UCENTRAL_UAUTHSERVICE_H
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <regex>
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
#include "Poco/Crypto/DigestEngine.h"
 | 
			
		||||
#include "Poco/ExpireLRUCache.h"
 | 
			
		||||
#include "Poco/HMACEngine.h"
 | 
			
		||||
#include "Poco/JSON/Object.h"
 | 
			
		||||
#include "Poco/JWT/Signer.h"
 | 
			
		||||
#include "Poco/Net/HTTPServerRequest.h"
 | 
			
		||||
#include "Poco/Net/HTTPServerResponse.h"
 | 
			
		||||
#include "Poco/JWT/Signer.h"
 | 
			
		||||
#include "Poco/SHA2Engine.h"
 | 
			
		||||
#include "Poco/Crypto/DigestEngine.h"
 | 
			
		||||
#include "Poco/HMACEngine.h"
 | 
			
		||||
#include "Poco/ExpireLRUCache.h"
 | 
			
		||||
#include "framework/SubSystemServer.h"
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
#include "MessagingTemplates.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -31,12 +32,7 @@ namespace OpenWifi{
 | 
			
		||||
 | 
			
		||||
	class AuthService : public SubSystemServer {
 | 
			
		||||
	  public:
 | 
			
		||||
 | 
			
		||||
        enum ACCESS_TYPE {
 | 
			
		||||
            USERNAME,
 | 
			
		||||
            SERVER,
 | 
			
		||||
            CUSTOM
 | 
			
		||||
        };
 | 
			
		||||
		enum ACCESS_TYPE { USERNAME, SERVER, CUSTOM };
 | 
			
		||||
 | 
			
		||||
		static ACCESS_TYPE IntToAccessType(int C);
 | 
			
		||||
		static int AccessTypeToInt(ACCESS_TYPE T);
 | 
			
		||||
@@ -49,18 +45,43 @@ namespace OpenWifi{
 | 
			
		||||
		int Start() override;
 | 
			
		||||
		void Stop() override;
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
 | 
			
		||||
        [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
 | 
			
		||||
		[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest &Request,
 | 
			
		||||
										std::string &SessionToken,
 | 
			
		||||
										SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
										std::uint64_t TID, bool &Expired);
 | 
			
		||||
		[[nodiscard]] bool IsAuthorized(const std::string &SessionToken,
 | 
			
		||||
										SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
										std::uint64_t TID, bool &Expired);
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] UNAUTHORIZED_REASON Authorize(std::string &UserName,
 | 
			
		||||
													const std::string &Password,
 | 
			
		||||
													const std::string &NewPassword,
 | 
			
		||||
													SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
													bool &Expired);
 | 
			
		||||
		void CreateToken(const std::string &UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
        [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
 | 
			
		||||
        [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
			
		||||
		[[nodiscard]] bool SetPassword(const std::string &Password,
 | 
			
		||||
									   SecurityObjects::UserInfo &UInfo);
 | 
			
		||||
		[[nodiscard]] const std::string &PasswordValidationExpression() const {
 | 
			
		||||
			return PasswordValidationStr_;
 | 
			
		||||
		};
 | 
			
		||||
		void Logout(const std::string &token, bool EraseFromCache = true);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired);
 | 
			
		||||
        [[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
 | 
			
		||||
		[[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest &Request,
 | 
			
		||||
										   std::string &SessionToken,
 | 
			
		||||
										   SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
										   std::uint64_t TID, bool &Expired);
 | 
			
		||||
		[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub(std::string &UserName,
 | 
			
		||||
													   const std::string &Password,
 | 
			
		||||
													   const std::string &NewPassword,
 | 
			
		||||
													   SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
													   bool &Expired);
 | 
			
		||||
 | 
			
		||||
		void CreateSubToken(const std::string &UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
        [[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
 | 
			
		||||
        [[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;};
 | 
			
		||||
		[[nodiscard]] bool SetSubPassword(const std::string &Password,
 | 
			
		||||
										  SecurityObjects::UserInfo &UInfo);
 | 
			
		||||
		[[nodiscard]] const std::string &SubPasswordValidationExpression() const {
 | 
			
		||||
			return PasswordValidationStr_;
 | 
			
		||||
		};
 | 
			
		||||
		void SubLogout(const std::string &token, bool EraseFromCache = true);
 | 
			
		||||
 | 
			
		||||
		void RemoveTokenSystemWide(const std::string &token);
 | 
			
		||||
@@ -68,29 +89,52 @@ namespace OpenWifi{
 | 
			
		||||
		bool ValidatePassword(const std::string &pwd);
 | 
			
		||||
		bool ValidateSubPassword(const std::string &pwd);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
 | 
			
		||||
        [[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
 | 
			
		||||
		[[nodiscard]] bool IsValidToken(const std::string &Token,
 | 
			
		||||
										SecurityObjects::WebToken &WebToken,
 | 
			
		||||
										SecurityObjects::UserInfo &UserInfo, 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]] 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 IsValidApiKey(const std::string &ApiKey,
 | 
			
		||||
										 SecurityObjects::WebToken &WebToken,
 | 
			
		||||
										 SecurityObjects::UserInfo &UserInfo, bool &Expired,
 | 
			
		||||
										 std::uint64_t &expiresOn, bool &Suspended);
 | 
			
		||||
		[[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName,
 | 
			
		||||
														 const std::string &Password);
 | 
			
		||||
		[[nodiscard]] bool ValidatePasswordHash(const std::string &UserName,
 | 
			
		||||
												const std::string &Password,
 | 
			
		||||
												const std::string &StoredPassword);
 | 
			
		||||
		[[nodiscard]] bool ValidateSubPasswordHash(const std::string &UserName,
 | 
			
		||||
												   const std::string &Password,
 | 
			
		||||
												   const std::string &StoredPassword);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
 | 
			
		||||
        [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
 | 
			
		||||
		[[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName,
 | 
			
		||||
										  const std::string &OldPassword,
 | 
			
		||||
										  const std::string &NewPassword);
 | 
			
		||||
		[[nodiscard]] std::string ResetPassword(const std::string &Admin,
 | 
			
		||||
												const std::string &UserName);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
 | 
			
		||||
        [[nodiscard]] std::string ResetSubPassword(const std::string &Admin, const std::string &UserName);
 | 
			
		||||
		[[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName,
 | 
			
		||||
											 const std::string &OldPassword,
 | 
			
		||||
											 const std::string &NewPassword);
 | 
			
		||||
		[[nodiscard]] std::string ResetSubPassword(const std::string &Admin,
 | 
			
		||||
												   const std::string &UserName);
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
 | 
			
		||||
		[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason);
 | 
			
		||||
        [[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, MessagingTemplates::EMAIL_REASON Reason, const std::string &OperatorName);
 | 
			
		||||
		[[nodiscard]] 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);
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &code);
 | 
			
		||||
		[[nodiscard]] bool SendEmailChallengeCode(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
												  const std::string &code);
 | 
			
		||||
 | 
			
		||||
		bool DeleteUserFromCache(const std::string &UserName);
 | 
			
		||||
		bool DeleteSubUserFromCache(const std::string &UserName);
 | 
			
		||||
@@ -98,11 +142,19 @@ namespace OpenWifi{
 | 
			
		||||
		void RevokeSubToken(std::string &Token);
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] static inline const std::string GetLogoAssetURI() {
 | 
			
		||||
            return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
 | 
			
		||||
			return MicroServicePublicEndPoint() + "/wwwassets/logo.png";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
 | 
			
		||||
            return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
 | 
			
		||||
			return MicroServiceWWWAssetsDir() + "/logo.png";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] static inline const std::string GetSubLogoAssetURI() {
 | 
			
		||||
			return MicroServicePublicEndPoint() + "/wwwassets/sub_logo.png";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] static inline const std::string GetSubLogoAssetFileName() {
 | 
			
		||||
			return MicroServiceWWWAssetsDir() + "/sub_logo.png";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		inline const std::string &GetPasswordPolicy() const { return PasswordPolicy_; }
 | 
			
		||||
@@ -111,8 +163,22 @@ namespace OpenWifi{
 | 
			
		||||
		inline const std::string &GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
 | 
			
		||||
		inline const std::string &GetSubAccessPolicy() const { return SubAccessPolicy_; }
 | 
			
		||||
 | 
			
		||||
        bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
 | 
			
		||||
        bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
 | 
			
		||||
		bool RefreshUserToken(Poco::Net::HTTPServerRequest &Request,
 | 
			
		||||
							  const std::string &RefreshToken,
 | 
			
		||||
							  SecurityObjects::UserInfoAndPolicy &UI);
 | 
			
		||||
		bool RefreshSubToken(Poco::Net::HTTPServerRequest &Request, const std::string &RefreshToken,
 | 
			
		||||
							 SecurityObjects::UserInfoAndPolicy &UI);
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]] inline auto HelperEmail() const { return HelperEmail_; };
 | 
			
		||||
		[[nodiscard]] inline auto SubHelperEmail() const { return SubHelperEmail_; };
 | 
			
		||||
		[[nodiscard]] inline auto GlobalHelperEmail() const { return GlobalHelperEmail_; };
 | 
			
		||||
		[[nodiscard]] inline auto GlobalSubHelperEmail() const { return GlobalSubHelperEmail_; };
 | 
			
		||||
		[[nodiscard]] inline auto HelperSite() const { return HelperSite_; };
 | 
			
		||||
		[[nodiscard]] inline auto SubHelperSite() const { return SubHelperSite_; };
 | 
			
		||||
		[[nodiscard]] inline auto SystemLoginSite() const { return SystemLoginSite_; };
 | 
			
		||||
		[[nodiscard]] inline auto SubSystemLoginSite() const { return SubSystemLoginSite_; };
 | 
			
		||||
		[[nodiscard]] inline auto UserSignature() const { return UserSignature_; };
 | 
			
		||||
		[[nodiscard]] inline auto SubSignature() const { return SubSignature_; };
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
		Poco::SHA2Engine SHA2_;
 | 
			
		||||
@@ -130,39 +196,39 @@ namespace OpenWifi{
 | 
			
		||||
		uint64_t HowManyOldPassword_ = 5;
 | 
			
		||||
		uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60;
 | 
			
		||||
 | 
			
		||||
        class SHA256Engine : public Poco::Crypto::DigestEngine
 | 
			
		||||
                {
 | 
			
		||||
		std::string HelperEmail_;
 | 
			
		||||
		std::string SubHelperEmail_;
 | 
			
		||||
		std::string GlobalHelperEmail_;
 | 
			
		||||
		std::string GlobalSubHelperEmail_;
 | 
			
		||||
		std::string HelperSite_;
 | 
			
		||||
		std::string SubHelperSite_;
 | 
			
		||||
		std::string SystemLoginSite_;
 | 
			
		||||
		std::string SubSystemLoginSite_;
 | 
			
		||||
		std::string UserSignature_;
 | 
			
		||||
		std::string SubSignature_;
 | 
			
		||||
 | 
			
		||||
		class SHA256Engine : public Poco::Crypto::DigestEngine {
 | 
			
		||||
		  public:
 | 
			
		||||
                    enum
 | 
			
		||||
                    {
 | 
			
		||||
                        BLOCK_SIZE = 64,
 | 
			
		||||
                        DIGEST_SIZE = 32
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    SHA256Engine()
 | 
			
		||||
                    : DigestEngine("SHA256")
 | 
			
		||||
                    {
 | 
			
		||||
                    }
 | 
			
		||||
			enum { BLOCK_SIZE = 64, DIGEST_SIZE = 32 };
 | 
			
		||||
 | 
			
		||||
			SHA256Engine() : DigestEngine("SHA256") {}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		Poco::HMACEngine<SHA256Engine> HMAC_{"tipopenwifi"};
 | 
			
		||||
 | 
			
		||||
        AuthService() noexcept:
 | 
			
		||||
            SubSystemServer("Authentication", "AUTH-SVR", "authentication")
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
		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 ) {
 | 
			
		||||
	[[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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
} // end of namespace
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRAL_UAUTHSERVICE_H
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -10,42 +10,36 @@
 | 
			
		||||
//	Arilia Wireless Inc.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "Poco/Environment.h"
 | 
			
		||||
#include "Poco/Util/Application.h"
 | 
			
		||||
#include "Poco/Util/Option.h"
 | 
			
		||||
#include "Poco/Environment.h"
 | 
			
		||||
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
 | 
			
		||||
#include <aws/core/Aws.h>
 | 
			
		||||
#include <aws/s3/model/AccessControlPolicy.h>
 | 
			
		||||
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "ActionLinkManager.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "ActionLinkManager.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "TotpCache.h"
 | 
			
		||||
#include "framework/RESTAPI_RateLimiter.h"
 | 
			
		||||
#include "framework/UI_WebSocketClientServer.h"
 | 
			
		||||
#include <SecretStore.h>
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class Daemon *Daemon::instance_ = nullptr;
 | 
			
		||||
 | 
			
		||||
	class Daemon *Daemon::instance() {
 | 
			
		||||
		if (instance_ == nullptr) {
 | 
			
		||||
            instance_ = new Daemon(vDAEMON_PROPERTIES_FILENAME,
 | 
			
		||||
                                   vDAEMON_ROOT_ENV_VAR,
 | 
			
		||||
                                   vDAEMON_CONFIG_ENV_VAR,
 | 
			
		||||
                                   vDAEMON_APP_NAME,
 | 
			
		||||
                                   vDAEMON_BUS_TIMER,
 | 
			
		||||
                                   SubSystemVec{
 | 
			
		||||
                                           StorageService(),
 | 
			
		||||
                                           SMSSender(),
 | 
			
		||||
                                           ActionLinkManager(),
 | 
			
		||||
                                           SMTPMailerService(),
 | 
			
		||||
                                           RESTAPI_RateLimiter(),
 | 
			
		||||
                                           TotpCache(),
 | 
			
		||||
                                           AuthService()
 | 
			
		||||
                                   });
 | 
			
		||||
			instance_ =
 | 
			
		||||
				new Daemon(vDAEMON_PROPERTIES_FILENAME, vDAEMON_ROOT_ENV_VAR,
 | 
			
		||||
						   vDAEMON_CONFIG_ENV_VAR, vDAEMON_APP_NAME, vDAEMON_BUS_TIMER,
 | 
			
		||||
						   SubSystemVec{StorageService(), SMSSender(), ActionLinkManager(),
 | 
			
		||||
										SMTPMailerService(), RESTAPI_RateLimiter(), TotpCache(),
 | 
			
		||||
										AuthService(), UI_WebSocketClientServer(), SecretStore()});
 | 
			
		||||
		}
 | 
			
		||||
		return instance_;
 | 
			
		||||
	}
 | 
			
		||||
@@ -53,7 +47,11 @@ namespace OpenWifi {
 | 
			
		||||
	void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
 | 
			
		||||
		AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
			
		||||
		Daemon()->PostInitialization(self);
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
	try {
 | 
			
		||||
@@ -78,5 +76,4 @@ int main(int argc, char **argv) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// end of namespace
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								src/Daemon.h
									
									
									
									
									
								
							
							
						
						@@ -2,26 +2,25 @@
 | 
			
		||||
// Created by stephane bourque on 2021-06-10.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifndef UCENTRALSEC_DAEMON_H
 | 
			
		||||
#define UCENTRALSEC_DAEMON_H
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/MicroServiceNames.h"
 | 
			
		||||
 | 
			
		||||
#include "Poco/Crypto/Cipher.h"
 | 
			
		||||
#include "Poco/Crypto/CipherFactory.h"
 | 
			
		||||
#include "Poco/Crypto/RSAKey.h"
 | 
			
		||||
#include "Poco/ErrorHandler.h"
 | 
			
		||||
#include "Poco/UUIDGenerator.h"
 | 
			
		||||
#include "Poco/Util/Application.h"
 | 
			
		||||
#include "Poco/Util/ServerApplication.h"
 | 
			
		||||
#include "Poco/Util/Option.h"
 | 
			
		||||
#include "Poco/Util/OptionSet.h"
 | 
			
		||||
#include "Poco/UUIDGenerator.h"
 | 
			
		||||
#include "Poco/ErrorHandler.h"
 | 
			
		||||
#include "Poco/Crypto/RSAKey.h"
 | 
			
		||||
#include "Poco/Crypto/CipherFactory.h"
 | 
			
		||||
#include "Poco/Crypto/Cipher.h"
 | 
			
		||||
 | 
			
		||||
#include "Poco/Util/ServerApplication.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -33,26 +32,20 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class Daemon : public MicroService {
 | 
			
		||||
	  public:
 | 
			
		||||
        explicit Daemon(const std::string & PropFile,
 | 
			
		||||
                        const std::string & RootEnv,
 | 
			
		||||
                        const std::string & ConfigEnv,
 | 
			
		||||
                        const std::string & AppName,
 | 
			
		||||
                        uint64_t BusTimer,
 | 
			
		||||
                        const SubSystemVec & SubSystems) :
 | 
			
		||||
                MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
 | 
			
		||||
		explicit Daemon(const std::string &PropFile, const std::string &RootEnv,
 | 
			
		||||
						const std::string &ConfigEnv, const std::string &AppName, uint64_t BusTimer,
 | 
			
		||||
						const SubSystemVec &SubSystems)
 | 
			
		||||
			: MicroService(PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems){};
 | 
			
		||||
 | 
			
		||||
		void PostInitialization(Poco::Util::Application &self);
 | 
			
		||||
		static Daemon *instance();
 | 
			
		||||
		inline const std::string &AssetDir() { return AssetDir_; }
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
		static Daemon *instance_;
 | 
			
		||||
		std::string AssetDir_;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline Daemon *Daemon() { return Daemon::instance(); }
 | 
			
		||||
    inline void DaemonPostInitialization(Poco::Util::Application &self) {
 | 
			
		||||
        Daemon()->PostInitialization(self);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif //UCENTRALSEC_DAEMON_H
 | 
			
		||||
	void DaemonPostInitialization(Poco::Util::Application &self);
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -2,24 +2,23 @@
 | 
			
		||||
// Created by stephane bourque on 2021-10-11.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "TotpCache.h"
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
#include "framework/utils.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    int MFAServer::Start() {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
	int MFAServer::Start() { return 0; }
 | 
			
		||||
 | 
			
		||||
    void MFAServer::Stop() {
 | 
			
		||||
    }
 | 
			
		||||
	void MFAServer::Stop() {}
 | 
			
		||||
 | 
			
		||||
    bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &ChallengeStart) {
 | 
			
		||||
	bool MFAServer::StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
									  Poco::JSON::Object &ChallengeStart) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		CleanCache();
 | 
			
		||||
@@ -28,25 +27,34 @@ namespace OpenWifi {
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		std::string Challenge = MakeChallenge();
 | 
			
		||||
        std::string uuid = MicroService::CreateUUID();
 | 
			
		||||
        uint64_t Created = OpenWifi::Now();
 | 
			
		||||
		std::string uuid = MicroServiceCreateUUID();
 | 
			
		||||
		uint64_t Created = Utils::Now();
 | 
			
		||||
 | 
			
		||||
		ChallengeStart.set("uuid", uuid);
 | 
			
		||||
		ChallengeStart.set("created", Created);
 | 
			
		||||
		ChallengeStart.set("question", "mfa challenge");
 | 
			
		||||
		ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
 | 
			
		||||
 | 
			
		||||
        Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method };
 | 
			
		||||
		Cache_[uuid] = MFACacheEntry{.UInfo = UInfo,
 | 
			
		||||
									 .Answer = Challenge,
 | 
			
		||||
									 .Created = Created,
 | 
			
		||||
									 .Method = UInfo.userinfo.userTypeProprietaryInfo.mfa.method};
 | 
			
		||||
		return SendChallenge(UInfo, UInfo.userinfo.userTypeProprietaryInfo.mfa.method, Challenge);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) {
 | 
			
		||||
        if(Method==MFAMETHODS::SMS && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
 | 
			
		||||
            std::string Message = "This is your login code: " + Challenge + " Please enter this in your login screen.";
 | 
			
		||||
            return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message);
 | 
			
		||||
        } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
 | 
			
		||||
	bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
								  const std::string &Method, const std::string &Challenge) {
 | 
			
		||||
		if (Method == MFAMETHODS::SMS && SMSSender()->Enabled() &&
 | 
			
		||||
			!UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) {
 | 
			
		||||
			std::string Message = "This is your login code: " + Challenge +
 | 
			
		||||
								  " Please enter this in your login screen.";
 | 
			
		||||
			return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number,
 | 
			
		||||
									 Message);
 | 
			
		||||
		} else if (Method == MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() &&
 | 
			
		||||
				   !UInfo.userinfo.email.empty()) {
 | 
			
		||||
			return AuthService()->SendEmailChallengeCode(UInfo, Challenge);
 | 
			
		||||
        } else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
			
		||||
		} else if (Method == MFAMETHODS::AUTHENTICATOR &&
 | 
			
		||||
				   !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +69,8 @@ namespace OpenWifi {
 | 
			
		||||
		return SendChallenge(Hint->second.UInfo, Hint->second.Method, Hint->second.Answer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
			
		||||
	bool MFAServer::CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
 | 
			
		||||
										 SecurityObjects::UserInfoAndPolicy &UInfo) {
 | 
			
		||||
		std::lock_guard G(Mutex_);
 | 
			
		||||
 | 
			
		||||
		if (!ChallengeResponse->has("uuid") || !ChallengeResponse->has("answer"))
 | 
			
		||||
@@ -76,7 +85,9 @@ namespace OpenWifi {
 | 
			
		||||
		auto answer = ChallengeResponse->get("answer").toString();
 | 
			
		||||
		std::string Expecting;
 | 
			
		||||
		if (Hint->second.Method == MFAMETHODS::AUTHENTICATOR) {
 | 
			
		||||
            if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) {
 | 
			
		||||
			if (!TotpCache()->ValidateCode(
 | 
			
		||||
					Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret, answer,
 | 
			
		||||
					Expecting)) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (Hint->second.Answer != answer) {
 | 
			
		||||
@@ -103,7 +114,7 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	void MFAServer::CleanCache() {
 | 
			
		||||
		// 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_);) {
 | 
			
		||||
			if ((Now - i->second.Created) > 300) {
 | 
			
		||||
				i = Cache_.erase(i);
 | 
			
		||||
@@ -112,4 +123,4 @@ namespace OpenWifi {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,9 +4,12 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "Poco/JSON/Object.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
#include "framework/SubSystemServer.h"
 | 
			
		||||
 | 
			
		||||
#include "fmt/format.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +21,7 @@ namespace OpenWifi {
 | 
			
		||||
		inline bool Validate(const std::string &M) {
 | 
			
		||||
			return std::find(cbegin(Methods), cend(Methods), M) != Methods.end();
 | 
			
		||||
		}
 | 
			
		||||
    }
 | 
			
		||||
	} // namespace MFAMETHODS
 | 
			
		||||
 | 
			
		||||
	struct MFACacheEntry {
 | 
			
		||||
		SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
@@ -27,7 +30,6 @@ namespace OpenWifi {
 | 
			
		||||
		std::string Method;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	typedef std::map<std::string, MFACacheEntry> MFAChallengeCache;
 | 
			
		||||
 | 
			
		||||
	class MFAServer : public SubSystemServer {
 | 
			
		||||
@@ -39,26 +41,25 @@ namespace OpenWifi {
 | 
			
		||||
			return instance_;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
 | 
			
		||||
        bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
		bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
							   Poco::JSON::Object &Challenge);
 | 
			
		||||
		bool CompleteMFAChallenge(const Poco::JSON::Object::Ptr &ChallengeResponse,
 | 
			
		||||
								  SecurityObjects::UserInfoAndPolicy &UInfo);
 | 
			
		||||
		static bool MethodEnabled(const std::string &Method);
 | 
			
		||||
		bool ResendCode(const std::string &uuid);
 | 
			
		||||
        static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
 | 
			
		||||
		static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo,
 | 
			
		||||
								  const std::string &Method, const std::string &Challenge);
 | 
			
		||||
 | 
			
		||||
		static inline std::string MakeChallenge() {
 | 
			
		||||
            return fmt::format("{0:06}" , MicroService::instance().Random(1,999999) );
 | 
			
		||||
			return fmt::format("{0:06}", MicroServiceRandom(1, 999999));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
		MFAChallengeCache Cache_;
 | 
			
		||||
        MFAServer() noexcept:
 | 
			
		||||
            SubSystemServer("MFServer", "MFA-SVR", "mfa")
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
		MFAServer() noexcept : SubSystemServer("MFServer", "MFA-SVR", "mfa") {}
 | 
			
		||||
 | 
			
		||||
		void CleanCache();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline auto MFAServer() { return MFAServer::instance(); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by stephane bourque on 2022-07-25.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "MessagingTemplates.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
} // OpenWifi
 | 
			
		||||
@@ -19,15 +19,23 @@ namespace OpenWifi {
 | 
			
		||||
		enum EMAIL_REASON {
 | 
			
		||||
			FORGOT_PASSWORD = 0,
 | 
			
		||||
			EMAIL_VERIFICATION,
 | 
			
		||||
            SIGNUP_VERIFICATION,
 | 
			
		||||
			SUB_SIGNUP_VERIFICATION,
 | 
			
		||||
			EMAIL_INVITATION,
 | 
			
		||||
			VERIFICATION_CODE,
 | 
			
		||||
			SUB_FORGOT_PASSWORD,
 | 
			
		||||
			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,
 | 
			
		||||
									   const std::string &OperatorName) {
 | 
			
		||||
			if (OperatorName.empty())
 | 
			
		||||
				return "/" + filename;
 | 
			
		||||
			return "/" + OperatorName + "/" + filename;
 | 
			
		||||
@@ -35,41 +43,70 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		static std::string TemplateName(EMAIL_REASON r, const std::string &OperatorName = "") {
 | 
			
		||||
			switch (r) {
 | 
			
		||||
                case FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[FORGOT_PASSWORD],OperatorName);
 | 
			
		||||
                case EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION],OperatorName);
 | 
			
		||||
                case SIGNUP_VERIFICATION: return AddOperator(EmailTemplateNames[SIGNUP_VERIFICATION],OperatorName);
 | 
			
		||||
                case EMAIL_INVITATION: return AddOperator(EmailTemplateNames[EMAIL_INVITATION],OperatorName);
 | 
			
		||||
                case VERIFICATION_CODE: return AddOperator(EmailTemplateNames[VERIFICATION_CODE],OperatorName);
 | 
			
		||||
                case SUB_FORGOT_PASSWORD: return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD],OperatorName);
 | 
			
		||||
                case SUB_EMAIL_VERIFICATION: return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION],OperatorName);
 | 
			
		||||
                case SUB_VERIFICATION_CODE: return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE],OperatorName);
 | 
			
		||||
			case FORGOT_PASSWORD:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[FORGOT_PASSWORD], OperatorName);
 | 
			
		||||
			case EMAIL_VERIFICATION:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[EMAIL_VERIFICATION], OperatorName);
 | 
			
		||||
			case SUB_SIGNUP_VERIFICATION:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[SUB_SIGNUP_VERIFICATION], OperatorName);
 | 
			
		||||
			case EMAIL_INVITATION:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[EMAIL_INVITATION], OperatorName);
 | 
			
		||||
			case VERIFICATION_CODE:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[VERIFICATION_CODE], OperatorName);
 | 
			
		||||
			case SUB_FORGOT_PASSWORD:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[SUB_FORGOT_PASSWORD], OperatorName);
 | 
			
		||||
			case SUB_EMAIL_VERIFICATION:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[SUB_EMAIL_VERIFICATION], OperatorName);
 | 
			
		||||
			case SUB_VERIFICATION_CODE:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[SUB_VERIFICATION_CODE], OperatorName);
 | 
			
		||||
			case CERTIFICATE_TRANSFER_NOTIFICATION:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_NOTIFICATION],
 | 
			
		||||
								   OperatorName);
 | 
			
		||||
			case CERTIFICATE_TRANSFER_AUTHORIZATION:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_AUTHORIZATION],
 | 
			
		||||
								   OperatorName);
 | 
			
		||||
			case CERTIFICATE_DISPUTE_SUCCESS:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_DISPUTE_SUCCESS], OperatorName);
 | 
			
		||||
			case CERTIFICATE_DISPUTE_REJECTED:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_DISPUTE_REJECTED], OperatorName);
 | 
			
		||||
			case CERTIFICATE_TRANSFER_CANCELED:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_CANCELED], OperatorName);
 | 
			
		||||
			case CERTIFICATE_TRANSFER_ACCEPTED:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_ACCEPTED], OperatorName);
 | 
			
		||||
			case CERTIFICATE_TRANSFER_REJECTED:
 | 
			
		||||
				return AddOperator(EmailTemplateNames[CERTIFICATE_TRANSFER_REJECTED], OperatorName);
 | 
			
		||||
			default:
 | 
			
		||||
				return "";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static std::string Logo(const std::string &OperatorName = "") {
 | 
			
		||||
            return AddOperator("logo.jpg", OperatorName);
 | 
			
		||||
			return AddOperator("logo.png", OperatorName);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static std::string SubLogo(const std::string &OperatorName = "") {
 | 
			
		||||
            return AddOperator("sub_logo.jpg", OperatorName);
 | 
			
		||||
			return AddOperator("sub_logo.png", OperatorName);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
		inline const static std::vector<std::string> EmailTemplateNames = {
 | 
			
		||||
			"password_reset",
 | 
			
		||||
			"email_verification",
 | 
			
		||||
                "signup_verification",
 | 
			
		||||
			"sub_signup_verification",
 | 
			
		||||
			"email_invitation",
 | 
			
		||||
			"verification_code",
 | 
			
		||||
			"sub_password_reset",
 | 
			
		||||
			"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(); }
 | 
			
		||||
 | 
			
		||||
} // OpenWifi
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -7,16 +7,29 @@
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_action_links.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/OpenAPIRequests.h"
 | 
			
		||||
#include "framework/RESTAPI_PartHandler.h"
 | 
			
		||||
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
#if defined(TIP_CERT_SERVICE)
 | 
			
		||||
	bool ProcessExternalActionLinks(RESTAPIHandler &handler, const std::string &Id,
 | 
			
		||||
									const std::string &Action);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_action_links::DoGet() {
 | 
			
		||||
 | 
			
		||||
		auto Action = GetParameter("action", "");
 | 
			
		||||
		auto Id = GetParameter("id", "");
 | 
			
		||||
 | 
			
		||||
#if defined(TIP_CERT_SERVICE)
 | 
			
		||||
		if (!OpenWifi::ProcessExternalActionLinks(*this, Id, Action)) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		SecurityObjects::ActionLink Link;
 | 
			
		||||
		if (!StorageService()->ActionLinksDB().GetActionLink(Id, Link))
 | 
			
		||||
			return DoReturnA404();
 | 
			
		||||
@@ -50,19 +63,40 @@ namespace OpenWifi {
 | 
			
		||||
			return DoReturnA404();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_action_links::AddGlobalVars(Types::StringPairVec &Vars) {
 | 
			
		||||
		Vars.push_back(std::make_pair("USER_HELPER_EMAIL", AuthService()->HelperEmail()));
 | 
			
		||||
		Vars.push_back(std::make_pair("SUB_HELPER_EMAIL", AuthService()->SubHelperEmail()));
 | 
			
		||||
		Vars.push_back(
 | 
			
		||||
			std::make_pair("GLOBAL_USER_HELPER_EMAIL", AuthService()->GlobalHelperEmail()));
 | 
			
		||||
		Vars.push_back(
 | 
			
		||||
			std::make_pair("GLOBAL_SUB_HELPER_EMAIL", AuthService()->GlobalSubHelperEmail()));
 | 
			
		||||
		Vars.push_back(std::make_pair("USER_HELPER_SITE", AuthService()->HelperSite()));
 | 
			
		||||
		Vars.push_back(std::make_pair("SUB_HELPER_SITE", AuthService()->SubHelperSite()));
 | 
			
		||||
		Vars.push_back(std::make_pair("USER_SYSTEM_LOGIN", AuthService()->SystemLoginSite()));
 | 
			
		||||
		Vars.push_back(std::make_pair("SUB_SYSTEM_LOGIN", AuthService()->SubSystemLoginSite()));
 | 
			
		||||
		Vars.push_back(std::make_pair("USER_SIGNATURE", AuthService()->UserSignature()));
 | 
			
		||||
		Vars.push_back(std::make_pair("SUB_SIGNATURE", AuthService()->SubSignature()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) {
 | 
			
		||||
        Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}", Request->clientAddress().toString(), Link.userId));
 | 
			
		||||
		Logger_.information(fmt::format("REQUEST-PASSWORD-RESET({}): For ID={}",
 | 
			
		||||
										Request->clientAddress().toString(), Link.userId));
 | 
			
		||||
		Poco::File FormFile{Daemon()->AssetDir() + "/password_reset.html"};
 | 
			
		||||
        Types::StringPairVec    FormVars{ {"UUID", Link.id},
 | 
			
		||||
		Types::StringPairVec FormVars{
 | 
			
		||||
			{"UUID", Link.id},
 | 
			
		||||
			{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
			
		||||
		AddGlobalVars(FormVars);
 | 
			
		||||
		SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
 | 
			
		||||
        Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}", Request->clientAddress().toString(), Link.userId));
 | 
			
		||||
        Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification.html"};
 | 
			
		||||
        Types::StringPairVec    FormVars{ {"UUID", Link.id},
 | 
			
		||||
		Logger_.information(fmt::format("REQUEST-SUB-SIGNUP({}): For ID={}",
 | 
			
		||||
										Request->clientAddress().toString(), Link.userId));
 | 
			
		||||
		Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification.html"};
 | 
			
		||||
		Types::StringPairVec FormVars{
 | 
			
		||||
			{"UUID", Link.id},
 | 
			
		||||
			{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
 | 
			
		||||
		AddGlobalVars(FormVars);
 | 
			
		||||
		SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -86,38 +120,55 @@ namespace OpenWifi {
 | 
			
		||||
				return DoReturnA404();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
            if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) {
 | 
			
		||||
			if (Password1 != Password2 || !AuthService()->ValidatePassword(Password2) ||
 | 
			
		||||
				!AuthService()->ValidatePassword(Password1)) {
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
 | 
			
		||||
				Types::StringPairVec FormVars{
 | 
			
		||||
					{"UUID", Id},
 | 
			
		||||
					{"ERROR_TEXT",
 | 
			
		||||
					 "For some reason, the passwords entered do not match or they do not comply "
 | 
			
		||||
					 "with"
 | 
			
		||||
					 " accepted password creation restrictions. Please consult our on-line help"
 | 
			
		||||
                                                                 " to look at the our password policy. If you would like to contact us, please mention"
 | 
			
		||||
                                                                 " id(" + Id + ")"}};
 | 
			
		||||
					 " to look at the our password policy. If you would like to contact us, please "
 | 
			
		||||
					 "mention"
 | 
			
		||||
					 " id(" +
 | 
			
		||||
						 Id + ")"}};
 | 
			
		||||
				AddGlobalVars(FormVars);
 | 
			
		||||
				return SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SecurityObjects::UserInfo UInfo;
 | 
			
		||||
 | 
			
		||||
            bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
			
		||||
			bool Found = Link.userAction
 | 
			
		||||
							 ? StorageService()->UserDB().GetUserById(Link.userId, UInfo)
 | 
			
		||||
							 : StorageService()->SubDB().GetUserById(Link.userId, UInfo);
 | 
			
		||||
			if (!Found) {
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
			
		||||
				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);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (UInfo.blackListed || UInfo.suspended) {
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
 | 
			
		||||
				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);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
            bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1,UInfo) : AuthService()->SetSubPassword(Password1,UInfo);
 | 
			
		||||
			bool GoodPassword = Link.userAction ? AuthService()->SetPassword(Password1, UInfo)
 | 
			
		||||
												: AuthService()->SetSubPassword(Password1, UInfo);
 | 
			
		||||
			if (!GoodPassword) {
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
			
		||||
				Types::StringPairVec FormVars{
 | 
			
		||||
					{"UUID", Id}, {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
			
		||||
				AddGlobalVars(FormVars);
 | 
			
		||||
				return SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -131,6 +182,7 @@ namespace OpenWifi {
 | 
			
		||||
			Types::StringPairVec FormVars{{"UUID", Id},
 | 
			
		||||
										  {"USERNAME", UInfo.email},
 | 
			
		||||
										  {"ACTION_LINK", MicroService::instance().GetUIURI()}};
 | 
			
		||||
			AddGlobalVars(FormVars);
 | 
			
		||||
			StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
			
		||||
			SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -159,36 +211,49 @@ namespace OpenWifi {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (Password1 != Password2 || !AuthService()->ValidateSubPassword(Password1)) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/sub_password_reset_error.html"};
 | 
			
		||||
				Types::StringPairVec FormVars{
 | 
			
		||||
					{"UUID", Id},
 | 
			
		||||
					{"ERROR_TEXT",
 | 
			
		||||
					 "For some reason, the passwords entered do not match or they do not comply "
 | 
			
		||||
					 "with"
 | 
			
		||||
					 " accepted password creation restrictions. Please consult our on-line help"
 | 
			
		||||
                                                                 " to look at the our password policy. If you would like to contact us, please mention"
 | 
			
		||||
                                                                 " id(" + Id + ")"}};
 | 
			
		||||
					 " to look at the our password policy. If you would like to contact us, please "
 | 
			
		||||
					 "mention"
 | 
			
		||||
					 " id(" +
 | 
			
		||||
						 Id + ")"}};
 | 
			
		||||
				AddGlobalVars(FormVars);
 | 
			
		||||
				return SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SecurityObjects::UserInfo UInfo;
 | 
			
		||||
			bool Found = StorageService()->SubDB().GetUserById(Link.userId, UInfo);
 | 
			
		||||
			if (!Found) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
 | 
			
		||||
				Types::StringPairVec FormVars{
 | 
			
		||||
					{"UUID", Id},
 | 
			
		||||
					{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact "
 | 
			
		||||
								   "your system administrator."}};
 | 
			
		||||
				AddGlobalVars(FormVars);
 | 
			
		||||
				return SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (UInfo.blackListed || UInfo.suspended) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
 | 
			
		||||
				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);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool GoodPassword = AuthService()->SetSubPassword(Password1, UInfo);
 | 
			
		||||
			if (!GoodPassword) {
 | 
			
		||||
                Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
 | 
			
		||||
                Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                                  {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
			
		||||
				Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_error.html"};
 | 
			
		||||
				Types::StringPairVec FormVars{
 | 
			
		||||
					{"UUID", Id}, {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
 | 
			
		||||
				AddGlobalVars(FormVars);
 | 
			
		||||
				return SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -200,31 +265,33 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
			StorageService()->SubDB().UpdateUserInfo(UInfo.email, Link.userId, UInfo);
 | 
			
		||||
 | 
			
		||||
            Poco::File  FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"};
 | 
			
		||||
            Types::StringPairVec    FormVars{ {"UUID", Id},
 | 
			
		||||
                                              {"USERNAME", UInfo.email} };
 | 
			
		||||
			Poco::File FormFile{Daemon()->AssetDir() + "/sub_signup_verification_success.html"};
 | 
			
		||||
			Types::StringPairVec FormVars{{"UUID", Id}, {"USERNAME", UInfo.email}};
 | 
			
		||||
			StorageService()->ActionLinksDB().CompleteAction(Id);
 | 
			
		||||
 | 
			
		||||
			//  Send the update to the provisioning service
 | 
			
		||||
			Poco::JSON::Object Body;
 | 
			
		||||
			auto RawSignup = Poco::StringTokenizer(UInfo.signingUp, ":");
 | 
			
		||||
			Body.set("signupUUID", RawSignup.count() == 1 ? UInfo.signingUp : RawSignup[1]);
 | 
			
		||||
            OpenAPIRequestPut   ProvRequest(uSERVICE_PROVISIONING,"/api/v1/signup",
 | 
			
		||||
                                            {
 | 
			
		||||
                                                {"signupUUID", RawSignup.count()==1 ? UInfo.signingUp : RawSignup[1]} ,
 | 
			
		||||
                                                {"operation", "emailVerified"}
 | 
			
		||||
                                            },
 | 
			
		||||
			OpenAPIRequestPut ProvRequest(
 | 
			
		||||
				uSERVICE_PROVISIONING, "/api/v1/signup",
 | 
			
		||||
				{{"signupUUID", RawSignup.count() == 1 ? UInfo.signingUp : RawSignup[1]},
 | 
			
		||||
				 {"operation", "emailVerified"}},
 | 
			
		||||
				Body, 30000);
 | 
			
		||||
            Logger().information(fmt::format("({}): Completed subscriber e-mail verification and password.",UInfo.email));
 | 
			
		||||
			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={}.",
 | 
			
		||||
			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));
 | 
			
		||||
			Logger().information(fmt::format(
 | 
			
		||||
				"({}): Completed subscriber e-mail verification. FORM notified.", UInfo.email));
 | 
			
		||||
		} else {
 | 
			
		||||
			DoReturnA404();
 | 
			
		||||
		}
 | 
			
		||||
@@ -239,16 +306,19 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SecurityObjects::UserInfo UInfo;
 | 
			
		||||
        bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId,UInfo) : StorageService()->SubDB().GetUserById(Link.userId,UInfo);
 | 
			
		||||
		bool Found = Link.userAction ? StorageService()->UserDB().GetUserById(Link.userId, UInfo)
 | 
			
		||||
									 : StorageService()->SubDB().GetUserById(Link.userId, UInfo);
 | 
			
		||||
		if (!Found) {
 | 
			
		||||
            Types::StringPairVec FormVars{{"UUID",       Link.id},
 | 
			
		||||
			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);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}", Request->clientAddress().toString(),
 | 
			
		||||
                                        UInfo.email));
 | 
			
		||||
		Logger_.information(fmt::format("EMAIL-VERIFICATION(%s): For ID={}",
 | 
			
		||||
										Request->clientAddress().toString(), UInfo.email));
 | 
			
		||||
		UInfo.waitingForEmailCheck = false;
 | 
			
		||||
		UInfo.validated = true;
 | 
			
		||||
		UInfo.lastEmailCheck = OpenWifi::Now();
 | 
			
		||||
@@ -262,6 +332,7 @@ namespace OpenWifi {
 | 
			
		||||
									  {"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);
 | 
			
		||||
	}
 | 
			
		||||
@@ -269,6 +340,7 @@ namespace OpenWifi {
 | 
			
		||||
	void RESTAPI_action_links::DoReturnA404() {
 | 
			
		||||
		Types::StringPairVec FormVars;
 | 
			
		||||
		Poco::File FormFile{Daemon()->AssetDir() + "/404_error.html"};
 | 
			
		||||
		AddGlobalVars(FormVars);
 | 
			
		||||
		SendHTMLFileBack(FormFile, FormVars);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -276,12 +348,10 @@ namespace OpenWifi {
 | 
			
		||||
		/// TODO:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::RequestSubResetPassword([[maybe_unused]] SecurityObjects::ActionLink &Link) {
 | 
			
		||||
	void RESTAPI_action_links::RequestSubResetPassword(
 | 
			
		||||
		[[maybe_unused]] SecurityObjects::ActionLink &Link) {}
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
	void RESTAPI_action_links::DoSubEmailVerification(
 | 
			
		||||
		[[maybe_unused]] SecurityObjects::ActionLink &Link) {}
 | 
			
		||||
 | 
			
		||||
    void RESTAPI_action_links::DoSubEmailVerification([[maybe_unused]] SecurityObjects::ActionLink &Link) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -4,22 +4,20 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_action_links : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_action_links(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							 RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							 bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
             std::vector<std::string>{
 | 
			
		||||
                                        Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                        Server,
 | 
			
		||||
                                        TransactionId,
 | 
			
		||||
                                        Internal,
 | 
			
		||||
                                        false,
 | 
			
		||||
                                        true, RateLimit{.Interval=1000,.MaxCalls=10}) {}
 | 
			
		||||
							 Server, TransactionId, Internal, false, true,
 | 
			
		||||
							 RateLimit{.Interval = 1000, .MaxCalls = 10}) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/actionLink"}; };
 | 
			
		||||
		void RequestResetPassword(SecurityObjects::ActionLink &Link);
 | 
			
		||||
		void RequestSubResetPassword(SecurityObjects::ActionLink &Link);
 | 
			
		||||
@@ -30,10 +28,11 @@ namespace OpenWifi {
 | 
			
		||||
		void DoReturnA404();
 | 
			
		||||
		void DoNewSubVerification(SecurityObjects::ActionLink &Link);
 | 
			
		||||
		void CompleteEmailInvitation();
 | 
			
		||||
		static void AddGlobalVars(Types::StringPairVec &Vars);
 | 
			
		||||
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // 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,9 +3,9 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_asset_server.h"
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
#include "Poco/File.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
#include "Daemon.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	void RESTAPI_asset_server::DoGet() {
 | 
			
		||||
@@ -22,4 +22,4 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
		SendFile(AssetFile);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,31 +4,29 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "../framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_asset_server : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							 RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							 bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                                 std::vector<std::string>
 | 
			
		||||
                                         {Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                          Server,
 | 
			
		||||
                                          TransactionId,
 | 
			
		||||
                                          Internal, false) {}
 | 
			
		||||
        static auto PathName() { return std::list<std::string>{"/wwwassets/{id}" ,
 | 
			
		||||
                                                                                         "/favicon.ico"}; };
 | 
			
		||||
							 Server, TransactionId, Internal, false) {}
 | 
			
		||||
		static auto PathName() {
 | 
			
		||||
			return std::list<std::string>{"/wwwassets/{id}", "/favicon.ico"};
 | 
			
		||||
		};
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final{};
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -5,19 +5,22 @@
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "Poco/CountingStream.h"
 | 
			
		||||
#include "Poco/Net/HTMLForm.h"
 | 
			
		||||
#include "RESTAPI_avatar_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "Poco/Net/HTMLForm.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void AvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
 | 
			
		||||
	void AvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header,
 | 
			
		||||
									   std::istream &Stream) {
 | 
			
		||||
		FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
			
		||||
		if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
			
		||||
			std::string Disposition;
 | 
			
		||||
			Poco::Net::NameValueCollection Parameters;
 | 
			
		||||
            Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
 | 
			
		||||
			Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION],
 | 
			
		||||
													  Disposition, Parameters);
 | 
			
		||||
			Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
			
		||||
		}
 | 
			
		||||
		Poco::CountingInputStream InputStream(Stream);
 | 
			
		||||
@@ -34,12 +37,14 @@ namespace OpenWifi {
 | 
			
		||||
		Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
 | 
			
		||||
		Poco::JSON::Object Answer;
 | 
			
		||||
 | 
			
		||||
        if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
 | 
			
		||||
		if (!partHandler.Name().empty() &&
 | 
			
		||||
			partHandler.Length() < MicroServiceConfigGetInt("openwifi.avatar.maxsize", 2000000)) {
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
 | 
			
		||||
            Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
 | 
			
		||||
            StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email,
 | 
			
		||||
                                 Id, SS.str(), partHandler.ContentType(), partHandler.Name());
 | 
			
		||||
			Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(),
 | 
			
		||||
											partHandler.ContentType()));
 | 
			
		||||
			StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, SS.str(),
 | 
			
		||||
												   partHandler.ContentType(), partHandler.Name());
 | 
			
		||||
			StorageService()->UserDB().SetAvatar(Id, "1");
 | 
			
		||||
			Logger().information(fmt::format("Adding avatar for {}", UserInfo_.userinfo.email));
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -57,10 +62,12 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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,
 | 
			
		||||
													Type, Name)) {
 | 
			
		||||
			return NotFound();
 | 
			
		||||
		}
 | 
			
		||||
        Logger().information(fmt::format("Retrieving avatar for {}, size:{}",UserInfo_.userinfo.email,AvatarContent.size()));
 | 
			
		||||
		Logger().information(fmt::format("Retrieving avatar for {}, size:{}",
 | 
			
		||||
										 UserInfo_.userinfo.email, AvatarContent.size()));
 | 
			
		||||
		return SendFileContent(AvatarContent, Type, Name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -79,4 +86,4 @@ namespace OpenWifi {
 | 
			
		||||
		StorageService()->UserDB().SetAvatar(Id, "");
 | 
			
		||||
		OK();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,15 @@
 | 
			
		||||
//
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "Poco/Net/PartHandler.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class AvatarPartHandler : public Poco::Net::PartHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
 | 
			
		||||
                Id_(std::move(Id)),
 | 
			
		||||
                Logger_(Logger),
 | 
			
		||||
                OutputStream_(ofs){
 | 
			
		||||
        }
 | 
			
		||||
		AvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
 | 
			
		||||
			: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
 | 
			
		||||
		void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
 | 
			
		||||
		[[nodiscard]] uint64_t Length() const { return Length_; }
 | 
			
		||||
		[[nodiscard]] std::string &Name() { return Name_; }
 | 
			
		||||
@@ -32,22 +30,20 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class RESTAPI_avatar_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							   bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                                 std::vector<std::string>{
 | 
			
		||||
                                         Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                         Server,
 | 
			
		||||
                                         TransactionId,
 | 
			
		||||
                                         Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/avatar/{id}"}; };
 | 
			
		||||
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final;
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,15 @@
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User, SecurityObjects::UserInfo & U) {
 | 
			
		||||
	inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
 | 
			
		||||
						 SecurityObjects::UserInfo &U) {
 | 
			
		||||
		U.currentPassword.clear();
 | 
			
		||||
		U.lastPasswords.clear();
 | 
			
		||||
		U.oauthType.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void Sanitize([[maybe_unused]] const SecurityObjects::UserInfoAndPolicy &User,
 | 
			
		||||
						 SecurityObjects::ApiKeyEntry &U) {
 | 
			
		||||
		U.salt.clear();
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -3,22 +3,15 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_email_handler.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "Poco/Exception.h"
 | 
			
		||||
#include "Poco/JSON/Parser.h"
 | 
			
		||||
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	void RESTAPI_email_handler::DoPost() {
 | 
			
		||||
		const auto &Obj = ParsedBody_;
 | 
			
		||||
        if (Obj->has("subject") &&
 | 
			
		||||
            Obj->has("from") &&
 | 
			
		||||
            Obj->has("text") &&
 | 
			
		||||
            Obj->has("recipients") &&
 | 
			
		||||
		if (Obj->has("subject") && Obj->has("from") && Obj->has("text") && Obj->has("recipients") &&
 | 
			
		||||
			Obj->isArray("recipients")) {
 | 
			
		||||
 | 
			
		||||
			Poco::JSON::Array::Ptr Recipients = Obj->getArray("recipients");
 | 
			
		||||
@@ -28,11 +21,11 @@ namespace OpenWifi {
 | 
			
		||||
			Attrs[SUBJECT] = Obj->get("subject").toString();
 | 
			
		||||
			Attrs[TEXT] = Obj->get("text").toString();
 | 
			
		||||
			Attrs[SENDER] = Obj->get("from").toString();
 | 
			
		||||
            if(SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs)) {
 | 
			
		||||
			if (SMTPMailerService()->SendMessage(Recipient, "password_reset.txt", Attrs, false)) {
 | 
			
		||||
				return OK();
 | 
			
		||||
			}
 | 
			
		||||
			return ReturnStatus(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
 | 
			
		||||
		}
 | 
			
		||||
		BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,22 +4,22 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_email_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_email_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							  bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                                  Server,
 | 
			
		||||
                                                  TransactionId,
 | 
			
		||||
                                                  Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/email"}; }
 | 
			
		||||
		void DoGet() final{};
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,12 @@
 | 
			
		||||
#include "Poco/JSON/Parser.h"
 | 
			
		||||
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "RESTAPI_oauth2_handler.h"
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "RESTAPI_db_helpers.h"
 | 
			
		||||
#include "RESTAPI_oauth2_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +26,8 @@ namespace OpenWifi {
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
 | 
			
		||||
		}
 | 
			
		||||
		if (GetBoolParameter(RESTAPI::Protocol::ME)) {
 | 
			
		||||
            Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
 | 
			
		||||
			Logger_.information(fmt::format("REQUEST-ME({}): Request for {}",
 | 
			
		||||
											Request->clientAddress().toString(),
 | 
			
		||||
											UserInfo_.userinfo.email));
 | 
			
		||||
			Poco::JSON::Object Me;
 | 
			
		||||
			SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
 | 
			
		||||
@@ -83,9 +84,11 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
 | 
			
		||||
            Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
			
		||||
			Logger_.information(
 | 
			
		||||
				fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
			
		||||
			Poco::JSON::Object Answer;
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->PasswordValidationExpression());
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::PASSWORDPATTERN,
 | 
			
		||||
					   AuthService()->PasswordValidationExpression());
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetAccessPolicy());
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetPasswordPolicy());
 | 
			
		||||
			return ReturnObject(Answer);
 | 
			
		||||
@@ -95,7 +98,8 @@ namespace OpenWifi {
 | 
			
		||||
			SecurityObjects::UserInfo UInfo1;
 | 
			
		||||
			auto UserExists = StorageService()->UserDB().GetUserByEmail(userId, UInfo1);
 | 
			
		||||
			if (UserExists) {
 | 
			
		||||
                Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
			
		||||
				Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
 | 
			
		||||
												Request->clientAddress().toString(), userId));
 | 
			
		||||
				SecurityObjects::ActionLink NewLink;
 | 
			
		||||
 | 
			
		||||
				NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
 | 
			
		||||
@@ -121,7 +125,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {}",
 | 
			
		||||
											Request->clientAddress().toString(), userId));
 | 
			
		||||
			if (Obj->has("uuid")) {
 | 
			
		||||
				auto uuid = Obj->get("uuid").toString();
 | 
			
		||||
				if (MFAServer()->ResendCode(uuid))
 | 
			
		||||
@@ -131,7 +136,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {}",
 | 
			
		||||
											Request->clientAddress().toString(), userId));
 | 
			
		||||
			if (Obj->has("uuid")) {
 | 
			
		||||
				SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
				if (MFAServer()->CompleteMFAChallenge(Obj, UInfo)) {
 | 
			
		||||
@@ -146,19 +152,19 @@ namespace OpenWifi {
 | 
			
		||||
		SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
		bool Expired = false;
 | 
			
		||||
		auto Code = AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
 | 
			
		||||
        if (Code==SUCCESS) {
 | 
			
		||||
		switch (Code) {
 | 
			
		||||
		case SUCCESS: {
 | 
			
		||||
			Poco::JSON::Object ReturnObj;
 | 
			
		||||
			if (AuthService()->RequiresMFA(UInfo)) {
 | 
			
		||||
				if (MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
			
		||||
					return ReturnObject(ReturnObj);
 | 
			
		||||
				}
 | 
			
		||||
                Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
			
		||||
				Logger_.warning(
 | 
			
		||||
					"MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
			
		||||
			}
 | 
			
		||||
			UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
			return ReturnObject(ReturnObj);
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            switch(Code) {
 | 
			
		||||
		}
 | 
			
		||||
		case INVALID_CREDENTIALS:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
			
		||||
		case PASSWORD_INVALID:
 | 
			
		||||
@@ -169,10 +175,10 @@ namespace OpenWifi {
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
 | 
			
		||||
		case PASSWORD_CHANGE_REQUIRED:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
 | 
			
		||||
		case ACCOUNT_SUSPENDED:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
 | 
			
		||||
		default:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
			
		||||
		}
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -7,26 +7,27 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_oauth2_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
	    RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							   bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
													  Server,
 | 
			
		||||
                                                      TransactionId,
 | 
			
		||||
													  Internal, false, true , RateLimit{.Interval=1000,.MaxCalls=10}) {}
 | 
			
		||||
        static auto PathName() { return std::list<std::string>{"/api/v1/oauth2/{token}","/api/v1/oauth2"}; };
 | 
			
		||||
							 Server, TransactionId, Internal, false, true,
 | 
			
		||||
							 RateLimit{.Interval = 1000, .MaxCalls = 10}) {}
 | 
			
		||||
		static auto PathName() {
 | 
			
		||||
			return std::list<std::string>{"/api/v1/oauth2/{token}", "/api/v1/oauth2"};
 | 
			
		||||
		};
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final;
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -33,4 +33,4 @@ namespace OpenWifi {
 | 
			
		||||
		ReturnObject(Answer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,24 +4,23 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_preferences : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_preferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                         std::vector<std::string>{
 | 
			
		||||
            Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
            Server,
 | 
			
		||||
            TransactionId,
 | 
			
		||||
            Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/preferences"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPut() final;
 | 
			
		||||
		void DoPost() final{};
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -2,87 +2,66 @@
 | 
			
		||||
// Created by stephane bourque on 2021-10-23.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI/RESTAPI_oauth2_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_user_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_users_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_action_links.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_apiKey_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_asset_server.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_avatar_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subavatar_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_email_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_sms_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_validate_token_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_oauth2_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_preferences.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subpreferences.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_signup_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_sms_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subavatar_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_submfa_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_suboauth2_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subpreferences.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subtotp_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subuser_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subusers_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_submfa_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_totp_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_subtotp_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_signup_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_user_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_users_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_validate_apikey.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_validate_token_handler.h"
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_systemSecret_handler.h"
 | 
			
		||||
#include "framework/RESTAPI_SystemCommand.h"
 | 
			
		||||
#include "framework/RESTAPI_WebSocketServer.h"
 | 
			
		||||
#include "framework/RESTAPI_SystemConfiguration.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
			
		||||
                                                            Poco::Logger & L, RESTAPI_GenericServer & S,
 | 
			
		||||
                                                            uint64_t TransactionId) {
 | 
			
		||||
	Poco::Net::HTTPRequestHandler *
 | 
			
		||||
	RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
			
		||||
					  Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
 | 
			
		||||
		return RESTAPI_Router<
 | 
			
		||||
            RESTAPI_oauth2_handler,
 | 
			
		||||
            RESTAPI_user_handler,
 | 
			
		||||
            RESTAPI_users_handler,
 | 
			
		||||
            RESTAPI_system_command,
 | 
			
		||||
            RESTAPI_asset_server,
 | 
			
		||||
            RESTAPI_system_endpoints_handler,
 | 
			
		||||
            RESTAPI_action_links,
 | 
			
		||||
            RESTAPI_avatar_handler,
 | 
			
		||||
            RESTAPI_subavatar_handler,
 | 
			
		||||
            RESTAPI_email_handler,
 | 
			
		||||
            RESTAPI_sms_handler,
 | 
			
		||||
            RESTAPI_preferences,
 | 
			
		||||
            RESTAPI_subpreferences,
 | 
			
		||||
            RESTAPI_suboauth2_handler,
 | 
			
		||||
            RESTAPI_subuser_handler,
 | 
			
		||||
            RESTAPI_subusers_handler,
 | 
			
		||||
            RESTAPI_submfa_handler,
 | 
			
		||||
            RESTAPI_totp_handler,
 | 
			
		||||
            RESTAPI_subtotp_handler,
 | 
			
		||||
            RESTAPI_signup_handler,
 | 
			
		||||
            RESTAPI_validate_sub_token_handler,
 | 
			
		||||
            RESTAPI_validate_token_handler
 | 
			
		||||
        >(Path, Bindings, L, S,TransactionId);
 | 
			
		||||
			RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
 | 
			
		||||
			RESTAPI_system_command, RESTAPI_system_configuration, RESTAPI_asset_server, RESTAPI_system_endpoints_handler,
 | 
			
		||||
			RESTAPI_action_links, RESTAPI_avatar_handler, RESTAPI_subavatar_handler,
 | 
			
		||||
			RESTAPI_email_handler, RESTAPI_sms_handler, RESTAPI_preferences, RESTAPI_subpreferences,
 | 
			
		||||
			RESTAPI_suboauth2_handler, RESTAPI_subuser_handler, RESTAPI_subusers_handler,
 | 
			
		||||
			RESTAPI_submfa_handler, RESTAPI_totp_handler, RESTAPI_subtotp_handler,
 | 
			
		||||
			RESTAPI_signup_handler, RESTAPI_validate_sub_token_handler,
 | 
			
		||||
			RESTAPI_validate_token_handler, RESTAPI_validate_apikey, RESTAPI_webSocketServer,
 | 
			
		||||
			RESTAPI_apiKey_handler, RESTAPI_systemSecret_handler>(Path, Bindings, L, S,
 | 
			
		||||
																  TransactionId);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
			
		||||
                                                            Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
 | 
			
		||||
	Poco::Net::HTTPRequestHandler *
 | 
			
		||||
	RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
 | 
			
		||||
					  Poco::Logger &L, RESTAPI_GenericServerAccounting &S, uint64_t TransactionId) {
 | 
			
		||||
 | 
			
		||||
		return RESTAPI_Router_I<
 | 
			
		||||
            RESTAPI_oauth2_handler,
 | 
			
		||||
            RESTAPI_user_handler,
 | 
			
		||||
            RESTAPI_users_handler,
 | 
			
		||||
            RESTAPI_system_command,
 | 
			
		||||
            RESTAPI_asset_server,
 | 
			
		||||
            RESTAPI_system_endpoints_handler,
 | 
			
		||||
            RESTAPI_action_links,
 | 
			
		||||
            RESTAPI_avatar_handler,
 | 
			
		||||
            RESTAPI_subavatar_handler,
 | 
			
		||||
            RESTAPI_email_handler,
 | 
			
		||||
            RESTAPI_sms_handler,
 | 
			
		||||
            RESTAPI_preferences,
 | 
			
		||||
            RESTAPI_subpreferences,
 | 
			
		||||
            RESTAPI_suboauth2_handler,
 | 
			
		||||
            RESTAPI_subuser_handler,
 | 
			
		||||
            RESTAPI_subusers_handler,
 | 
			
		||||
            RESTAPI_submfa_handler,
 | 
			
		||||
            RESTAPI_totp_handler,
 | 
			
		||||
            RESTAPI_subtotp_handler,
 | 
			
		||||
            RESTAPI_validate_sub_token_handler,
 | 
			
		||||
            RESTAPI_validate_token_handler,
 | 
			
		||||
            RESTAPI_signup_handler
 | 
			
		||||
        >(Path, Bindings, L, S, TransactionId);
 | 
			
		||||
    }
 | 
			
		||||
			RESTAPI_oauth2_handler, RESTAPI_user_handler, RESTAPI_users_handler,
 | 
			
		||||
			RESTAPI_system_command, RESTAPI_system_configuration, RESTAPI_asset_server, RESTAPI_system_endpoints_handler,
 | 
			
		||||
			RESTAPI_action_links, RESTAPI_avatar_handler, RESTAPI_subavatar_handler,
 | 
			
		||||
			RESTAPI_email_handler, RESTAPI_sms_handler, RESTAPI_preferences, RESTAPI_subpreferences,
 | 
			
		||||
			RESTAPI_suboauth2_handler, RESTAPI_subuser_handler, RESTAPI_subusers_handler,
 | 
			
		||||
			RESTAPI_submfa_handler, RESTAPI_totp_handler, RESTAPI_subtotp_handler,
 | 
			
		||||
			RESTAPI_validate_sub_token_handler, RESTAPI_validate_token_handler,
 | 
			
		||||
			RESTAPI_validate_apikey, RESTAPI_signup_handler, RESTAPI_systemSecret_handler>(
 | 
			
		||||
			Path, Bindings, L, S, TransactionId);
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -3,8 +3,9 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_signup_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
#define __DBG__ std::cout << __LINE__ << std::endl;
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
@@ -43,7 +44,7 @@ namespace OpenWifi {
 | 
			
		||||
		NewSub.name = UserName;
 | 
			
		||||
		NewSub.modified = OpenWifi::Now();
 | 
			
		||||
		NewSub.creationDate = OpenWifi::Now();
 | 
			
		||||
        NewSub.id = MicroService::instance().CreateUUID();
 | 
			
		||||
		NewSub.id = MicroServiceCreateUUID();
 | 
			
		||||
		NewSub.email = UserName;
 | 
			
		||||
		NewSub.userRole = SecurityObjects::SUBSCRIBER;
 | 
			
		||||
		NewSub.changePassword = true;
 | 
			
		||||
@@ -51,11 +52,12 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		StorageService()->SubDB().CreateRecord(NewSub);
 | 
			
		||||
 | 
			
		||||
        Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}", Request->clientAddress().toString(), UserName));
 | 
			
		||||
		Logger_.information(fmt::format("SIGNUP-PASSWORD({}): Request for {}",
 | 
			
		||||
										Request->clientAddress().toString(), UserName));
 | 
			
		||||
		SecurityObjects::ActionLink NewLink;
 | 
			
		||||
 | 
			
		||||
		NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
 | 
			
		||||
        NewLink.id = MicroService::CreateUUID();
 | 
			
		||||
		NewLink.id = MicroServiceCreateUUID();
 | 
			
		||||
		NewLink.userId = NewSub.id;
 | 
			
		||||
		NewLink.created = OpenWifi::Now();
 | 
			
		||||
		NewLink.expires = NewLink.created + (1 * 60 * 60); // 1 hour
 | 
			
		||||
@@ -71,4 +73,4 @@ namespace OpenWifi {
 | 
			
		||||
		// TODO
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,20 +4,19 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_signup_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							   bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                                 std::vector<std::string>{
 | 
			
		||||
                                         Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_PUT},
 | 
			
		||||
                                 Server,
 | 
			
		||||
                                 TransactionId,
 | 
			
		||||
                                 Internal, false, true ){}
 | 
			
		||||
							 Server, TransactionId, Internal, false, true) {}
 | 
			
		||||
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/signup"}; };
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +32,7 @@ namespace OpenWifi {
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoPut() final;
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
#include "RESTAPI_sms_handler.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -26,10 +25,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::string Code;
 | 
			
		||||
        if( HasParameter("completeValidation",Arg) &&
 | 
			
		||||
            Arg=="true" &&
 | 
			
		||||
            HasParameter("validationCode", Code) &&
 | 
			
		||||
            Obj->has("to")) {
 | 
			
		||||
		if (HasParameter("completeValidation", Arg) && Arg == "true" &&
 | 
			
		||||
			HasParameter("validationCode", Code) && Obj->has("to")) {
 | 
			
		||||
			auto Number = Obj->get("to").toString();
 | 
			
		||||
			if (SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
 | 
			
		||||
				return OK();
 | 
			
		||||
@@ -43,8 +40,7 @@ namespace OpenWifi {
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        if (Obj->has("to") &&
 | 
			
		||||
            Obj->has("text")) {
 | 
			
		||||
		if (Obj->has("to") && Obj->has("text")) {
 | 
			
		||||
 | 
			
		||||
			std::string PhoneNumber = Obj->get("to").toString();
 | 
			
		||||
			std::string Text = Obj->get("text").toString();
 | 
			
		||||
@@ -56,4 +52,4 @@ namespace OpenWifi {
 | 
			
		||||
		BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,22 +4,22 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_sms_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_sms_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                                  Server,
 | 
			
		||||
                                                  TransactionId,
 | 
			
		||||
                                                  Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/sms"}; }
 | 
			
		||||
		void DoGet() final{};
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -5,19 +5,22 @@
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "Poco/CountingStream.h"
 | 
			
		||||
#include "Poco/Net/HTMLForm.h"
 | 
			
		||||
#include "RESTAPI_subavatar_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "Poco/Net/HTMLForm.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
    void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream) {
 | 
			
		||||
	void SubAvatarPartHandler::handlePart(const Poco::Net::MessageHeader &Header,
 | 
			
		||||
										  std::istream &Stream) {
 | 
			
		||||
		FileType_ = Header.get(RESTAPI::Protocol::CONTENTTYPE, RESTAPI::Protocol::UNSPECIFIED);
 | 
			
		||||
		if (Header.has(RESTAPI::Protocol::CONTENTDISPOSITION)) {
 | 
			
		||||
			std::string Disposition;
 | 
			
		||||
			Poco::Net::NameValueCollection Parameters;
 | 
			
		||||
            Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION], Disposition, Parameters);
 | 
			
		||||
			Poco::Net::MessageHeader::splitParameters(Header[RESTAPI::Protocol::CONTENTDISPOSITION],
 | 
			
		||||
													  Disposition, Parameters);
 | 
			
		||||
			Name_ = Parameters.get(RESTAPI::Protocol::NAME, RESTAPI::Protocol::UNNAMED);
 | 
			
		||||
		}
 | 
			
		||||
		Poco::CountingInputStream InputStream(Stream);
 | 
			
		||||
@@ -34,12 +37,15 @@ namespace OpenWifi {
 | 
			
		||||
		Poco::Net::HTMLForm form(*Request, Request->stream(), partHandler);
 | 
			
		||||
		Poco::JSON::Object Answer;
 | 
			
		||||
 | 
			
		||||
        if (!partHandler.Name().empty() && partHandler.Length()< MicroService::instance().ConfigGetInt("openwifi.avatar.maxsize",2000000)) {
 | 
			
		||||
		if (!partHandler.Name().empty() &&
 | 
			
		||||
			partHandler.Length() < MicroServiceConfigGetInt("openwifi.avatar.maxsize", 2000000)) {
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::AVATARID, Id);
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::ERRORCODE, 0);
 | 
			
		||||
            Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(), partHandler.ContentType()));
 | 
			
		||||
            StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email,
 | 
			
		||||
                                 Id, SS.str(), partHandler.ContentType(), partHandler.Name());
 | 
			
		||||
			Logger_.information(fmt::format("Uploaded avatar: {} Type: {}", partHandler.Name(),
 | 
			
		||||
											partHandler.ContentType()));
 | 
			
		||||
			StorageService()->SubAvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, SS.str(),
 | 
			
		||||
													  partHandler.ContentType(),
 | 
			
		||||
													  partHandler.Name());
 | 
			
		||||
			StorageService()->SubDB().SetAvatar(Id, "1");
 | 
			
		||||
			Logger().information(fmt::format("Adding avatar for {}", UserInfo_.userinfo.email));
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -57,7 +63,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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,
 | 
			
		||||
													   Type, Name)) {
 | 
			
		||||
			return NotFound();
 | 
			
		||||
		}
 | 
			
		||||
		Logger().information(fmt::format("Retrieving avatar for {}", UserInfo_.userinfo.email));
 | 
			
		||||
@@ -78,4 +85,4 @@ namespace OpenWifi {
 | 
			
		||||
		StorageService()->SubDB().SetAvatar(Id, "");
 | 
			
		||||
		OK();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,15 @@
 | 
			
		||||
//
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "Poco/Net/PartHandler.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class SubAvatarPartHandler : public Poco::Net::PartHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream & ofs) :
 | 
			
		||||
                Id_(std::move(Id)),
 | 
			
		||||
                Logger_(Logger),
 | 
			
		||||
                OutputStream_(ofs){
 | 
			
		||||
        }
 | 
			
		||||
		SubAvatarPartHandler(std::string Id, Poco::Logger &Logger, std::stringstream &ofs)
 | 
			
		||||
			: Id_(std::move(Id)), Logger_(Logger), OutputStream_(ofs) {}
 | 
			
		||||
		void handlePart(const Poco::Net::MessageHeader &Header, std::istream &Stream);
 | 
			
		||||
		[[nodiscard]] uint64_t Length() const { return Length_; }
 | 
			
		||||
		[[nodiscard]] std::string &Name() { return Name_; }
 | 
			
		||||
@@ -32,22 +30,20 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
	class RESTAPI_subavatar_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_subavatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
								  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
								  bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                                 std::vector<std::string>{
 | 
			
		||||
                                         Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                         Server,
 | 
			
		||||
                                         TransactionId,
 | 
			
		||||
                                         Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/subavatar/{id}"}; };
 | 
			
		||||
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final;
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,9 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_submfa_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -48,7 +49,8 @@ namespace OpenWifi {
 | 
			
		||||
				SecurityObjects::UserInfo User;
 | 
			
		||||
				StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
			
		||||
				User.userTypeProprietaryInfo.mfa.enabled = false;
 | 
			
		||||
                StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
 | 
			
		||||
				StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
 | 
			
		||||
														 UserInfo_.userinfo.id, User);
 | 
			
		||||
 | 
			
		||||
				Poco::JSON::Object Answer;
 | 
			
		||||
				MFC.to_json(Answer);
 | 
			
		||||
@@ -59,12 +61,13 @@ namespace OpenWifi {
 | 
			
		||||
				StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
			
		||||
				User.userTypeProprietaryInfo.mfa.enabled = true;
 | 
			
		||||
				User.userTypeProprietaryInfo.mfa.method = "email";
 | 
			
		||||
                StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
 | 
			
		||||
				StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
 | 
			
		||||
														 UserInfo_.userinfo.id, User);
 | 
			
		||||
 | 
			
		||||
				MFC.sms = MFC.sms;
 | 
			
		||||
				MFC.type = "email";
 | 
			
		||||
				MFC.email = UserInfo_.userinfo.email;
 | 
			
		||||
                MFC.id = MicroService::instance().CreateUUID();
 | 
			
		||||
				MFC.id = MicroServiceCreateUUID();
 | 
			
		||||
 | 
			
		||||
				Poco::JSON::Object Answer;
 | 
			
		||||
				MFC.to_json(Answer);
 | 
			
		||||
@@ -98,7 +101,8 @@ namespace OpenWifi {
 | 
			
		||||
					if (MFC.sms.empty()) {
 | 
			
		||||
						return BadRequest(RESTAPI::Errors::SMSMissingPhoneNumber);
 | 
			
		||||
					}
 | 
			
		||||
                    if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) {
 | 
			
		||||
					if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode,
 | 
			
		||||
														UserInfo_.userinfo.email)) {
 | 
			
		||||
						SecurityObjects::UserInfo User;
 | 
			
		||||
 | 
			
		||||
						StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
 | 
			
		||||
@@ -111,12 +115,13 @@ namespace OpenWifi {
 | 
			
		||||
						User.userTypeProprietaryInfo.mobiles.clear();
 | 
			
		||||
						User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
 | 
			
		||||
 | 
			
		||||
                        StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
 | 
			
		||||
						StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,
 | 
			
		||||
																 UserInfo_.userinfo.id, User);
 | 
			
		||||
 | 
			
		||||
						MFC.sms = MFC.sms;
 | 
			
		||||
						MFC.type = "sms";
 | 
			
		||||
						MFC.email = UserInfo_.userinfo.email;
 | 
			
		||||
                        MFC.id = MicroService::instance().CreateUUID();
 | 
			
		||||
						MFC.id = MicroServiceCreateUUID();
 | 
			
		||||
 | 
			
		||||
						Poco::JSON::Object Answer;
 | 
			
		||||
						MFC.to_json(Answer);
 | 
			
		||||
@@ -134,4 +139,4 @@ namespace OpenWifi {
 | 
			
		||||
		return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -4,24 +4,24 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_submfa_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_submfa_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							   bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                                  Server,
 | 
			
		||||
                                                  TransactionId,
 | 
			
		||||
                                                  Internal, true, false , RateLimit{.Interval=1000,.MaxCalls=10},
 | 
			
		||||
                                                  true) {}
 | 
			
		||||
							 Server, TransactionId, Internal, true, false,
 | 
			
		||||
							 RateLimit{.Interval = 1000, .MaxCalls = 10}, true) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/submfa"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final{};
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final;
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,8 @@
 | 
			
		||||
#include "RESTAPI_suboauth2_handler.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -20,7 +19,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
		bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
 | 
			
		||||
		if (GetMe) {
 | 
			
		||||
            Logger_.information(fmt::format("REQUEST-ME({}): Request for {}", Request->clientAddress().toString(),
 | 
			
		||||
			Logger_.information(fmt::format("REQUEST-ME({}): Request for {}",
 | 
			
		||||
											Request->clientAddress().toString(),
 | 
			
		||||
											UserInfo_.userinfo.email));
 | 
			
		||||
			Poco::JSON::Object Me;
 | 
			
		||||
			SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
 | 
			
		||||
@@ -71,9 +71,11 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS)) {
 | 
			
		||||
            Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
			
		||||
			Logger_.information(
 | 
			
		||||
				fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
 | 
			
		||||
			Poco::JSON::Object Answer;
 | 
			
		||||
            Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression());
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::PASSWORDPATTERN,
 | 
			
		||||
					   AuthService()->SubPasswordValidationExpression());
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::ACCESSPOLICY, AuthService()->GetSubAccessPolicy());
 | 
			
		||||
			Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, AuthService()->GetSubPasswordPolicy());
 | 
			
		||||
			return ReturnObject(Answer);
 | 
			
		||||
@@ -83,11 +85,12 @@ namespace OpenWifi {
 | 
			
		||||
			SecurityObjects::UserInfo UInfo1;
 | 
			
		||||
			auto UserExists = StorageService()->SubDB().GetUserByEmail(userId, UInfo1);
 | 
			
		||||
			if (UserExists) {
 | 
			
		||||
                Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}", Request->clientAddress().toString(), userId));
 | 
			
		||||
				Logger_.information(fmt::format("FORGOTTEN-PASSWORD({}): Request for {}",
 | 
			
		||||
												Request->clientAddress().toString(), userId));
 | 
			
		||||
				SecurityObjects::ActionLink NewLink;
 | 
			
		||||
 | 
			
		||||
				NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
 | 
			
		||||
                NewLink.id = MicroService::CreateUUID();
 | 
			
		||||
				NewLink.id = MicroServiceCreateUUID();
 | 
			
		||||
				NewLink.userId = UInfo1.id;
 | 
			
		||||
				NewLink.created = OpenWifi::Now();
 | 
			
		||||
				NewLink.expires = NewLink.created + (24 * 60 * 60);
 | 
			
		||||
@@ -109,7 +112,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {}",
 | 
			
		||||
											Request->clientAddress().toString(), userId));
 | 
			
		||||
			if (Obj->has("uuid")) {
 | 
			
		||||
				auto uuid = Obj->get("uuid").toString();
 | 
			
		||||
				if (MFAServer()->ResendCode(uuid))
 | 
			
		||||
@@ -119,7 +123,8 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {}",
 | 
			
		||||
											Request->clientAddress().toString(), userId));
 | 
			
		||||
			if (Obj->has("uuid") && Obj->has("answer")) {
 | 
			
		||||
				SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
				if (MFAServer()->CompleteMFAChallenge(Obj, UInfo)) {
 | 
			
		||||
@@ -134,18 +139,19 @@ namespace OpenWifi {
 | 
			
		||||
		SecurityObjects::UserInfoAndPolicy UInfo;
 | 
			
		||||
		bool Expired = false;
 | 
			
		||||
		auto Code = AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
 | 
			
		||||
        if (Code==SUCCESS) {
 | 
			
		||||
		switch (Code) {
 | 
			
		||||
		case SUCCESS: {
 | 
			
		||||
			Poco::JSON::Object ReturnObj;
 | 
			
		||||
			if (AuthService()->RequiresMFA(UInfo)) {
 | 
			
		||||
				if (MFAServer()->StartMFAChallenge(UInfo, ReturnObj)) {
 | 
			
		||||
					return ReturnObject(ReturnObj);
 | 
			
		||||
				}
 | 
			
		||||
                Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
			
		||||
				Logger_.warning(
 | 
			
		||||
					"MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
 | 
			
		||||
			}
 | 
			
		||||
			UInfo.webtoken.to_json(ReturnObj);
 | 
			
		||||
			return ReturnObject(ReturnObj);
 | 
			
		||||
        } else {
 | 
			
		||||
            switch(Code) {
 | 
			
		||||
		}
 | 
			
		||||
		case INVALID_CREDENTIALS:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
			
		||||
		case PASSWORD_INVALID:
 | 
			
		||||
@@ -156,10 +162,10 @@ namespace OpenWifi {
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::USERNAME_PENDING_VERIFICATION);
 | 
			
		||||
		case PASSWORD_CHANGE_REQUIRED:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::PASSWORD_CHANGE_REQUIRED);
 | 
			
		||||
		case ACCOUNT_SUSPENDED:
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::ACCOUNT_SUSPENDED);
 | 
			
		||||
		default:
 | 
			
		||||
                    return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS); break;
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::INVALID_CREDENTIALS);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -3,25 +3,27 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_suboauth2_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
								  RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
								  bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                                                  Server,
 | 
			
		||||
                                                  TransactionId,
 | 
			
		||||
                                                  Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10},
 | 
			
		||||
                                                  false) {}
 | 
			
		||||
        static auto PathName() { return std::list<std::string>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; };
 | 
			
		||||
							 Server, TransactionId, Internal, false, false,
 | 
			
		||||
							 RateLimit{.Interval = 1000, .MaxCalls = 10}, false) {}
 | 
			
		||||
		static auto PathName() {
 | 
			
		||||
			return std::list<std::string>{"/api/v1/suboauth2/{token}", "/api/v1/suboauth2"};
 | 
			
		||||
		};
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final;
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -33,4 +33,4 @@ namespace OpenWifi {
 | 
			
		||||
		ReturnObject(Answer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,24 +4,23 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_subpreferences : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_subpreferences(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
							   RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
							   bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                         std::vector<std::string>{
 | 
			
		||||
            Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
            Server,
 | 
			
		||||
            TransactionId,
 | 
			
		||||
            Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/subpreferences"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPut() final;
 | 
			
		||||
		void DoPost() final{};
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#include "RESTAPI_subtotp_handler.h"
 | 
			
		||||
 | 
			
		||||
#include "TotpCache.h"
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -25,7 +26,8 @@ namespace OpenWifi {
 | 
			
		||||
		bool moreCodes = false;
 | 
			
		||||
 | 
			
		||||
		RESTAPI::Errors::msg Error;
 | 
			
		||||
        if(TotpCache()->ContinueValidation(UserInfo_.userinfo,true,Value,nextIndex,moreCodes, Error )) {
 | 
			
		||||
		if (TotpCache()->ContinueValidation(UserInfo_.userinfo, true, Value, nextIndex, moreCodes,
 | 
			
		||||
											Error)) {
 | 
			
		||||
			Poco::JSON::Object Answer;
 | 
			
		||||
			Answer.set("nextIndex", nextIndex);
 | 
			
		||||
			Answer.set("moreCodes", moreCodes);
 | 
			
		||||
@@ -34,4 +36,4 @@ namespace OpenWifi {
 | 
			
		||||
		return BadRequest(Error);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -2,28 +2,25 @@
 | 
			
		||||
// Created by stephane bourque on 2022-01-31.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_subtotp_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_subtotp_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
								RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
								bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                                 std::vector<std::string>
 | 
			
		||||
                                         {
 | 
			
		||||
                                                 Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
			
		||||
                                                 Poco::Net::HTTPRequest::HTTP_OPTIONS
 | 
			
		||||
                                         },
 | 
			
		||||
                                 Server,
 | 
			
		||||
                                 TransactionId,
 | 
			
		||||
                                 Internal) {}
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/subtotp"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final{};
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final;
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -3,15 +3,17 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_subuser_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "ACLProcessor.h"
 | 
			
		||||
#include "AuthService.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
			
		||||
#include "MFAServer.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
			
		||||
#include "SMSSender.h"
 | 
			
		||||
#include "SMTPMailerService.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "TotpCache.h"
 | 
			
		||||
#include "framework/ow_constants.h"
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroServiceFuncs.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -53,7 +55,8 @@ namespace OpenWifi {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        if(!Internal_ && !ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) {
 | 
			
		||||
		if (!Internal_ &&
 | 
			
		||||
			!ACLProcessor::Can(UserInfo_.userinfo, TargetUser, ACLProcessor::DELETE)) {
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +68,8 @@ namespace OpenWifi {
 | 
			
		||||
		StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
 | 
			
		||||
		StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
 | 
			
		||||
		StorageService()->SubAvatarDB().DeleteRecord("id", Id);
 | 
			
		||||
        Logger_.information(fmt::format("User '{}' deleted by '{}'.",Id,UserInfo_.userinfo.email));
 | 
			
		||||
		Logger_.information(
 | 
			
		||||
			fmt::format("User '{}' deleted by '{}'.", Id, UserInfo_.userinfo.email));
 | 
			
		||||
		OK();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -81,7 +85,8 @@ namespace OpenWifi {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) {
 | 
			
		||||
		if (NewUser.userRole == SecurityObjects::UNKNOWN ||
 | 
			
		||||
			NewUser.userRole != SecurityObjects::SUBSCRIBER) {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -122,7 +127,8 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		if (GetParameter("email_verification", "false") == "true") {
 | 
			
		||||
			if (AuthService::VerifySubEmail(NewUser))
 | 
			
		||||
                Logger_.information(fmt::format("Verification e-mail requested for {}",NewUser.email));
 | 
			
		||||
				Logger_.information(
 | 
			
		||||
					fmt::format("Verification e-mail requested for {}", NewUser.email));
 | 
			
		||||
			StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, NewUser.id, NewUser);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -135,7 +141,8 @@ namespace OpenWifi {
 | 
			
		||||
		Sanitize(UserInfo_, NewUser);
 | 
			
		||||
		NewUser.to_json(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() {
 | 
			
		||||
@@ -155,14 +162,15 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		if (GetBoolParameter("resetMFA")) {
 | 
			
		||||
			if ((UserInfo_.userinfo.userRole == SecurityObjects::ROOT) ||
 | 
			
		||||
                (UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole!=SecurityObjects::ROOT) ||
 | 
			
		||||
				(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN &&
 | 
			
		||||
				 Existing.userRole != SecurityObjects::ROOT) ||
 | 
			
		||||
				(UserInfo_.userinfo.id == Id)) {
 | 
			
		||||
				Existing.userTypeProprietaryInfo.mfa.enabled = false;
 | 
			
		||||
				Existing.userTypeProprietaryInfo.mfa.method.clear();
 | 
			
		||||
				Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
			
		||||
				Existing.modified = OpenWifi::Now();
 | 
			
		||||
                Existing.notes.push_back( SecurityObjects::NoteInfo{
 | 
			
		||||
                        .created=OpenWifi::Now(),
 | 
			
		||||
				Existing.notes.push_back(
 | 
			
		||||
					SecurityObjects::NoteInfo{.created = OpenWifi::Now(),
 | 
			
		||||
											  .createdBy = UserInfo_.userinfo.email,
 | 
			
		||||
											  .note = "MFA Reset by " + UserInfo_.userinfo.email});
 | 
			
		||||
				StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, Id, Existing);
 | 
			
		||||
@@ -179,11 +187,12 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		if (GetBoolParameter("forgotPassword")) {
 | 
			
		||||
			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;
 | 
			
		||||
			NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD;
 | 
			
		||||
            NewLink.id = MicroService::CreateUUID();
 | 
			
		||||
			NewLink.id = MicroServiceCreateUUID();
 | 
			
		||||
			NewLink.userId = Existing.id;
 | 
			
		||||
			NewLink.created = OpenWifi::Now();
 | 
			
		||||
			NewLink.expires = NewLink.created + (24 * 60 * 60);
 | 
			
		||||
@@ -201,8 +210,10 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		// some basic validations
 | 
			
		||||
		if (RawObject->has("userRole") &&
 | 
			
		||||
            (SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN ||
 | 
			
		||||
            SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) {
 | 
			
		||||
			(SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()) ==
 | 
			
		||||
				 SecurityObjects::UNKNOWN ||
 | 
			
		||||
			 SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()) ==
 | 
			
		||||
				 SecurityObjects::SUBSCRIBER)) {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::InvalidUserRole);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -217,9 +228,11 @@ namespace OpenWifi {
 | 
			
		||||
		AssignIfPresent(RawObject, "blackListed", Existing.blackListed);
 | 
			
		||||
 | 
			
		||||
		if (RawObject->has("userRole")) {
 | 
			
		||||
            auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
 | 
			
		||||
			auto NewRole =
 | 
			
		||||
				SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
 | 
			
		||||
			if (NewRole != Existing.userRole) {
 | 
			
		||||
                if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
 | 
			
		||||
				if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
 | 
			
		||||
					NewRole == SecurityObjects::ROOT) {
 | 
			
		||||
					return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
				}
 | 
			
		||||
				if (Id == UserInfo_.userinfo.id) {
 | 
			
		||||
@@ -231,9 +244,12 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		if (RawObject->has("notes")) {
 | 
			
		||||
			SecurityObjects::NoteInfoVec NIV;
 | 
			
		||||
            NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
 | 
			
		||||
			NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(
 | 
			
		||||
				RawObject->get("notes").toString());
 | 
			
		||||
			for (auto const &i : NIV) {
 | 
			
		||||
                SecurityObjects::NoteInfo   ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
 | 
			
		||||
				SecurityObjects::NoteInfo ii{.created = (uint64_t)OpenWifi::Now(),
 | 
			
		||||
											 .createdBy = UserInfo_.userinfo.email,
 | 
			
		||||
											 .note = i.note};
 | 
			
		||||
				Existing.notes.push_back(ii);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -241,14 +257,16 @@ namespace OpenWifi {
 | 
			
		||||
			if (!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
 | 
			
		||||
				return BadRequest(RESTAPI::Errors::InvalidPassword);
 | 
			
		||||
			}
 | 
			
		||||
            if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) {
 | 
			
		||||
			if (!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),
 | 
			
		||||
											Existing)) {
 | 
			
		||||
				return BadRequest(RESTAPI::Errors::PasswordRejected);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (GetParameter("email_verification", "false") == "true") {
 | 
			
		||||
			if (AuthService::VerifySubEmail(Existing))
 | 
			
		||||
                Logger_.information(fmt::format("Verification e-mail requested for {}",Existing.email));
 | 
			
		||||
				Logger_.information(
 | 
			
		||||
					fmt::format("Verification e-mail requested for {}", Existing.email));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (RawObject->has("userTypeProprietaryInfo")) {
 | 
			
		||||
@@ -269,23 +287,29 @@ namespace OpenWifi {
 | 
			
		||||
					return BadRequest(RESTAPI::Errors::EMailMFANotEnabled);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
                Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
 | 
			
		||||
				Existing.userTypeProprietaryInfo.mfa.method =
 | 
			
		||||
					NewUser.userTypeProprietaryInfo.mfa.method;
 | 
			
		||||
				Existing.userTypeProprietaryInfo.mfa.enabled = true;
 | 
			
		||||
 | 
			
		||||
				if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
 | 
			
		||||
					if (NewUser.userTypeProprietaryInfo.mobiles.empty()) {
 | 
			
		||||
						return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
			
		||||
					}
 | 
			
		||||
                    if (!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)) {
 | 
			
		||||
					if (!SMSSender()->IsNumberValid(
 | 
			
		||||
							NewUser.userTypeProprietaryInfo.mobiles[0].number,
 | 
			
		||||
							UserInfo_.userinfo.email)) {
 | 
			
		||||
						return BadRequest(RESTAPI::Errors::NeedMobileNumber);
 | 
			
		||||
					}
 | 
			
		||||
                    Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
 | 
			
		||||
					Existing.userTypeProprietaryInfo.mobiles =
 | 
			
		||||
						NewUser.userTypeProprietaryInfo.mobiles;
 | 
			
		||||
					Existing.userTypeProprietaryInfo.mobiles[0].verified = true;
 | 
			
		||||
					Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
 | 
			
		||||
                } else if (NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
 | 
			
		||||
				} else if (NewUser.userTypeProprietaryInfo.mfa.method ==
 | 
			
		||||
						   MFAMETHODS::AUTHENTICATOR) {
 | 
			
		||||
					std::string Secret;
 | 
			
		||||
					Existing.userTypeProprietaryInfo.mobiles.clear();
 | 
			
		||||
                    if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
 | 
			
		||||
					if (Existing.userTypeProprietaryInfo.authenticatorSecret.empty() &&
 | 
			
		||||
						TotpCache()->CompleteValidation(UserInfo_.userinfo, false, Secret)) {
 | 
			
		||||
						Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
 | 
			
		||||
					} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
 | 
			
		||||
						// we allow someone to use their old secret
 | 
			
		||||
@@ -313,4 +337,4 @@ namespace OpenWifi {
 | 
			
		||||
		}
 | 
			
		||||
		BadRequest(RESTAPI::Errors::RecordNotUpdated);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,28 +4,27 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_subuser_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
 | 
			
		||||
								RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
 | 
			
		||||
								bool Internal)
 | 
			
		||||
			: RESTAPIHandler(bindings, L,
 | 
			
		||||
                         std::vector<std::string>
 | 
			
		||||
                         {Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_PUT,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_DELETE,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                          Server,
 | 
			
		||||
                          TransactionId,
 | 
			
		||||
                          Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/subuser/{id}"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final;
 | 
			
		||||
		void DoDelete() final;
 | 
			
		||||
		void DoPut() final;
 | 
			
		||||
    private:
 | 
			
		||||
 | 
			
		||||
	  private:
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,8 @@
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "RESTAPI_subusers_handler.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "RESTAPI/RESTAPI_db_helpers.h"
 | 
			
		||||
#include "StorageService.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
@@ -18,17 +17,22 @@ namespace OpenWifi {
 | 
			
		||||
		std::string baseQuery;
 | 
			
		||||
		if (!nameSearch.empty() || !emailSearch.empty()) {
 | 
			
		||||
			if (!nameSearch.empty())
 | 
			
		||||
                baseQuery = fmt::format(" Lower(name) like('%{}%') ", Poco::toLower(nameSearch) );
 | 
			
		||||
				baseQuery = fmt::format(" Lower(name) like('%{}%') ",
 | 
			
		||||
										ORM::Escape(Poco::toLower(nameSearch)));
 | 
			
		||||
			if (!emailSearch.empty())
 | 
			
		||||
                baseQuery += baseQuery.empty() ? fmt::format(" Lower(email) like('%{}%') ", Poco::toLower(emailSearch))
 | 
			
		||||
                : fmt::format(" and Lower(email) like('%{}%') ", Poco::toLower(emailSearch));
 | 
			
		||||
				baseQuery += baseQuery.empty()
 | 
			
		||||
								 ? fmt::format(" Lower(email) like('%{}%') ",
 | 
			
		||||
											   ORM::Escape(Poco::toLower(emailSearch)))
 | 
			
		||||
								 : fmt::format(" and Lower(email) like('%{}%') ",
 | 
			
		||||
											   ORM::Escape(Poco::toLower(emailSearch)));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (QB_.CountOnly) {
 | 
			
		||||
			std::string whereClause;
 | 
			
		||||
            if(!operatorId.empty()) {
 | 
			
		||||
                whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) :
 | 
			
		||||
                              fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
 | 
			
		||||
			if (!operatorId.empty() && Utils::ValidUUID(operatorId)) {
 | 
			
		||||
				whereClause = baseQuery.empty()
 | 
			
		||||
								  ? fmt::format(" owner='{}' ", operatorId)
 | 
			
		||||
								  : fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
 | 
			
		||||
				auto count = StorageService()->SubDB().Count(whereClause);
 | 
			
		||||
				return ReturnCountOnly(count);
 | 
			
		||||
			}
 | 
			
		||||
@@ -36,13 +40,15 @@ namespace OpenWifi {
 | 
			
		||||
			return ReturnCountOnly(count);
 | 
			
		||||
		} else if (QB_.Select.empty()) {
 | 
			
		||||
			std::string whereClause;
 | 
			
		||||
            if(!operatorId.empty()) {
 | 
			
		||||
                whereClause = baseQuery.empty() ? fmt::format(" owner='{}' ", operatorId) :
 | 
			
		||||
                              fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
 | 
			
		||||
			if (!operatorId.empty() && Utils::ValidUUID(operatorId)) {
 | 
			
		||||
				whereClause = baseQuery.empty()
 | 
			
		||||
								  ? fmt::format(" owner='{}' ", operatorId)
 | 
			
		||||
								  : fmt::format(" owner='{}' and {} ", operatorId, baseQuery);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SecurityObjects::UserInfoList Users;
 | 
			
		||||
            if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users.users, whereClause)) {
 | 
			
		||||
			if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users.users,
 | 
			
		||||
												   whereClause)) {
 | 
			
		||||
				for (auto &i : Users.users) {
 | 
			
		||||
					Sanitize(UserInfo_, i);
 | 
			
		||||
				}
 | 
			
		||||
@@ -77,4 +83,4 @@ namespace OpenWifi {
 | 
			
		||||
			return ReturnObject(Answer);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
@@ -4,23 +4,22 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "framework/MicroService.h"
 | 
			
		||||
#include "framework/RESTAPI_Handler.h"
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi {
 | 
			
		||||
	class RESTAPI_subusers_handler : public RESTAPIHandler {
 | 
			
		||||
	  public:
 | 
			
		||||
        RESTAPI_subusers_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal)
 | 
			
		||||
		RESTAPI_subusers_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,
 | 
			
		||||
							 std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
 | 
			
		||||
													  Poco::Net::HTTPRequest::HTTP_OPTIONS},
 | 
			
		||||
                          Server,
 | 
			
		||||
                          TransactionId,
 | 
			
		||||
                          Internal) {}
 | 
			
		||||
							 Server, TransactionId, Internal) {}
 | 
			
		||||
		static auto PathName() { return std::list<std::string>{"/api/v1/subusers"}; };
 | 
			
		||||
		void DoGet() final;
 | 
			
		||||
		void DoPost() final{};
 | 
			
		||||
		void DoDelete() final{};
 | 
			
		||||
		void DoPut() final{};
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
}; // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||