Compare commits

...

288 Commits

Author SHA1 Message Date
Dmitry Dunaev
96b712eba1 Merge pull request #48 from Telecominfraproject/fix/wifi-9174--dep-charts-2.5
[WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
2022-06-03 19:32:54 +03:00
Dmitry Dunaev
8b45bfd812 [WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-06-03 19:32:28 +03:00
TIP Automation User
e0a57a4846 Chg: update image tag in helm values to v2.5.0 2022-03-30 13:48:18 +00:00
TIP Automation User
a72e286a83 Chg: update image tag in helm values to v2.5.0-RC1 2022-02-11 16:02:40 +00:00
stephb9959
2fb80c68dd Merge remote-tracking branch 'origin/main' 2022-02-08 22:13:58 -08:00
stephb9959
0652c13139 Framework Update 2022-02-08 22:13:50 -08:00
Johann Hoffmann
feb5ff1f2c [WIFI-6729] Speed up Docker image build time (#38)
* Re-structure Dockerfile and use docker-image-build composite action

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Fix aws-sdk-cpp repo url

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Fix package list syntax error

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Add curl to build-base

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Install curl-dev instead of curl in build image

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Cut build lib copying

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Remove branch since PR was merged in composite actions repo

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-02-08 15:02:31 +01:00
stephb9959
5a9a62ff7e Framework Update 2022-02-04 11:45:35 -08:00
stephb9959
bd331913e1 Framework Update 2022-02-04 09:55:59 -08:00
stephb9959
5756e31ae6 Framework Update 2022-02-04 09:53:51 -08:00
stephb9959
884b91af63 Adding Authenticator doc. 2022-02-02 10:41:00 -08:00
stephb9959
fed43efadf Adding Authenticator doc. 2022-02-02 10:31:01 -08:00
stephb9959
48d3e56b79 Adding Authenticator doc. 2022-02-02 10:29:58 -08:00
stephb9959
a0f9abea88 Adding Authenticator doc. 2022-02-02 10:03:20 -08:00
stephb9959
3e0ecda9d6 Adding Authenticator doc. 2022-02-02 09:29:58 -08:00
stephb9959
ad38d8e84c Adding Authenticator doc. 2022-02-02 09:06:59 -08:00
stephb9959
27c581750c Adding Authenticator doc. 2022-02-02 09:06:05 -08:00
stephb9959
e09ee35940 Adding Authenticator doc. 2022-02-02 09:03:15 -08:00
stephb9959
3c4d9612d3 Adding Authenticator doc. 2022-02-02 09:02:38 -08:00
stephb9959
6485b2426c Adding Authenticator doc. 2022-02-02 08:39:49 -08:00
stephb9959
3d3dbc6b4d Adding Authenticator doc. 2022-02-02 08:09:33 -08:00
stephb9959
8965b3c590 Adding Authenticator doc. 2022-02-02 08:07:47 -08:00
stephb9959
77941c4775 Adding Authenticator doc. 2022-02-02 08:05:18 -08:00
stephb9959
ef9cd80df6 Adding Authenticator doc. 2022-02-02 07:58:00 -08:00
stephb9959
042f7619ec Adding Authenticator doc. 2022-02-02 07:40:39 -08:00
stephb9959
8a371d7eaf Adding Authenticator doc. 2022-02-01 21:35:15 -08:00
stephb9959
ac92c7da85 Adding Authenticator doc. 2022-02-01 21:34:44 -08:00
stephb9959
7a8449efbf Adding Authenticator doc. 2022-02-01 21:33:35 -08:00
stephb9959
8365aa5463 Adding Authenticator doc. 2022-02-01 21:31:08 -08:00
stephb9959
1c4f961971 Adding Authenticator doc. 2022-01-31 15:43:47 -08:00
stephb9959
19c92edfcc Adding missing config parameter. 2022-01-31 15:25:16 -08:00
stephb9959
3fd6e6b849 Framework update. 2022-01-31 15:24:01 -08:00
stephb9959
bc6d8a8a79 Framework update. 2022-01-31 14:24:29 -08:00
stephb9959
29da9b4b8e Fixing Google Authenticator 2022-01-31 14:14:33 -08:00
stephb9959
b3f1f35bb4 Adding Google Authenticator 2022-01-31 13:56:30 -08:00
stephb9959
a9bd44b3b2 Adding Google Authenticator 2022-01-31 13:56:01 -08:00
stephb9959
01f457dd0c Adding Google Authenticator 2022-01-31 09:23:49 -08:00
stephb9959
f27f036e62 Merge remote-tracking branch 'origin/main' 2022-01-31 09:01:19 -08:00
stephb9959
27f8d06cab Framework update. 2022-01-31 09:01:11 -08:00
Dmitry Dunaev
7960cda46e Merge pull request #37 from Telecominfraproject/feature/wifi-6837--chart-improvements
[WIFI-6837] Chg: modify readiness to make some envs optional, switch default helm service type to ClusterIP
2022-01-28 16:04:54 +03:00
Dmitry Dunaev
9907f91c49 [WIFI-6837] Chg: modify readiness to make some envs optional, switch default helm service type to ClusterIP
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-01-28 13:52:47 +03:00
stephb9959
b3b98d90ca Framework update. 2022-01-27 10:00:38 -08:00
stephb9959
ef947c3e33 Framework update. 2022-01-26 23:16:38 -08:00
stephb9959
a5eb0d792b Framework update. 2022-01-26 23:11:53 -08:00
stephb9959
151585f6e5 Adding kafka logging in framework. 2022-01-26 22:35:28 -08:00
stephb9959
7fc7daf595 Adding kafka logging in framework. 2022-01-26 22:33:31 -08:00
stephb9959
ebe2df4dc7 Adding kafka logging in framework. 2022-01-23 22:52:03 -08:00
stephb9959
9dcc19f4fe Adding kafka logging in framework. 2022-01-23 10:26:26 -08:00
stephb9959
984ba88341 Adding kafka logging in framework. 2022-01-20 22:56:13 -08:00
stephb9959
b14eba63c3 Removing owner constraint on subscriber. 2022-01-18 09:00:52 -08:00
stephb9959
b8c02906ea Merge remote-tracking branch 'origin/main' 2022-01-18 08:56:04 -08:00
stephb9959
f3c3539f62 Removing owner constraint on subscriber. 2022-01-18 08:55:56 -08:00
Johann Hoffmann
5fef83d726 Remove ref since PR was merged
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-01-17 17:42:38 +01:00
Stephane Bourque
874e28ffff Merge pull request #34 from Telecominfraproject/WIFI-5775-test-sdk-on-pr
[WIFI-5775] Run SDK tests on a PR level
2022-01-17 08:41:32 -08:00
Johann Hoffmann
f84b8c4b5c Revert "Adapt logging configuration to newest changes"
This reverts commit 04cffd13c8.

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-01-17 14:26:16 +01:00
Johann Hoffmann
ae6a986e57 Adapt logging configuration to newest changes
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-01-17 11:52:11 +01:00
Johann Hoffmann
04cffd13c8 Adapt logging configuration to newest changes
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-01-15 14:18:23 +01:00
Johann Hoffmann
28635dcbdd Pass versions as one JSON string
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-01-13 12:07:22 +01:00
Dmitry Dunaev
6a67bf80af Merge pull request #35 from Telecominfraproject/feature/wifi-6393--add-wait-kafka-initcontainer
[WIFI-6393] Add: initContainer to wait for Kafka to be ready
2022-01-13 12:18:05 +03:00
Dmitry Dunaev
9460cc1e5b [WIFI-6393] Add: initContainer to wait for Kafka to be ready
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-01-12 11:23:40 +03:00
stephb9959
6d20c8408f Framework update + added modified to userrecord. 2022-01-11 23:17:49 -08:00
Johann Hoffmann
fd21917a93 Trigger testing with Docker Compose deployment
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Switch to trigger-workflow-and-wait community Github action

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Switch to latest version

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Test base branch versions of microservices on PR events

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Fix input and env variable names

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Set and debug base branch name

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Try setting base branch name as an output and increase wait_interval

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Try context syntax for accessing env variables

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Replace base branch name for OWGW and further increase wait_interval

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Fix set-output statements

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Try setting env variable since wait_interval action input does not work

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Switch back to repository dispatch community action

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Fix client_payload variable names

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Test trigger-workflow-and-wait composite action

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Fix duplicate statement

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Add path to repo checkout

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Add ref input

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-01-11 16:48:04 +01:00
stephb9959
c47e9bc98d Framework update + added modified to userrecord. 2022-01-10 23:40:45 -08:00
stephb9959
30431ab954 Framework update + added modified to userrecord. 2022-01-10 22:39:46 -08:00
stephb9959
76175d8bbb Framework update 2022-01-10 14:14:07 -08:00
stephb9959
36e16e3c8e Framework update 2022-01-10 12:26:37 -08:00
stephb9959
cc4e5848a5 Add 2022-01-10 09:04:29 -08:00
stephb9959
8425950da7 Adding additional security for SMS: only root, partner, admin are allowed to send SMS. 2022-01-10 07:57:17 -08:00
stephb9959
cf903a57ab Adding additional security for SMS: only root, partner, admin are allowed to send SMS. 2022-01-10 07:11:13 -08:00
stephb9959
d38e4ca2fc Logging and framework update 2022-01-09 22:35:50 -08:00
stephb9959
584254cb07 Framework update 2022-01-09 10:04:19 -08:00
stephb9959
dcf7ff5f48 Framework update 2022-01-08 22:18:33 -08:00
stephb9959
1039a53925 ORM update 2022-01-06 09:26:37 -08:00
stephb9959
a80bcd16d8 adding logout/login recording. 2022-01-05 23:34:13 -08:00
stephb9959
fce18f6238 Merge remote-tracking branch 'origin/main' 2022-01-05 22:16:32 -08:00
stephb9959
f8c6dad974 Fixing typo in UserInfo struct 2022-01-05 22:16:25 -08:00
Dmitry Dunaev
eec8662a3c Merge pull request #32 from Telecominfraproject/feature/wifi-6183--cli-review
[WIFI-6183] Chg: cli review and usage enhancement
2022-01-04 14:46:42 +03:00
Dmitry Dunaev
f26c6e1454 [WIFI-6183] Chg: cli review and usage enhancement
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-01-04 13:03:20 +03:00
stephb9959
08a50db13c Adding avatars and preferences for subs. 2022-01-03 11:49:58 -08:00
stephb9959
7b741048ff Updating framework & removing debug prints 2022-01-02 23:07:29 -08:00
stephb9959
7fcd451e3b Adding creation right ans support for owner field in user. 2022-01-02 22:59:50 -08:00
stephb9959
c545be6ae9 Adding creation right ans support for owner field in user. 2022-01-02 22:57:17 -08:00
stephb9959
b1f489bf4f Adding creation right ans support for owner field in user. 2022-01-02 22:53:09 -08:00
stephb9959
92910fe0c5 Adding creation right ans support for owner field in user. 2022-01-02 22:47:46 -08:00
stephb9959
eda30b3dc3 Adding creation right ans support for owner field in user. 2022-01-01 23:01:02 -08:00
stephb9959
51dd7bdfa7 Adding creation right ans support for owner field in user. 2022-01-01 22:47:06 -08:00
stephb9959
2eccf1ef06 Adding DB Cache 2021-12-31 23:30:30 -08:00
stephb9959
b37edca02c Adding DB Cache 2021-12-31 23:13:09 -08:00
stephb9959
e831619673 Adding DB Cache 2021-12-31 22:56:23 -08:00
stephb9959
78ae79b1d5 Adding DB Cache 2021-12-31 22:41:12 -08:00
stephb9959
2bc6d7c325 Adding DB Cache 2021-12-31 22:27:23 -08:00
stephb9959
0f6a95a330 Adding DB Cache 2021-12-31 22:19:46 -08:00
stephb9959
83a1d80d77 Adding DB Cache 2021-12-31 22:11:46 -08:00
stephb9959
84bcb28328 Fixing Avatar access rights. 2021-12-31 07:24:38 -08:00
stephb9959
4d03faf523 Framework update 2021-12-28 22:20:32 -08:00
stephb9959
73096153b4 Framework update 2021-12-28 11:30:32 -08:00
stephb9959
1cf9894f7d Framework update 2021-12-28 11:14:58 -08:00
stephb9959
f54cd95fc4 Framework update 2021-12-28 11:08:47 -08:00
stephb9959
882226ccdb Framework update 2021-12-28 10:54:28 -08:00
stephb9959
e5f10ccd17 Moving Avatars into ORM 2021-12-28 08:18:44 -08:00
stephb9959
c500ae36b1 Moving Avatars into ORM 2021-12-28 08:06:20 -08:00
stephb9959
6ead810ec6 Moving Avatars into ORM 2021-12-28 08:03:05 -08:00
stephb9959
c6ac384cdb Moving Avatars into ORM 2021-12-28 00:17:08 -08:00
stephb9959
f28e07a615 Moving Avatars into ORM 2021-12-28 00:14:36 -08:00
stephb9959
c7c5401bc2 Moving Avatars into ORM 2021-12-28 00:12:08 -08:00
stephb9959
6264c7f3bb Moving Avatars into ORM 2021-12-27 23:57:05 -08:00
stephb9959
c078bdb555 Moving Avatars into ORM 2021-12-27 23:50:38 -08:00
stephb9959
81131b8038 Moving Avatars into ORM 2021-12-27 23:38:58 -08:00
stephb9959
4633db416d Moving Avatars into ORM 2021-12-27 23:33:19 -08:00
stephb9959
6c14337333 Moving Avatars into ORM 2021-12-27 23:30:03 -08:00
stephb9959
784fc3256b Moving Avatars into ORM 2021-12-27 23:19:14 -08:00
stephb9959
2c513d8374 Moving ActionLinks into ORM 2021-12-27 22:24:15 -08:00
stephb9959
d202b9e365 Moving preferences into ORM. 2021-12-27 21:38:21 -08:00
stephb9959
b869da3b09 Refactor users/tokens into orm. 2021-12-27 20:45:17 -08:00
stephb9959
f31195e854 Refactor users/tokens into orm. 2021-12-27 20:43:45 -08:00
stephb9959
ec4ab520d8 Refactor users/tokens into orm. 2021-12-27 20:39:49 -08:00
stephb9959
a9ade83094 Refactor users/tokens into orm. 2021-12-27 16:03:11 -08:00
stephb9959
977742d802 Refactor users/tokens into orm. 2021-12-27 15:51:11 -08:00
stephb9959
b69b90b243 Merge remote-tracking branch 'origin/main' 2021-12-23 07:04:39 -08:00
stephb9959
ec0aa4e15a Fixes for cache issues. 2021-12-23 07:04:31 -08:00
Dmitry Dunaev
5fc313aa50 Merge pull request #31 from Telecominfraproject/feature/wifi-4977--introduce-revisionHistoryLimit
[WIFI-4977] Add: helm add revisionHistoryLimit support
2021-12-23 16:27:43 +03:00
Dmitry Dunaev
a3975829e4 [WIFI-4977] Add: helm add revisionHistoryLimit support
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2021-12-23 16:16:18 +03:00
stephb9959
e8cf7a6f21 Fixes for cache issues. 2021-12-22 21:54:03 -08:00
stephb9959
d27441d793 Fixes for cache issues. 2021-12-22 20:02:37 -08:00
stephb9959
ae5c32a8ec Fixes for subscriber service. 2021-12-22 09:12:15 -08:00
stephb9959
96c684fe5e Fixes for subscriber service. 2021-12-17 08:36:31 -08:00
stephb9959
8609990551 Merge remote-tracking branch 'origin/main' 2021-12-17 08:34:36 -08:00
stephb9959
4566bb942c Fixes for subscriber service. 2021-12-17 08:34:28 -08:00
Johann Hoffmann
e5d6f42433 [WIFI-6170] Add OpenWifi Docker Compose deployment with PostgreSQL (#30)
* Add wait-for-postgres.sh wrapper script

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Copy wait-for-postgres.sh into Docker image

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2021-12-16 17:20:10 +01:00
stephb9959
524f79e825 Fixes for subscriber service. 2021-12-14 14:23:24 -08:00
stephb9959
be46b46340 Fix for subscriber authentication tokens. 2021-12-13 19:23:52 -08:00
stephb9959
5ff0841112 Fix for subscriber authentication tokens. 2021-12-13 15:43:10 -08:00
stephb9959
a6c115adb5 Fix for subscriber authentication tokens. 2021-12-13 15:20:28 -08:00
stephb9959
4d474fe92c Fix for subscriber authentication tokens. 2021-12-13 14:14:23 -08:00
stephb9959
4b46e0c9c9 Fix for subscriber authentication tokens. 2021-12-13 14:05:26 -08:00
stephb9959
de0ddc769b Fix for subscriber authentication tokens. 2021-12-13 13:46:50 -08:00
stephb9959
4a11602fb9 Fix for subscriber authentication tokens. 2021-12-13 13:43:45 -08:00
stephb9959
ef1f7098a6 Fix for subscriber authentication tokens. 2021-12-13 13:31:18 -08:00
stephb9959
38eebe6162 Fix for subscriber authentication tokens. 2021-12-13 12:39:33 -08:00
stephb9959
5124ed016c Framweork update 2021-12-11 23:33:43 -08:00
stephb9959
fb632b6ce1 Fixing submfa method 2021-12-11 23:07:42 -08:00
stephb9959
775d0c0a65 Fixing submfa method 2021-12-10 13:04:01 -08:00
stephb9959
fb2ddaa136 Fixing submfa method 2021-12-10 13:01:07 -08:00
stephb9959
f51e00c50c Fixing submfa method 2021-12-08 23:33:15 -08:00
stephb9959
da49bebb15 Fixing submfa method 2021-12-08 23:11:18 -08:00
stephb9959
916d5cdf13 Fixing submfa method 2021-12-08 22:41:24 -08:00
stephb9959
5eecfbfd30 Fixing submfa method 2021-12-08 17:06:39 -08:00
stephb9959
32a5c81f1d Fixing submfa method 2021-12-08 15:53:52 -08:00
stephb9959
a72189f854 Fixing submfa method 2021-12-08 15:51:09 -08:00
stephb9959
2be40d5d17 Fixing submfa method 2021-12-08 15:47:43 -08:00
stephb9959
f8407f7b7c Fixing submfa method 2021-12-08 14:43:31 -08:00
stephb9959
2ec792a74b Framework update 2021-12-07 20:37:26 -08:00
stephb9959
72f0b11f81 Wrong dir for .git 2021-12-07 09:29:13 -08:00
stephb9959
00965b78c7 Adding git hash 2021-12-07 08:52:42 -08:00
stephb9959
b2c06affa8 Adding git hash 2021-12-07 08:42:16 -08:00
Dmitry Dunaev
7b467850b6 Add: .git dir to build image to expose git hash for version
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2021-12-07 15:48:01 +03:00
stephb9959
be89574363 Merge remote-tracking branch 'origin/main' 2021-12-06 07:53:58 -08:00
stephb9959
e4d3855251 Adding git hash 2021-12-06 07:53:50 -08:00
Dmitry Dunaev
57bd712634 [WIFI-5840] Chg: failureThreshold for readiness_check up to 3
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2021-12-06 15:20:10 +03:00
stephb9959
797f4e9c80 Allow + sign in e-mail addresses. 2021-12-05 12:03:31 -08:00
stephb9959
309a856cd0 Allow + sign in e-mail addresses. 2021-12-05 10:02:59 -08:00
stephb9959
937a20beea Allow + sign in e-mail addresses. 2021-12-02 14:41:16 -08:00
stephb9959
2217a428c1 Completing sub mfa support. 2021-12-01 22:12:28 -08:00
stephb9959
ec82bdec24 Completing sub support. 2021-12-01 09:04:51 -08:00
stephb9959
40faa84d2b Delete Sub bug. 2021-12-01 07:44:34 -08:00
stephb9959
cb3efcecb5 Additional verification for internal API calls. 2021-11-30 20:44:59 -08:00
stephb9959
e11d955529 Additional verification for internal API calls. 2021-11-30 16:32:59 -08:00
stephb9959
5a4eafee7d User role validation on Subscribers. 2021-11-30 14:11:14 -08:00
stephb9959
2df45c26a4 User role validation on Subscribers. 2021-11-30 14:01:28 -08:00
stephb9959
311786f8d8 User role validation on Subscribers. 2021-11-30 10:23:23 -08:00
stephb9959
829de62967 Merge remote-tracking branch 'origin/main' 2021-11-30 10:07:18 -08:00
stephb9959
55d1f9571d Adding Subscriber DB Support. 2021-11-30 10:07:08 -08:00
Dmitry Dunaev
80a520c4cc [WIFI-4860] Chg: apply enforce-jira-issue-key only to PRs to release branches 2021-11-19 16:23:48 +03:00
Dmitry Dunaev
040623fc8c Merge pull request #27 from Telecominfraproject/feature/wifi-4860--add-ensure-jira-issue-key-workflow
[WIFI-4860] Add: enforce-jira-issue-key workflow
2021-11-19 15:50:08 +03:00
Dmitry Dunaev
dc6eaaeb89 [WIFI-4860] Add: enforce-jira-issue-key workflow
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2021-11-19 13:18:05 +03:00
Johann Hoffmann
4953aa02dc Add new config properties to templating mechanism
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2021-11-18 11:32:18 +01:00
stephb9959
e794647469 Fixing DB offset/limit computation. 2021-11-17 15:53:38 -08:00
stephb9959
e87bdc9440 Adding preferences. 2021-11-16 22:06:40 -08:00
stephb9959
a8f59e0fb5 Adding preferences. 2021-11-16 19:53:48 -08:00
stephb9959
2730a8c5e4 Adding preferences. 2021-11-16 19:48:16 -08:00
stephb9959
b3ef448628 Adding preferences. 2021-11-16 19:44:03 -08:00
stephb9959
13fe7d295b Adding preferences. 2021-11-16 19:41:53 -08:00
stephb9959
ef1eb190a2 Adding preferences. 2021-11-16 19:39:24 -08:00
stephb9959
370d4aca47 Adding preferences. 2021-11-16 19:03:18 -08:00
stephb9959
a575d95b91 Adding preferences. 2021-11-16 17:52:39 -08:00
stephb9959
0477ab5349 Adding preferences. 2021-11-16 15:57:57 -08:00
stephb9959
730f8d169a Adding preferences. 2021-11-16 15:42:57 -08:00
stephb9959
be7f50ccbb Adding preferences. 2021-11-16 15:38:35 -08:00
stephb9959
8d681988a9 Merge remote-tracking branch 'origin/main' 2021-11-16 15:25:26 -08:00
stephb9959
8842f23a8e Adding preferences. 2021-11-16 15:25:14 -08:00
Dmitry Dunaev
5e5150a73f Add: mailer and smssender properties in helm values 2021-11-16 16:52:39 +03:00
stephb9959
9e79b73e20 Adding proper default for mailer and sms. 2021-11-15 15:04:48 -08:00
stephb9959
eb4dfc25f2 Adding proper default for mailer and sms. 2021-11-15 14:54:23 -08:00
stephb9959
bedec254c5 Mail refactoring. 2021-11-15 14:38:56 -08:00
stephb9959
96a566a2b5 Sendmail crash fix. 2021-11-15 13:46:44 -08:00
stephb9959
ad2eb1711e ACL Fix. 2021-11-15 13:34:54 -08:00
stephb9959
7244bcb455 ACL Fix. 2021-11-15 13:22:03 -08:00
stephb9959
1db5201418 ACL Fix. 2021-11-15 13:16:34 -08:00
stephb9959
1bc635f553 ACL Fix. 2021-11-15 12:05:14 -08:00
stephb9959
257ac42d7c ACL Fix. 2021-11-15 11:51:07 -08:00
stephb9959
acb38e5313 New UUIDv4 generator 2021-11-15 11:19:31 -08:00
stephb9959
7940f0bd85 New UUIDv4 generator 2021-11-15 10:56:27 -08:00
stephb9959
62c06d0bad Filtering credentials. 2021-11-15 09:26:46 -08:00
stephb9959
494a199610 WiFi 5617 and ACL Error 2021-11-15 09:16:23 -08:00
stephb9959
5307b0b35a WiFi 5617 and ACL Error 2021-11-15 09:09:17 -08:00
stephb9959
c58728f38e WiFi 5617 and ACL Error 2021-11-15 08:29:08 -08:00
stephb9959
1f09c3b619 WiFi 5617 and ACL Error 2021-11-15 08:24:57 -08:00
stephb9959
d9c6388502 Merge remote-tracking branch 'origin/main' 2021-11-14 14:18:11 -08:00
stephb9959
5e35906aec Fixing shutdown crash 2021-11-14 14:18:02 -08:00
Dmitry Dunaev
773618ae07 [WIFI-5702] Add: README note on owgw-ui password change ability 2021-11-14 22:39:45 +03:00
stephb9959
cca4441ac7 Rate limiting log error. 2021-11-13 21:33:51 -08:00
stephb9959
730ca7b292 Proper error returning for rate limiting. 2021-11-13 17:35:15 -08:00
stephb9959
5b4dbb088f Final token cache/revocation fix. 2021-11-13 17:23:19 -08:00
stephb9959
bc11a19ee4 Fixing token revocation/ 2021-11-13 17:17:49 -08:00
stephb9959
c835e4d0b9 Fixing token revocatiopn/ 2021-11-13 17:12:39 -08:00
stephb9959
f1a2ba90f6 Fixing token revocatiopn/ 2021-11-13 17:06:52 -08:00
stephb9959
5b96ef396f Fixing token revocatiopn/ 2021-11-13 17:01:49 -08:00
stephb9959
c204d34bf4 Fixing token revocatiopn/ 2021-11-13 16:44:51 -08:00
stephb9959
4b982bf64b Fixing token revocatiopn/ 2021-11-13 16:42:20 -08:00
stephb9959
37298cc600 Fixing token revocatiopn/ 2021-11-13 16:38:18 -08:00
stephb9959
03619cc900 Fixing token revocatiopn/ 2021-11-13 16:24:13 -08:00
stephb9959
f4fc6975e1 Fixing token revocatiopn/ 2021-11-13 16:18:42 -08:00
stephb9959
1f1d596c5a Fixing token cache. 2021-11-13 16:03:58 -08:00
stephb9959
a5802bf631 Adding token expiry detection and reporting. 2021-11-13 15:24:24 -08:00
stephb9959
6471eabc82 Unitialized MFA in user record. 2021-11-13 10:24:21 -08:00
stephb9959
ab6fbaca11 Removing expired links and avatars. 2021-11-13 09:05:16 -08:00
stephb9959
1e8e5c18b2 Removing expired tokens periodically. 2021-11-13 08:43:57 -08:00
stephb9959
3cf23af068 Fix the fix...arg 2021-11-13 08:18:13 -08:00
stephb9959
1a0b549731 Fix the fix...arg 2021-11-13 07:19:52 -08:00
stephb9959
a835d2e571 Framework update. 2021-11-12 23:35:43 -08:00
stephb9959
ff7455af24 improving ACL processing. 2021-11-12 22:25:29 -08:00
stephb9959
48610bac5d Hardening SMS code. 2021-11-12 08:59:45 -08:00
stephb9959
7bd5b4d4e6 Fixing MFA UUID issue. 2021-11-12 08:49:03 -08:00
stephb9959
e1a51c2a91 Fixing MFA UUID issue. 2021-11-12 08:37:17 -08:00
stephb9959
cd0222f765 Fixing MFA UUID issue. 2021-11-12 08:21:44 -08:00
stephb9959
12fddd8bc4 Fixing MFA UUID issue. 2021-11-12 08:20:16 -08:00
stephb9959
9095d831db Merge remote-tracking branch 'origin/main' 2021-11-12 08:14:23 -08:00
stephb9959
4e8f97df9b Fixing logo problem in email 2021-11-12 08:14:15 -08:00
Dmitry Dunaev
28808eae93 Merge pull request #25 from Telecominfraproject/feature/wifi-5702--add-change-password-cli-command-on-startup
[WIFI-5702] Add: README note on changing default password
2021-11-12 19:12:47 +03:00
stephb9959
6c24a23863 Fixing logo problem in email 2021-11-12 08:10:32 -08:00
stephb9959
5931c91054 Fixing logo problem in email 2021-11-12 08:06:21 -08:00
stephb9959
9d956c13f7 Fixing logo problem in email 2021-11-12 07:53:49 -08:00
Dmitry Dunaev
ea1adde361 [WIFI-5702] Add: README note on changing default password 2021-11-12 14:40:56 +03:00
stephb9959
eaac1f1625 Adding JSON to docker build 2021-11-11 21:49:54 -08:00
stephb9959
c5f4c067bb Adding JSON to docker build 2021-11-11 21:45:24 -08:00
stephb9959
31a9e4564b Adding JSON to docker build 2021-11-11 21:23:28 -08:00
stephb9959
a9affc29bb Introducing rules on userroles. 2021-11-11 21:13:11 -08:00
stephb9959
65fc0a1d10 Adding minimal user access rights. 2021-11-11 20:35:45 -08:00
stephb9959
82c01ce438 Adding minimal user access rights. 2021-11-11 18:17:24 -08:00
stephb9959
5f900883e8 Adding error codes on login. 2021-11-11 17:52:20 -08:00
stephb9959
e97b8e64be First iteration of default user credentials creation. 2021-11-11 15:57:09 -08:00
stephb9959
6c90c75708 First iteration of default user credentials creation. 2021-11-11 15:52:23 -08:00
stephb9959
a3d86c7cf9 First iteration of default user credentials creation. 2021-11-11 15:49:19 -08:00
stephb9959
50b6ac9522 First iteration of default user credentials creation. 2021-11-11 15:42:36 -08:00
stephb9959
15b947a34d Fixing ActionLinks 2021-11-11 13:43:46 -08:00
stephb9959
160bd00a99 Fixing ActionLinks 2021-11-10 13:22:57 -08:00
stephb9959
3c7daa537a Fixing ActionLinks 2021-11-10 11:44:09 -08:00
stephb9959
c5bab1d749 Fixing ActionLinks 2021-11-10 09:22:08 -08:00
stephb9959
96c3244be0 Framework update. 2021-11-09 19:36:27 -08:00
stephb9959
7e4b515f60 Framework update. 2021-11-09 18:03:49 -08:00
stephb9959
a63f80e497 Fixing ActionLinks 2021-11-09 17:22:00 -08:00
stephb9959
2eae6cc73c Fixing ActionLinks 2021-11-09 17:06:30 -08:00
stephb9959
96f215b3c2 Fixing ActionLinks 2021-11-09 15:03:18 -08:00
stephb9959
9551384358 Fixing ActionLinks 2021-11-09 14:58:04 -08:00
stephb9959
b21c5c5e00 Fixing ActionLinks 2021-11-09 14:43:49 -08:00
stephb9959
031d35256c Fixing ActionLinks 2021-11-09 14:21:30 -08:00
stephb9959
5738fa47bb Fixing ActionLinks 2021-11-09 14:09:09 -08:00
stephb9959
fe17650333 Fixing ActionLinks 2021-11-09 13:54:32 -08:00
stephb9959
7636568fb4 Fixing ActionLinks 2021-11-09 13:41:28 -08:00
stephb9959
c0ef77eb53 Fixing ActionLinks 2021-11-09 13:24:26 -08:00
stephb9959
00742a5d0a Implementing several adjustments for security reasons. 2021-11-09 11:57:38 -08:00
stephb9959
a96f673380 Implementing several adjustments for security reasons. 2021-11-09 11:55:22 -08:00
stephb9959
53ecdb471e Implementing several adjustments for security reasons. 2021-11-09 11:52:08 -08:00
stephb9959
f80a0c5007 Implementing several adjustments for security reasons. 2021-11-09 11:50:39 -08:00
stephb9959
9e7d7ba67d Implementing several adjustments for security reasons. 2021-11-09 11:49:28 -08:00
stephb9959
b508c0d054 Implementing several adjustments for security reasons. 2021-11-09 11:48:20 -08:00
stephb9959
79788dab44 Implementing several adjustments for security reasons. 2021-11-09 11:47:25 -08:00
stephb9959
8dec946c45 Implementing several adjustments for security reasons. 2021-11-09 11:40:40 -08:00
stephb9959
43ea5ac424 Implementing several adjustments for security reasons. 2021-11-09 11:39:51 -08:00
stephb9959
328ff158cb Implementing several adjustments for security reasons. 2021-11-09 11:38:23 -08:00
stephb9959
2b89d843c3 Merge remote-tracking branch 'origin/main' 2021-11-09 11:33:29 -08:00
stephb9959
45a50483be Implementing several adjustments for security reasons. 2021-11-09 11:33:20 -08:00
Max
c8ae94a062 allow to set pod annotations (#24) 2021-11-09 12:39:36 +01:00
stephb9959
7b19143d6f Fixing some HTML templates. 2021-11-07 11:18:37 -08:00
stephb9959
bc0c889098 Fixing an issue with some www asset location. 2021-11-07 10:50:37 -08:00
stephb9959
6f8f81866f Fixing HTML policy files so they don't look like the work of a 3 year old. 2021-11-05 13:43:52 -07:00
stephb9959
f213c99816 Fixing passwordpolicy and policy path non-expansion. 2021-11-02 08:50:59 -07:00
stephb9959
423aca9892 Fixing token generation. 2021-10-30 09:46:07 -07:00
139 changed files with 13679 additions and 3431 deletions

View File

@@ -25,45 +25,46 @@ jobs:
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
DOCKER_REGISTRY_USERNAME: ucentral DOCKER_REGISTRY_USERNAME: ucentral
steps: steps:
- uses: actions/checkout@v2 - name: Checkout actions repo
uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t wlan-cloud-owsec:${{ github.sha }} .
- name: Tag Docker image
run: |
TAGS="${{ github.sha }}"
if [[ ${GITHUB_REF} == "refs/heads/"* ]]
then
CURRENT_TAG=$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-')
TAGS="$TAGS $CURRENT_TAG"
else
if [[ ${GITHUB_REF} == "refs/tags/"* ]]
then
CURRENT_TAG=$(echo ${GITHUB_REF#refs/tags/} | tr '/' '-')
TAGS="$TAGS $CURRENT_TAG"
else # PR build
CURRENT_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
TAGS="$TAGS $CURRENT_TAG"
fi
fi
echo "Result tags: $TAGS"
for tag in $TAGS; do
docker tag wlan-cloud-owsec:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owsec:$tag
done
- name: Log into Docker registry
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main'
uses: docker/login-action@v1
with: with:
registry: ${{ env.DOCKER_REGISTRY_URL }} repository: Telecominfraproject/.github
username: ${{ env.DOCKER_REGISTRY_USERNAME }} path: github
password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
- name: Push Docker images - name: Build and push Docker image
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/main' uses: ./github/composite-actions/docker-image-build
with:
image_name: owsec
registry: tip-tip-wlan-cloud-ucentral.jfrog.io
registry_user: ucentral
registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
trigger-testing:
if: startsWith(github.ref, 'refs/pull/')
runs-on: ubuntu-latest
needs: docker
steps:
- name: Get base branch name and set as output
id: get_base_branch
run: | run: |
docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/owsec | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {} echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
- name: Checkout actions repo
uses: actions/checkout@v2
with:
repository: Telecominfraproject/.github
path: github
- name: Trigger testing of OpenWifi Docker Compose deployment and wait for result
uses: ./github/composite-actions/trigger-workflow-and-wait
env:
BASE_BRANCH: ${{ steps.get_base_branch.outputs.branch }}
OWGW_BASE_BRANCH: ${{ steps.get_base_branch.outputs.owgw_branch }}
with:
owner: Telecominfraproject
repo: wlan-testing
workflow: ow_docker-compose.yml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"owgw_version": "${{ env.OWGW_BASE_BRANCH }}", "owgwui_version": "${{ env.BASE_BRANCH }}", "owsec_version": "${{ github.sha }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "main", "owprovui_version": "main"}'

View File

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

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(owsec VERSION 2.3.0) project(owsec VERSION 2.5.0)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@@ -20,19 +20,32 @@ endif()
# Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1 # Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build)
file(READ build BUILD_NUM) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/build BUILD_NUM)
if(BUILD_INCREMENT) if(BUILD_INCREMENT)
MATH(EXPR BUILD_NUM "${BUILD_NUM}+1") MATH(EXPR BUILD_NUM "${BUILD_NUM}+1")
file(WRITE build ${BUILD_NUM}) file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
endif() endif()
else() else()
set(BUILD_NUM 1) set(BUILD_NUM 1)
file(WRITE build ${BUILD_NUM}) file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM})
endif() endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
add_definitions(-DAWS_CUSTOM_MEMORY_MANAGEMENT)
set(BUILD_SHARED_LIBS 1) set(BUILD_SHARED_LIBS 1)
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}")
add_definitions(-DTIP_SECURITY_SERVICE="1") add_definitions(-DTIP_SECURITY_SERVICE="1")
set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_STATIC_LIBS OFF)
@@ -42,7 +55,7 @@ find_package(Boost REQUIRED system)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(AWSSDK REQUIRED COMPONENTS sns) find_package(AWSSDK REQUIRED COMPONENTS sns)
find_package(nlohmann_json REQUIRED)
find_package(CppKafka REQUIRED) find_package(CppKafka REQUIRED)
find_package(PostgreSQL REQUIRED) find_package(PostgreSQL REQUIRED)
find_package(MySQL REQUIRED) find_package(MySQL REQUIRED)
@@ -50,35 +63,48 @@ find_package(Poco REQUIRED COMPONENTS JSON Crypto JWT Net Util NetSSL Data DataS
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include) include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_executable( owsec add_executable( owsec
build build
src/ow_version.h.in
src/framework/CountryCodes.h src/framework/CountryCodes.h
src/framework/KafkaTopics.h src/framework/KafkaTopics.h
src/framework/MicroService.h src/framework/MicroService.h
src/framework/OpenWifiTypes.h
src/framework/orm.h src/framework/orm.h
src/framework/RESTAPI_errors.h src/framework/RESTAPI_errors.h
src/framework/RESTAPI_protocol.h src/framework/RESTAPI_protocol.h
src/framework/StorageClass.h src/framework/StorageClass.h
src/framework/uCentral_Protocol.h src/framework/uCentral_Protocol.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_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
src/RESTAPI/RESTAPI_oauth2Handler.h src/RESTAPI/RESTAPI_oauth2Handler.cpp src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h
src/RESTAPI/RESTAPI_validateToken_handler.cpp src/RESTAPI/RESTAPI_validateToken_handler.h src/RESTAPI/RESTAPI_validate_token_handler.cpp src/RESTAPI/RESTAPI_validate_token_handler.h
src/RESTAPI/RESTAPI_systemEndpoints_handler.cpp src/RESTAPI/RESTAPI_systemEndpoints_handler.h src/RESTAPI/RESTAPI_system_endpoints_handler.cpp src/RESTAPI/RESTAPI_system_endpoints_handler.h
src/RESTAPI/RESTAPI_AssetServer.cpp src/RESTAPI/RESTAPI_AssetServer.h src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h
src/RESTAPI/RESTAPI_avatarHandler.cpp src/RESTAPI/RESTAPI_avatarHandler.h src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h
src/RESTAPI/RESTAPI_subavatar_handler.cpp src/RESTAPI/RESTAPI_subavatar_handler.h
src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h
src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h
src/storage/storage_avatar.cpp src/storage/storage_avatar.h src/storage/storage_users.h src/RESTAPI/RESTAPI_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp
src/storage/storage_tables.cpp src/storage/storage_users.cpp src/storage/storage_tokens.cpp src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp
src/APIServers.cpp src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp
src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp src/RESTAPI/RESTAPI_validate_sub_token_handler.h
src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h
src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h
src/RESTAPI/RESTAPI_subpreferences.cpp src/RESTAPI/RESTAPI_subpreferences.h
src/RESTAPI/RESTAPI_routers.cpp
src/Daemon.h src/Daemon.cpp src/Daemon.h src/Daemon.cpp
src/SpecialUserHelpers.h
src/AuthService.h src/AuthService.cpp src/AuthService.h src/AuthService.cpp
src/StorageService.cpp src/StorageService.h src/StorageService.cpp src/StorageService.h
src/SMTPMailerService.cpp src/SMTPMailerService.h src/SMTPMailerService.cpp src/SMTPMailerService.h
@@ -86,7 +112,17 @@ add_executable( owsec
src/MFAServer.cpp src/MFAServer.h src/MFAServer.cpp src/MFAServer.h
src/SMS_provider_aws.cpp src/SMS_provider_aws.h src/SMS_provider_aws.cpp src/SMS_provider_aws.h
src/SMS_provider.cpp src/SMS_provider.h src/SMS_provider.cpp src/SMS_provider.h
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h) src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
src/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)
if(NOT SMALL_BUILD) if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC target_link_libraries(owsec PUBLIC

View File

@@ -1,16 +1,51 @@
FROM alpine AS builder FROM alpine:3.15 AS build-base
RUN apk add --update --no-cache \ RUN apk add --update --no-cache \
openssl openssh \ make cmake g++ git \
ncurses-libs \ unixodbc-dev postgresql-dev mariadb-dev \
bash util-linux coreutils curl libcurl \ librdkafka-dev boost-dev openssl-dev \
make cmake gcc g++ libstdc++ libgcc git zlib-dev \ zlib-dev nlohmann-json \
openssl-dev boost-dev curl-dev unixodbc-dev postgresql-dev mariadb-dev \ curl-dev
apache2-utils yaml-dev apr-util-dev \
librdkafka-dev
FROM build-base AS poco-build
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/poco /poco RUN git clone https://github.com/stephb9959/poco /poco
WORKDIR /poco
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS cppkafka-build
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
WORKDIR /cppkafka
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS json-schema-validator-build
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
WORKDIR /json-schema-validator
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
FROM build-base AS aws-sdk-cpp-build
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
WORKDIR /aws-sdk-cpp WORKDIR /aws-sdk-cpp
@@ -23,23 +58,21 @@ RUN cmake .. -DBUILD_ONLY="sns;s3" \
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install RUN cmake --build . --target install
WORKDIR /cppkafka FROM build-base AS owsec-build
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
WORKDIR /poco
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
ADD CMakeLists.txt build /owsec/ ADD CMakeLists.txt build /owsec/
ADD cmake /owsec/cmake ADD cmake /owsec/cmake
ADD src /owsec/src ADD src /owsec/src
ADD .git /owsec/.git
COPY --from=poco-build /usr/local/include /usr/local/include
COPY --from=poco-build /usr/local/lib /usr/local/lib
COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
WORKDIR /owsec WORKDIR /owsec
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -47,7 +80,7 @@ WORKDIR /owsec/cmake-build
RUN cmake .. RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
FROM alpine FROM alpine:3.15
ENV OWSEC_USER=owsec \ ENV OWSEC_USER=owsec \
OWSEC_ROOT=/owsec-data \ OWSEC_ROOT=/owsec-data \
@@ -59,22 +92,27 @@ RUN addgroup -S "$OWSEC_USER" && \
RUN mkdir /openwifi RUN mkdir /openwifi
RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \ RUN mkdir -p "$OWSEC_ROOT" "$OWSEC_CONFIG" && \
chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG" chown "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl
COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/ mariadb-connector-c libpq unixodbc postgresql-client
COPY --from=builder /poco/cmake-build/lib/* /lib/
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /lib/ COPY readiness_check /readiness_check
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /lib/ COPY test_scripts/curl/cli /cli
COPY --from=builder /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /lib/
COPY owsec.properties.tmpl / COPY owsec.properties.tmpl /
COPY wwwassets /dist/wwwassets COPY wwwassets /dist/wwwassets
COPY templates /dist/templates COPY templates /dist/templates
COPY docker-entrypoint.sh / COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh /
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
COPY readiness_check /readiness_check COPY --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
EXPOSE 16001 17001 16101 EXPOSE 16001 17001 16101

View File

@@ -98,6 +98,40 @@ to get a sample. The default is
### `authentication.oldpasswords` ### `authentication.oldpasswords`
The number of older passwords to keep. Default is 5. The number of older passwords to keep. Default is 5.
### Changing default password
On the first startup of the service new user will be created with the default credentials from properties `authentication.default.username` and `authentication.default.password`, but **you will have to change the password** before making any real requests.
You can this using [owgw-ui](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw-ui/) on first login or using the following script:
```
export OWSEC=openwifi.wlan.local:16001 # endpoint to your owsec RESTAPI endpoint
#export FLAGS="-k" # uncomment and add curl flags that you would like to pass for the request (for example '-k' may be used to pass errors with self-signed certificates)
export OWSEC_DEFAULT_USERNAME=root@system.com # default username that you've set in property 'authentication.default.username'
export OWSEC_DEFAULT_PASSWORD=weLoveWifi # default password __in cleartext__ from property 'authentication.default.password'
export OWSEC_NEW_PASSWORD=NewPass123% # new password that must be set for the user (must comply with 'authentication.validation.expression')
test_scripts/curl/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
```
CLI is also included in Docker image if you want to run it this way:
```
export OWSEC=openwifi.wlan.local:16001
#export FLAGS="-k"
export OWSEC_DEFAULT_USERNAME=root@system.com
export OWSEC_DEFAULT_PASSWORD=weLoveWifi
export OWSEC_NEW_PASSWORD=NewPass123%
docker run --rm -ti \
--network=host \
--env OWSEC \
--env FLAGS \
--env OWSEC_DEFAULT_USERNAME \
--env OWSEC_DEFAULT_PASSWORD \
--env OWSEC_NEW_PASSWORD \
tip-tip-wlan-cloud-ucentral.jfrog.io/owsec:main \
/cli testlogin $OWSEC_DEFAULT_USERNAME $OWSEC_DEFAULT_PASSWORD $OWSEC_NEW_PASSWORD
```
### Kafka integration ### Kafka integration
This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running This security service uses Kafka to coordinate security with other services that are part of the system. You must have a Kafka service running
in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure. in order to use this. You can find several examples of Kafka services available with Docker. Here are the values you need to configure.
@@ -184,8 +218,8 @@ This is the FQDN used externally serving the OpenAPI interface.
`owsec` hs the ability to send SMS messages to users during login or to send notifications. In order to do so, `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 an SMS provider must be configured. At present time, 2 providers are supported: Tilio and AWS SNS
#### AWS SNS #### AWS SMS
For SNS you must create an IAM ID that has sns:sendmessage rights. For SNS you must create an IAM ID that has sns:sendmessage rights.
```asm ```asm
smssender.provider = aws smssender.provider = aws
@@ -217,4 +251,14 @@ mailer.sender = OpenWIFI
mailer.loginmethod = login mailer.loginmethod = login
mailer.port = 587 mailer.port = 587
mailer.templates = $OWSEC_ROOT/templates mailer.templates = $OWSEC_ROOT/templates
``` ```
#### Google Authenticator
In order to use the Google Time-based One-Time Password (TOTP), the user must down load the Goole Authenticator
on any other app that support the TOTP protocol. You should include the following in your configuration
```asm
totp.issuer = OrgName
```
It is very important that you not use spaces in your OrgName.

2
build
View File

@@ -1 +1 @@
12 244

View File

@@ -25,9 +25,18 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWSEC_CONFIG"/owsec.properties ]]; t
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \ SERVICE_KEY=${SERVICE_KEY:-"\$OWSEC_ROOT/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
MAILER_HOSTNAME=${MAILER_HOSTNAME:-"smtp.gmail.com"} \ SMSSENDER_ENABLED=${SMSSENDER_ENABLED:-"false"} \
MAILER_USERNAME=${MAILER_USERNAME:-"************************"} \ SMSSENDER_PROVIDER=${SMSSENDER_PROVIDER:-""} \
MAILER_PASSWORD=${MAILER_PASSWORD:-"************************"} \ SMSSENDER_AWS_SECRETKEY=${SMSSENDER_AWS_SECRETKEY:-""} \
SMSSENDER_AWS_ACCESSKEY=${SMSSENDER_AWS_ACCESSKEY:-""} \
SMSSENDER_AWS_REGION=${SMSSENDER_AWS_REGION:-""} \
SMSSENDER_TWILIO_SID=${SMSSENDER_TWILIO_SID:-""} \
SMSSENDER_TWILIO_TOKEN=${SMSSENDER_TWILIO_TOKEN:-""} \
SMSSENDER_TWILIO_PHONENUMBER=${SMSSENDER_TWILIO_PHONENUMBER:-""} \
MAILER_ENABLED=${MAILER_ENABLED:-"false"} \
MAILER_HOSTNAME=${MAILER_HOSTNAME:-"localhost"} \
MAILER_USERNAME=${MAILER_USERNAME:-""} \
MAILER_PASSWORD=${MAILER_PASSWORD:-""} \
MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \ MAILER_SENDER=${MAILER_SENDER:-"OpenWIFI"} \
MAILER_PORT=${MAILER_PORT:-"587"} \ MAILER_PORT=${MAILER_PORT:-"587"} \
MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \ MAILER_TEMPLATES=${MAILER_TEMPLATES:-"\$OWSEC_ROOT/persist/templates"} \

View File

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

View File

@@ -13,6 +13,7 @@ spec:
replicas: {{ .Values.replicaCount }} replicas: {{ .Values.replicaCount }}
strategy: strategy:
type: {{ .Values.strategyType }} type: {{ .Values.strategyType }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector: selector:
matchLabels: matchLabels:
app.kubernetes.io/name: {{ include "owsec.name" . }} app.kubernetes.io/name: {{ include "owsec.name" . }}
@@ -24,6 +25,9 @@ spec:
metadata: metadata:
annotations: annotations:
checksum/config: {{ include "owsec.config" . | sha256sum }} checksum/config: {{ include "owsec.config" . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels: labels:
app.kubernetes.io/name: {{ include "owsec.name" . }} app.kubernetes.io/name: {{ include "owsec.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/instance: {{ .Release.Name }}
@@ -32,6 +36,16 @@ spec:
{{- end }} {{- end }}
spec: spec:
initContainers:
- name: wait-kafka
image: "{{ .Values.images.dockerize.repository }}:{{ .Values.images.dockerize.tag }}"
imagePullPolicy: {{ .Values.images.dockerize.pullPolicy }}
args:
- -wait
- tcp://{{ index .Values.configProperties "openwifi.kafka.brokerlist" }}
- -timeout
- 600s
containers: containers:
- name: owsec - name: owsec

View File

@@ -1,6 +1,7 @@
# System # System
replicaCount: 1 replicaCount: 1
strategyType: Recreate strategyType: Recreate
revisionHistoryLimit: 2
nameOverride: "" nameOverride: ""
fullnameOverride: "" fullnameOverride: ""
@@ -8,16 +9,20 @@ fullnameOverride: ""
images: images:
owsec: owsec:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owsec
tag: main tag: v2.5.0
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # registry: tip-tip-wlan-cloud-ucentral.jfrog.io
# username: username # username: username
# password: password # password: password
dockerize:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/dockerize
tag: 0.16.0
pullPolicy: IfNotPresent
services: services:
owsec: owsec:
type: LoadBalancer type: ClusterIP
ports: ports:
restapi: restapi:
servicePort: 16001 servicePort: 16001
@@ -38,7 +43,6 @@ checks:
exec: exec:
command: command:
- /readiness_check - /readiness_check
failureThreshold: 1
ingresses: ingresses:
restapi: restapi:
@@ -95,6 +99,8 @@ tolerations: []
affinity: {} affinity: {}
podAnnotations: {}
persistence: persistence:
enabled: true enabled: true
# storageClassName: "-" # storageClassName: "-"
@@ -139,11 +145,17 @@ configProperties:
authentication.default.access: master authentication.default.access: master
authentication.service.type: internal authentication.service.type: internal
# Mailer # Mailer
mailer.enabled: "false"
mailer.hostname: smtp.gmail.com mailer.hostname: smtp.gmail.com
mailer.sender: OpenWIFI mailer.sender: OpenWIFI
mailer.loginmethod: login mailer.loginmethod: login
mailer.port: 587 mailer.port: 587
mailer.templates: $OWSEC_ROOT/persist/templates mailer.templates: $OWSEC_ROOT/persist/templates
# SMS
smssender.enabled: "false"
smssender.provider: "aws"
#smssender.aws.region: ""
#smssender.twilio.phonenumber: ""
# ALB # ALB
alb.enable: "true" alb.enable: "true"
alb.port: 16101 alb.port: 16101
@@ -183,22 +195,9 @@ configProperties:
openwifi.system.uri.ui: https://localhost openwifi.system.uri.ui: https://localhost
openwifi.system.commandchannel: /tmp/app_owsec openwifi.system.commandchannel: /tmp/app_owsec
# Logging # Logging
logging.formatters.f1.class: PatternFormatter logging.type: console
logging.formatters.f1.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t" logging.path: $OWSEC_ROOT/logs
logging.formatters.f1.times: UTC logging.level: debug
logging.channels.c1.class: ConsoleChannel
logging.channels.c1.formatter: f1
logging.channels.c2.class: FileChannel
logging.channels.c2.path: /tmp/log_owsec
logging.channels.c2.formatter.class: PatternFormatter
logging.channels.c2.formatter.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t"
logging.channels.c2.rotation: "20 M"
logging.channels.c2.archive: timestamp
logging.channels.c2.purgeCount: 20
logging.channels.c3.class: ConsoleChannel
logging.channels.c3.pattern: "%s: [%p] %t"
logging.loggers.root.channel: c1
logging.loggers.root.level: debug
# -> Secret part # -> Secret part
# REST API # REST API
@@ -210,6 +209,12 @@ configProperties:
# Mailer # Mailer
mailer.username: no-reply@arilia.com mailer.username: no-reply@arilia.com
mailer.password: "**************************" mailer.password: "**************************"
# SMS
#smssender.aws.secretkey: ""
#smssender.aws.accesskey: ""
#smssender.twilio.sid: ""
#smssender.twilio.token: ""
#
# Storage # Storage
## PostgreSQL ## PostgreSQL
storage.type.postgresql.username: stephb storage.type.postgresql.username: stephb

View File

@@ -2,7 +2,7 @@ openapi: 3.0.1
info: info:
title: uCentral Security API title: uCentral Security API
description: A process to manage security logins. description: A process to manage security logins.
version: 2.0.0 version: 2.5.0
license: license:
name: BSD3 name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
@@ -51,6 +51,21 @@ components:
properties: properties:
ErrorCode: ErrorCode:
type: integer type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # EXPIRED_TOKEN
- 10 # RATE_LIMIT_EXCEEDED
- 11 # BAD_MFA_TRANSACTION
- 12 # MFA_FAILURE
- 13 # SECURITY_SERVICE_UNREACHABLE
ErrorDetails: ErrorDetails:
type: string type: string
ErrorDescription: ErrorDescription:
@@ -69,8 +84,20 @@ components:
Code: Code:
type: integer type: integer
schemas: BadRequest:
description: The requested operation failed.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: integer
schemas:
WebTokenRequest: WebTokenRequest:
description: User Id and password. description: User Id and password.
type: object type: object
@@ -216,7 +243,7 @@ components:
enum: enum:
- sms - sms
- email - email
- voice - authenticator
UserLoginLoginExtensions: UserLoginLoginExtensions:
type: object type: object
@@ -225,6 +252,8 @@ components:
type: array type: array
items: items:
$ref: '#/components/schemas/MobilePhoneNumber' $ref: '#/components/schemas/MobilePhoneNumber'
authenticatorSecret:
type: string
mfa: mfa:
$ref: '#/components/schemas/MfaAuthInfo' $ref: '#/components/schemas/MfaAuthInfo'
@@ -321,6 +350,9 @@ components:
securityPolicyChange: securityPolicyChange:
type: integer type: integer
format: int64 format: int64
modified:
type: integer
format: int64
userTypeProprietaryInfo: userTypeProprietaryInfo:
$ref: '#/components/schemas/UserLoginLoginExtensions' $ref: '#/components/schemas/UserLoginLoginExtensions'
@@ -381,6 +413,24 @@ components:
answer: answer:
type: string type: string
SubMfaConfig:
type: object
properties:
id:
type: string
format: uuid
type:
type: string
enum:
- disabled
- sms
- email
email:
type: string
format: email
sms:
type: string
######################################################################################### #########################################################################################
## ##
## These are endpoints that all services in the uCentral stack must provide ## These are endpoints that all services in the uCentral stack must provide
@@ -625,6 +675,22 @@ components:
items: items:
$ref: '#/components/schemas/TagValuePair' $ref: '#/components/schemas/TagValuePair'
Preferences:
type: object
properties:
modified:
type: integer
format: int64
data:
type: array
items:
type: object
properties:
tag:
type: string
value:
type: string
######################################################################################### #########################################################################################
## ##
## End of uCentral system wide values ## End of uCentral system wide values
@@ -690,6 +756,64 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/suboauth2:
post:
tags:
- Authentication
summary: Get access token - to be used as Bearer token header for all other API requests.
operationId: getSubAccessToken
parameters:
- in: query
name: newPassword
description: used when a user is trying to change her password. This will be the new password.
schema:
type: string
required: false
- in: query
name: forgotPassword
description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
schema:
type: boolean
required: false
- in: query
name: requirements
description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
schema:
type: boolean
required: false
- in: query
name: resendMFACode
schema:
type: boolean
required: false
- in: query
name: completeMFAChallenge
schema:
type: boolean
required: false
requestBody:
description: User id and password
required: true
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/WebTokenRequest'
- $ref: '#/components/schemas/MFAChallengeResponse'
responses:
200:
description: successful operation
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/WebTokenResult'
- $ref: '#/components/schemas/MFAChallengeRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/oauth2/{token}: /oauth2/{token}:
delete: delete:
tags: tags:
@@ -715,6 +839,31 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/suboauth2/{token}:
delete:
tags:
- Authentication
summary: Revoke a token.
operationId: removeSubAccessToken
parameters:
- in: path
name: token
schema:
type:
string
required: true
responses:
204:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/systemEndpoints: /systemEndpoints:
get: get:
tags: tags:
@@ -779,6 +928,52 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/subusers:
get:
tags:
- Subscribers
summary: Retrieve a list of existing users as well as some information about them.
operationId: getSubUsers
parameters:
- in: query
name: offset
schema:
type: integer
format: int64
required: false
- in: query
name: limit
schema:
type: integer
format: int64
required: false
- in: query
description: Selecting this option means the newest record will be returned. Use limit to select how many.
name: filter
schema:
type: string
required: false
- in: query
description: Return only the ids.
name: idOnly
schema:
type: boolean
required: false
- in: query
description: Return only the ids.
name: select
schema:
type: string
example: id1,id2,id3,id4,id5
required: false
responses:
200:
$ref: '#/components/schemas/UserList'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/user/{id}: /user/{id}:
get: get:
tags: tags:
@@ -883,6 +1078,110 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/subuser/{id}:
get:
tags:
- Subscribers
operationId: getSubUser
summary: Retrieve the information for a single user.
parameters:
- in: path
name: id
schema:
type: string
format: uuid
required: true
responses:
200:
$ref: '#/components/schemas/UserInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- Subscribers
operationId: deleteSubUser
summary: Delete a single user.
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
responses:
204:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
post:
tags:
- Subscribers
operationId: createSubUser
summary: Create a single user.
parameters:
- in: path
name: id
#must be set to 0 for user creation
schema:
type: integer
format: int64
required: true
- in: query
name: email_verification
schema:
type: boolean
required: false
requestBody:
description: User details (some fields are ignored during creation)
content:
application/json:
schema:
$ref: '#/components/schemas/UserInfo'
responses:
200:
$ref: '#/components/schemas/UserInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
put:
tags:
- Subscribers
operationId: updateSubUser
summary: Modify a single user.
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
- in: query
name: email_verification
schema:
type: boolean
required: false
requestBody:
description: User details (some fields are ignored during update)
content:
application/json:
schema:
$ref: '#/components/schemas/UserInfo'
responses:
200:
$ref: '#/components/schemas/UserInfo'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/avatar/{id}: /avatar/{id}:
get: get:
tags: tags:
@@ -1053,6 +1352,138 @@ paths:
items: items:
type: string type: string
/userPreferences:
get:
tags:
- Preferences
operationId: getUserPreferences
summary: Get the list of recorded preferences for a user
responses:
200:
$ref: '#/components/schemas/Preferences'
400:
$ref: '#/components/responses/BadRequest'
post:
tags:
- Preferences
operationId: setUserPreferences
summary: Set the list of recorded preferences for a user
requestBody:
description: Setting the list of preferences
content:
application/json:
schema:
$ref: '#/components/schemas/Preferences'
responses:
200:
$ref: '#/components/schemas/Preferences'
400:
$ref: '#/components/responses/BadRequest'
/submfa:
get:
tags:
- MFA
summary: Retrieve the cyrrent setting for MFA
operationId: getMFS
responses:
200:
$ref: '#/components/schemas/SubMfaConfig'
put:
tags:
- MFA
summary: Retrieve the cyrrent setting for MFA
operationId: modifyMFS
parameters:
- in: query
name: startValidation
schema:
type: boolean
required: false
- in: query
name: completeValidation
schema:
type: boolean
required: false
- in: query
name: challengeCode
schema:
type: string
required: false
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SubMfaConfig'
responses:
200:
$ref: '#/components/schemas/SubMfaConfig'
400:
$ref: '#/components/responses/BadRequest'
/totp:
get:
tags:
- Security
summary: Retrieve the Authenticator QR Code
operationId: getTotpQrCode
parameters:
- in: query
name: reset
schema:
type: boolean
default: false
required: false
responses:
200:
description: QRCode
content:
image/svg+xml:
schema:
type: string
format: binary
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
put:
tags:
- Security
summary: Send the first security code to validate your setup
operationId: sendToptTestCode
parameters:
- in: query
name: value
schema:
type: integer
format: int64
required: true
- in: query
name: index
schema:
type: integer
format: int64
required: required
example: 1,2,3
responses:
200:
description: Succesful posting of response.
content:
application/json:
schema:
type: object
properties:
nextIndex:
type: integer
moreCodes:
type: boolean
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
######################################################################################### #########################################################################################
## ##
## These are endpoints that all services in the uCentral stack must provide ## These are endpoints that all services in the uCentral stack must provide
@@ -1128,6 +1559,27 @@ paths:
404: 404:
$ref: '#/components/responses/NotFound' $ref: '#/components/responses/NotFound'
/validateSubToken:
get:
tags:
- Security
- Subscribers
summary: Allows any microservice to validate a token and get security policy for a specific user.
operationId: validateSubToken
parameters:
- in: query
name: token
schema:
type: string
required: true
responses:
200:
$ref: '#/components/schemas/TokenValidationResult'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/system: /system:
post: post:
tags: tags:

View File

@@ -40,6 +40,7 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec
openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem openwifi.service.key = $OWSEC_ROOT/certs/restapi-key.pem
openwifi.service.key.password = mypassword openwifi.service.key.password = mypassword
smssender.enabled = false
smssender.provider = aws smssender.provider = aws
smssender.aws.secretkey = *************************************** smssender.aws.secretkey = ***************************************
smssender.aws.accesskey = *************************************** smssender.aws.accesskey = ***************************************
@@ -53,6 +54,7 @@ smssender.aws.region = **************
# #
# Security Microservice Specific Section # Security Microservice Specific Section
# #
mailer.enabled = false
mailer.hostname = smtp.gmail.com mailer.hostname = smtp.gmail.com
mailer.username = ************************ mailer.username = ************************
mailer.password = ************************ mailer.password = ************************
@@ -84,6 +86,7 @@ openwifi.document.policy.access = /wwwassets/access_policy.html
openwifi.document.policy.password = /wwwassets/password_policy.html openwifi.document.policy.password = /wwwassets/password_policy.html
openwifi.avatar.maxsize = 2000000 openwifi.avatar.maxsize = 2000000
totp.issuer = OpenWiFi
# #
# This section select which form of persistence you need # This section select which form of persistence you need
# Only one selected at a time. If you select multiple, this service will die if a horrible # Only one selected at a time. If you select multiple, this service will die if a horrible
@@ -116,44 +119,12 @@ storage.type.mysql.database = ucentral
storage.type.mysql.port = 3306 storage.type.mysql.port = 3306
storage.type.mysql.connectiontimeout = 60 storage.type.mysql.connectiontimeout = 60
######################################################################## ########################################################################
######################################################################## ########################################################################
# #
# Logging: please leave as is for now. # Logging: please leave as is for now.
# #
######################################################################## ########################################################################
logging.formatters.f1.class = PatternFormatter logging.type = file
logging.formatters.f1.pattern = %s: [%p] %t logging.path = $OWSEC_ROOT/logs
logging.formatters.f1.times = UTC logging.level = debug
logging.channels.c1.class = ConsoleChannel
logging.channels.c1.formatter = f1
# This is where the logs will be written. This path MUST exist
logging.channels.c2.class = FileChannel
logging.channels.c2.path = $OWSEC_ROOT/logs/log
logging.channels.c2.formatter.class = PatternFormatter
logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
logging.channels.c2.rotation = 20 M
logging.channels.c2.archive = timestamp
logging.channels.c2.purgeCount = 20
logging.channels.c3.class = ConsoleChannel
logging.channels.c3.pattern = %s: [%p] %t
# External Channel
logging.loggers.root.channel = c2
logging.loggers.root.level = debug
# Inline Channel with PatternFormatter
# logging.loggers.l1.name = logger1
# logging.loggers.l1.channel.class = ConsoleChannel
# logging.loggers.l1.channel.pattern = %s: [%p] %t
# logging.loggers.l1.level = information
# SplitterChannel
# logging.channels.splitter.class = SplitterChannel
# logging.channels.splitter.channels = l1,l2
# logging.loggers.l2.name = logger2
# logging.loggers.l2.channel = splitter

View File

@@ -40,9 +40,21 @@ openwifi.system.commandchannel = /tmp/app.ucentralsec
openwifi.service.key = ${SERVICE_KEY} openwifi.service.key = ${SERVICE_KEY}
openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} openwifi.service.key.password = ${SERVICE_KEY_PASSWORD}
smssender.enabled = ${SMSSENDER_ENABLED}
smssender.provider = ${SMSSENDER_PROVIDER}
smssender.aws.secretkey = ${SMSSENDER_AWS_SECRETKEY}
smssender.aws.accesskey = ${SMSSENDER_AWS_ACCESSKEY}
smssender.aws.region = ${SMSSENDER_AWS_REGION}
smssender.twilio.sid = ${SMSSENDER_TWILIO_SID}
smssender.twilio.token = ${SMSSENDER_TWILIO_TOKEN}
smssender.twilio.phonenumber = ${SMSSENDER_TWILIO_PHONENUMBER}
# #
# Security Microservice Specific Section # Security Microservice Specific Section
# #
mailer.enabled = ${MAILER_ENABLED}
mailer.hostname = ${MAILER_HOSTNAME} mailer.hostname = ${MAILER_HOSTNAME}
mailer.username = ${MAILER_USERNAME} mailer.username = ${MAILER_USERNAME}
mailer.password = ${MAILER_PASSWORD} mailer.password = ${MAILER_PASSWORD}
@@ -110,37 +122,6 @@ storage.type.mysql.connectiontimeout = 60
# Logging: please leave as is for now. # Logging: please leave as is for now.
# #
######################################################################## ########################################################################
logging.formatters.f1.class = PatternFormatter logging.type = console
logging.formatters.f1.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t logging.path = $OWSEC_ROOT/logs
logging.formatters.f1.times = UTC logging.level = debug
logging.channels.c1.class = ConsoleChannel
logging.channels.c1.formatter = f1
# This is where the logs will be written. This path MUST exist
logging.channels.c2.class = FileChannel
logging.channels.c2.path = $OWSEC_ROOT/logs/log
logging.channels.c2.formatter.class = PatternFormatter
logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
logging.channels.c2.rotation = 20 M
logging.channels.c2.archive = timestamp
logging.channels.c2.purgeCount = 20
logging.channels.c3.class = ConsoleChannel
logging.channels.c3.pattern = %s: [%p] %t
# External Channel
logging.loggers.root.channel = c1
logging.loggers.root.level = debug
# Inline Channel with PatternFormatter
# logging.loggers.l1.name = logger1
# logging.loggers.l1.channel.class = ConsoleChannel
# logging.loggers.l1.channel.pattern = %s: [%p] %t
# logging.loggers.l1.level = information
# SplitterChannel
# logging.channels.splitter.class = SplitterChannel
# logging.channels.splitter.channels = l1,l2
# logging.loggers.l2.name = logger2
# logging.loggers.l2.channel = splitter

View File

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

84
src/ACLProcessor.h Normal file
View File

@@ -0,0 +1,84 @@
//
// Created by stephane bourque on 2021-11-12.
//
#ifndef OWSEC_ACLPROCESSOR_H
#define OWSEC_ACLPROCESSOR_H
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
class ACLProcessor {
public:
enum ACL_OPS {
READ,
MODIFY,
DELETE,
CREATE
};
/*
1) You cannot delete yourself
2) If you are root, you can do anything.
3) You can do anything to yourself
4) Nobody can touch a root, unless they are a root, unless it is to get information on a ROOT
5) Creation rules:
ROOT -> create anything
PARTNER -> (multi-tenant owner) admin,subs,csr,installer,noc,accounting - matches to an entity in provisioning
ADMIN -> admin-subs-csr-installer-noc-accounting
ACCOUNTING -> subs-installer-csr
*/
static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) {
// rule 1
if(User.id == Target.id && Op==DELETE)
return false;
// rule 2
if(User.userRole==SecurityObjects::ROOT)
return true;
// rule 3
if(User.id == Target.id)
return true;
// rule 4
if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
return false;
if(Op==CREATE) {
if(User.userRole==SecurityObjects::ROOT)
return true;
if(User.userRole==SecurityObjects::PARTNER && (Target.userRole==SecurityObjects::ADMIN ||
Target.userRole==SecurityObjects::SUBSCRIBER ||
Target.userRole==SecurityObjects::CSR ||
Target.userRole==SecurityObjects::INSTALLER ||
Target.userRole==SecurityObjects::NOC ||
Target.userRole==SecurityObjects::ACCOUNTING))
return true;
if(User.userRole==SecurityObjects::ADMIN &&
(Target.userRole==SecurityObjects::ADMIN ||
Target.userRole==SecurityObjects::SUBSCRIBER ||
Target.userRole==SecurityObjects::CSR ||
Target.userRole==SecurityObjects::INSTALLER ||
Target.userRole==SecurityObjects::NOC ||
Target.userRole==SecurityObjects::ACCOUNTING))
return true;
if(User.userRole==SecurityObjects::ACCOUNTING &&
(Target.userRole==SecurityObjects::SUBSCRIBER ||
Target.userRole==SecurityObjects::INSTALLER ||
Target.userRole==SecurityObjects::CSR))
return true;
return false;
}
return true;
}
private:
};
}
#endif //OWSEC_ACLPROCESSOR_H

View File

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

97
src/ActionLinkManager.cpp Normal file
View File

@@ -0,0 +1,97 @@
//
// Created by stephane bourque on 2021-11-08.
//
#include "ActionLinkManager.h"
#include "StorageService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
int ActionLinkManager::Start() {
if(!Running_)
Thr_.start(*this);
return 0;
}
void ActionLinkManager::Stop() {
if(Running_) {
Running_ = false;
Thr_.wakeUp();
Thr_.join();
}
}
void ActionLinkManager::run() {
Running_ = true ;
while(Running_) {
Poco::Thread::trySleep(2000);
if(!Running_)
break;
std::vector<SecurityObjects::ActionLink> Links;
{
std::lock_guard G(Mutex_);
StorageService()->ActionLinksDB().GetActions(Links);
}
if(Links.empty())
continue;
for(auto &i:Links) {
if(!Running_)
break;
SecurityObjects::UserInfo UInfo;
if((i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD ||
i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) && !StorageService()->UserDB().GetUserById(i.userId,UInfo)) {
StorageService()->ActionLinksDB().CancelAction(i.id);
continue;
} else if(( i.action==OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD ||
i.action==OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL) && !StorageService()->SubDB().GetUserById(i.userId,UInfo)) {
StorageService()->ActionLinksDB().CancelAction(i.id);
continue;
}
switch(i.action) {
case OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD: {
if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) {
Logger().information(Poco::format("Send password reset link to %s",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL: {
if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) {
Logger().information(Poco::format("Send email verification link to %s",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::SUB_FORGOT_PASSWORD: {
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) {
Logger().information(Poco::format("Send subscriber password reset link to %s",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
case OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL: {
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) {
Logger().information(Poco::format("Send subscriber email verification link to %s",UInfo.email));
}
StorageService()->ActionLinksDB().SentAction(i.id);
}
break;
default: {
StorageService()->ActionLinksDB().SentAction(i.id);
}
}
}
}
}
}

43
src/ActionLinkManager.h Normal file
View File

@@ -0,0 +1,43 @@
//
// Created by stephane bourque on 2021-11-08.
//
#ifndef OWSEC_ACTIONLINKMANAGER_H
#define OWSEC_ACTIONLINKMANAGER_H
#include "framework/MicroService.h"
namespace OpenWifi {
class ActionLinkManager : public SubSystemServer, Poco::Runnable {
public:
/* enum Actions {
FORGOT_PASSWORD,
VERIFY_EMAIL,
SUB_FORGOT_PASSWORD,
SUB_VERIFY_EMAIL
};
*/
static ActionLinkManager * instance() {
static auto * instance_ = new ActionLinkManager;
return instance_;
}
int Start() final;
void Stop() final;
void run();
private:
Poco::Thread Thr_;
std::atomic_bool Running_ = false;
ActionLinkManager() noexcept:
SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server")
{
}
};
inline ActionLinkManager * ActionLinkManager() { return ActionLinkManager::instance(); }
}
#endif //OWSEC_ACTIONLINKMANAGER_H

View File

@@ -11,6 +11,7 @@
#include "Poco/Net/OAuth20Credentials.h" #include "Poco/Net/OAuth20Credentials.h"
#include "Poco/JWT/Token.h" #include "Poco/JWT/Token.h"
#include "Poco/JWT/Signer.h" #include "Poco/JWT/Signer.h"
#include "Poco/StringTokenizer.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "StorageService.h" #include "StorageService.h"
@@ -21,7 +22,6 @@
#include "MFAServer.h" #include "MFAServer.h"
namespace OpenWifi { namespace OpenWifi {
class AuthService *AuthService::instance_ = nullptr;
AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) { AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) {
switch (C) { switch (C) {
@@ -45,105 +45,167 @@ namespace OpenWifi {
int AuthService::Start() { int AuthService::Start() {
Signer_.setRSAKey(MicroService::instance().Key()); Signer_.setRSAKey(MicroService::instance().Key());
Signer_.addAllAlgorithms(); Signer_.addAllAlgorithms();
Logger_.notice("Starting..."); Logger().notice("Starting...");
Secure_ = MicroService::instance().ConfigGetBool("authentication.enabled",true);
DefaultPassword_ = MicroService::instance().ConfigGetString("authentication.default.password","");
DefaultUserName_ = MicroService::instance().ConfigGetString("authentication.default.username","");
Mechanism_ = MicroService::instance().ConfigGetString("authentication.service.type","internal");
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html");
PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html");
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("subscriber.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
SubAccessPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.access", "/wwwassets/access_policy.html");
SubPasswordPolicy_ = MicroService::instance().ConfigPath("subscriber.policy.password", "/wwwassets/password_policy.html");
return 0; return 0;
} }
void AuthService::Stop() { void AuthService::Stop() {
Logger_.notice("Stopping..."); Logger().notice("Stopping...");
} }
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
{ {
if(!Secure_) std::lock_guard Guard(Mutex_);
return true; Expired = false;
std::lock_guard Guard(Mutex_);
std::string CallToken;
try { try {
Poco::Net::OAuth20Credentials Auth(Request); std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request);
if (Auth.getScheme() == "Bearer") { if (Auth.getScheme() == "Bearer") {
CallToken = Auth.getBearerToken(); CallToken = Auth.getBearerToken();
}
} catch(const Poco::Exception &E) {
}
if(!CallToken.empty()) {
if(StorageService()->IsTokenRevoked(CallToken))
return false;
auto Client = UserCache_.find(CallToken);
if( Client == UserCache_.end() )
return ValidateToken(CallToken, CallToken, UInfo);
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken;
UInfo = Client->second ;
return true;
} }
UserCache_.erase(CallToken);
StorageService()->RevokeToken(CallToken);
return false;
}
if(CallToken.empty()) {
return false;
}
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
std::string UserId;
if(StorageService()->UserTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (WT.created_ + WT.expires_in_) < time(nullptr);
if(StorageService()->UserDB().GetUserById(UserId,UInfo.userinfo)) {
UInfo.webtoken = WT;
SessionToken = CallToken;
return true;
}
}
return false;
} catch(const Poco::Exception &E) {
Logger().log(E);
}
return false; return false;
} }
bool AuthService::DeleteUserFromCache(const std::string &UserName) { bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
std::lock_guard Guard(Mutex_); {
std::lock_guard Guard(Mutex_);
for(auto i=UserCache_.begin();i!=UserCache_.end();) { Expired = false;
if (i->second.userinfo.email==UserName) { try {
Logout(i->first, false); std::string CallToken;
i = UserCache_.erase(i); Poco::Net::OAuth20Credentials Auth(Request);
} else { if (Auth.getScheme() == "Bearer") {
++i; CallToken = Auth.getBearerToken();
} }
if(CallToken.empty()) {
return false;
}
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
std::string UserId;
if(StorageService()->SubTokenDB().GetToken(CallToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (WT.created_ + WT.expires_in_) < time(nullptr);
if(StorageService()->SubDB().GetUserById(UserId,UInfo.userinfo)) {
UInfo.webtoken = WT;
SessionToken = CallToken;
return true;
}
}
return false;
} catch(const Poco::Exception &E) {
Logger().log(E);
} }
return true; return false;
}
void AuthService::RevokeToken(std::string & Token) {
StorageService()->UserTokenDB().RevokeToken(Token);
}
void AuthService::RevokeSubToken(std::string & Token) {
StorageService()->SubTokenDB().RevokeToken(Token);
}
bool AuthService::DeleteUserFromCache(const std::string &Id) {
return StorageService()->UserTokenDB().DeleteRecordsFromCache("userName",Id);
}
bool AuthService::DeleteSubUserFromCache(const std::string &Id) {
return StorageService()->SubTokenDB().DeleteRecordsFromCache("userName",Id);
} }
bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) { 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) { bool AuthService::ValidatePassword(const std::string &Password) {
return std::regex_match(Password, PasswordValidation_); return std::regex_match(Password, PasswordValidation_);
} }
void AuthService::Logout(const std::string &token, bool EraseFromCache) { bool AuthService::ValidateSubPassword(const std::string &Password) {
return std::regex_match(Password, SubPasswordValidation_);
}
void AuthService::RemoveTokenSystemWide(const std::string &token) {
try {
if(KafkaManager()->Enabled()) {
Poco::JSON::Object Obj;
Obj.set("event", "remove-token");
Obj.set("id", MicroService::instance().ID());
Obj.set("token", token);
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(),
ResultText.str(),
false);
}
} catch (const Poco::Exception &E) {
Logger().log(E);
}
}
void AuthService::Logout(const std::string &Token, bool EraseFromCache) {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
if(EraseFromCache) try {
UserCache_.erase(token); auto tToken{Token};
StorageService()->UserTokenDB().DeleteRecord("token",tToken);
StorageService()->LoginDB().AddLogout(Token);
} catch (const Poco::Exception &E) {
Logger().log(E);
}
}
void AuthService::SubLogout(const std::string &Token, bool EraseFromCache) {
std::lock_guard Guard(Mutex_);
try { try {
Poco::JSON::Object Obj; auto tToken{Token};
Obj.set("event", "remove-token"); StorageService()->SubTokenDB().DeleteRecord("token",tToken);
Obj.set("id", MicroService::instance().ID()); StorageService()->SubLoginDB().AddLogout(Token);
Obj.set("token", token);
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText);
std::string Tmp{token};
StorageService()->RevokeToken(Tmp);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(),
false);
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
Logger_.log(E); Logger().log(E);
} }
} }
[[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) { [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) {
std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr))); std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)) + ":" + std::to_string(rand()));
HMAC_.update(Identity); HMAC_.update(Identity);
return Poco::DigestEngine::digestToHex(HMAC_.digest()); return Poco::DigestEngine::digestToHex(HMAC_.digest());
} }
@@ -168,28 +230,6 @@ namespace OpenWifi {
return JWT; return JWT;
} }
bool AuthService::ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
std::lock_guard Guard(Mutex_);
try {
auto E = UserCache_.find(SessionToken);
if(E == UserCache_.end()) {
if(StorageService()->GetToken(SessionToken,UInfo)) {
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) {
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
} else {
UInfo = E->second;
return true;
}
} catch (const Poco::Exception &E ) {
Logger_.log(E);
}
return false;
}
void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
@@ -200,50 +240,170 @@ namespace OpenWifi {
UInfo.webtoken.expires_in_ = TokenAging_ ; UInfo.webtoken.expires_in_ = TokenAging_ ;
UInfo.webtoken.idle_timeout_ = 5 * 60; UInfo.webtoken.idle_timeout_ = 5 * 60;
UInfo.webtoken.token_type_ = "Bearer"; UInfo.webtoken.token_type_ = "Bearer";
UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME); UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME); UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,CUSTOM); UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM);
UInfo.webtoken.created_ = time(nullptr); UInfo.webtoken.created_ = time(nullptr);
UInfo.webtoken.username_ = UserName; UInfo.webtoken.username_ = UserName;
UInfo.webtoken.errorCode = 0; UInfo.webtoken.errorCode = 0;
UInfo.webtoken.userMustChangePassword = false; UInfo.webtoken.userMustChangePassword = false;
UserCache_[UInfo.webtoken.access_token_] = UInfo; StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id);
StorageService()->SetLastLogin(UInfo.userinfo.Id); StorageService()->UserTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_,
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_, UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_); UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
StorageService()->LoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ );
}
void AuthService::CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
{
std::lock_guard Guard(Mutex_);
SecurityObjects::AclTemplate ACL;
ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
UInfo.webtoken.acl_template_ = ACL;
UInfo.webtoken.expires_in_ = TokenAging_ ;
UInfo.webtoken.idle_timeout_ = 5 * 60;
UInfo.webtoken.token_type_ = "Bearer";
UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.id,USERNAME);
UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.id,CUSTOM);
UInfo.webtoken.created_ = time(nullptr);
UInfo.webtoken.username_ = UserName;
UInfo.webtoken.errorCode = 0;
UInfo.webtoken.userMustChangePassword = false;
StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
StorageService()->SubTokenDB().AddToken(UInfo.userinfo.id, UInfo.webtoken.access_token_,
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
StorageService()->SubLoginDB().AddLogin(UInfo.userinfo.id, UInfo.userinfo.email,UInfo.webtoken.access_token_ );
} }
bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword); std::lock_guard G(Mutex_);
for (auto const &i:UInfo.lastPasswords) {
if (i == NewPasswordHash) { Poco::toLowerInPlace(UInfo.email);
return false; for (const auto &i:UInfo.lastPasswords) {
auto Tokens = Poco::StringTokenizer(i,"|");
if(Tokens.count()==2) {
const auto & Salt = Tokens[0];
for(const auto &j:UInfo.lastPasswords) {
auto OldTokens = Poco::StringTokenizer(j,"|");
if(OldTokens.count()==2) {
SHA2_.update(Salt+NewPassword+UInfo.email);
if(OldTokens[1]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
} else {
SHA2_.update(NewPassword+UInfo.email);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return false;
} }
} }
if(UInfo.lastPasswords.size()==HowManyOldPassword_) { if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
} }
UInfo.lastPasswords.push_back(NewPasswordHash);
UInfo.currentPassword = NewPasswordHash; auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
UInfo.lastPasswords.push_back(NewHash);
UInfo.currentPassword = NewHash;
UInfo.changePassword = false; UInfo.changePassword = false;
return true; return true;
} }
AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ) bool AuthService::SetSubPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
std::lock_guard G(Mutex_);
Poco::toLowerInPlace(UInfo.email);
for (const auto &i:UInfo.lastPasswords) {
auto Tokens = Poco::StringTokenizer(i,"|");
if(Tokens.count()==2) {
const auto & Salt = Tokens[0];
for(const auto &j:UInfo.lastPasswords) {
auto OldTokens = Poco::StringTokenizer(j,"|");
if(OldTokens.count()==2) {
SHA2_.update(Salt+NewPassword+UInfo.email);
if(OldTokens[1]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
} else {
SHA2_.update(NewPassword+UInfo.email);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return false;
}
}
if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
}
auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
UInfo.lastPasswords.push_back(NewHash);
UInfo.currentPassword = NewHash;
UInfo.changePassword = false;
return true;
}
static std::string GetMeSomeSalt() {
auto start = std::chrono::high_resolution_clock::now();
return std::to_string(start.time_since_epoch().count());
}
std::string AuthService::ComputeNewPasswordHash(const std::string &UserName, const std::string &Password) {
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Salt = GetMeSomeSalt();
SHA2_.update(Salt + Password + UName );
return Salt + "|" + Utils::ToHex(SHA2_.digest());
}
bool AuthService::ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
std::lock_guard G(Mutex_);
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Tokens = Poco::StringTokenizer(StoredPassword,"|");
if(Tokens.count()==1) {
SHA2_.update(Password+UName);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return true;
} else if (Tokens.count()==2) {
SHA2_.update(Tokens[0]+Password+UName);
if(Tokens[1]==Utils::ToHex(SHA2_.digest()))
return true;
}
return false;
}
bool AuthService::ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
std::lock_guard G(Mutex_);
std::string UName = Poco::trim(Poco::toLower(UserName));
auto Tokens = Poco::StringTokenizer(StoredPassword,"|");
if(Tokens.count()==1) {
SHA2_.update(Password+UName);
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
return true;
} else if (Tokens.count()==2) {
SHA2_.update(Tokens[0]+Password+UName);
if(Tokens[1]==Utils::ToHex(SHA2_.digest()))
return true;
}
return false;
}
UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired )
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
SecurityObjects::AclTemplate ACL;
Poco::toLowerInPlace(UserName); Poco::toLowerInPlace(UserName);
auto PasswordHash = ComputePasswordHash(UserName, Password);
if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { if(StorageService()->UserDB().GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) { if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION; return USERNAME_PENDING_VERIFICATION;
} }
if(PasswordHash != UInfo.userinfo.currentPassword) { if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
return INVALID_CREDENTIALS; return INVALID_CREDENTIALS;
} }
@@ -263,61 +423,89 @@ namespace OpenWifi {
} }
UInfo.userinfo.lastPasswordChange = std::time(nullptr); UInfo.userinfo.lastPasswordChange = std::time(nullptr);
UInfo.userinfo.changePassword = false; UInfo.userinfo.changePassword = false;
StorageService()->UpdateUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.Id,UInfo.userinfo); UInfo.userinfo.modified = std::time(nullptr);
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. // so we have a good password, password up date has taken place if need be, now generate the token.
UInfo.userinfo.lastLogin=std::time(nullptr); UInfo.userinfo.lastLogin=std::time(nullptr);
StorageService()->SetLastLogin(UInfo.userinfo.Id); StorageService()->UserDB().SetLastLogin(UInfo.userinfo.id);
CreateToken(UserName, UInfo ); CreateToken(UserName, UInfo );
return SUCCESS; return SUCCESS;
} }
if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_)
{
ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
UInfo.webtoken.acl_template_ = ACL;
UInfo.userinfo.email = DefaultUserName_;
UInfo.userinfo.currentPassword = DefaultPassword_;
UInfo.userinfo.name = DefaultUserName_;
UInfo.userinfo.userRole = SecurityObjects::ROOT;
CreateToken(UserName, UInfo );
return SUCCESS;
}
return INVALID_CREDENTIALS; return INVALID_CREDENTIALS;
} }
std::string AuthService::ComputePasswordHash(const std::string &UserName, const std::string &Password) { UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired )
std::string UName = Poco::trim(Poco::toLower(UserName)); {
SHA2_.update(Password + UName); std::lock_guard Guard(Mutex_);
return Utils::ToHex(SHA2_.digest());
Poco::toLowerInPlace(UserName);
if(StorageService()->SubDB().GetUserByEmail(UserName,UInfo.userinfo)) {
if(UInfo.userinfo.waitingForEmailCheck) {
return USERNAME_PENDING_VERIFICATION;
}
if(!ValidateSubPasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
return INVALID_CREDENTIALS;
}
if(UInfo.userinfo.changePassword && NewPassword.empty()) {
UInfo.webtoken.userMustChangePassword = true ;
return PASSWORD_CHANGE_REQUIRED;
}
if(!NewPassword.empty() && !ValidateSubPassword(NewPassword)) {
return PASSWORD_INVALID;
}
if(UInfo.userinfo.changePassword || !NewPassword.empty()) {
if(!SetSubPassword(NewPassword,UInfo.userinfo)) {
UInfo.webtoken.errorCode = 1;
return PASSWORD_ALREADY_USED;
}
UInfo.userinfo.lastPasswordChange = std::time(nullptr);
UInfo.userinfo.changePassword = false;
UInfo.userinfo.modified = std::time(nullptr);
StorageService()->SubDB().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=std::time(nullptr);
StorageService()->SubDB().SetLastLogin(UInfo.userinfo.id);
CreateSubToken(UserName, UInfo );
return SUCCESS;
}
return INVALID_CREDENTIALS;
} }
bool AuthService::SendEmailToUser(std::string &Email, EMAIL_REASON Reason) { bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(StorageService()->GetUserByEmail(Email,UInfo)) { if(StorageService()->UserDB().GetUserByEmail(Email,UInfo)) {
switch (Reason) { switch (Reason) {
case FORGOT_PASSWORD: { case FORGOT_PASSWORD: {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg"; Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "Password reset link"; Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] = Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
} }
break; break;
case EMAIL_VERIFICATION: { case EMAIL_VERIFICATION: {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = "logo.jpg"; Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "EMail Address Verification"; Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] = Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true; UInfo.waitingForEmailCheck = true;
} }
@@ -326,33 +514,113 @@ namespace OpenWifi {
default: default:
break; break;
} }
return true;
}
return false;
}
bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
SecurityObjects::UserInfo UInfo;
if(StorageService()->SubDB().GetUserByEmail(Email,UInfo)) {
switch (Reason) {
case FORGOT_PASSWORD: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "Password reset link";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
}
break;
case EMAIL_VERIFICATION: {
MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.email;
Attrs[LOGO] = GetLogoAssetURI();
Attrs[SUBJECT] = "EMail Address Verification";
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
UInfo.waitingForEmailCheck = true;
}
break;
default:
break;
}
return true;
} }
return false; return false;
} }
bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
MessageAttributes Attrs; SecurityObjects::ActionLink A;
Attrs[RECIPIENT_EMAIL] = UInfo.email; A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
Attrs[LOGO] = "logo.jpg"; A.userId = UInfo.email;
Attrs[SUBJECT] = "EMail Address Verification"; A.id = MicroService::CreateUUID();
Attrs[ACTION_LINK] = A.created = std::time(nullptr);
MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ; A.expires = A.created + 24*60*60;
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); A.userAction = true;
StorageService()->ActionLinksDB().CreateAction(A);
UInfo.waitingForEmailCheck = true; UInfo.waitingForEmailCheck = true;
return true; return true;
} }
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo) { bool AuthService::VerifySubEmail(SecurityObjects::UserInfo &UInfo) {
std::lock_guard G(Mutex_); SecurityObjects::ActionLink A;
auto It = UserCache_.find(Token);
if(It==UserCache_.end()) A.action = OpenWifi::SecurityObjects::LinkActions::SUB_VERIFY_EMAIL;
return false; A.userId = UInfo.email;
WebToken = It->second.webtoken; A.id = MicroService::CreateUUID();
UserInfo = It->second.userinfo; A.created = std::time(nullptr);
A.expires = A.created + 24*60*60;
A.userAction = false;
StorageService()->ActionLinksDB().CreateAction(A);
UInfo.waitingForEmailCheck = true;
return true; return true;
} }
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
std::lock_guard G(Mutex_);
Expired = false;
std::string TToken{Token}, UserId;
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
if(StorageService()->UserTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr);
if(StorageService()->UserDB().GetUserById(UserId,UserInfo)) {
WebToken = WT;
return true;
}
return false;
}
return IsValidSubToken(Token, WebToken, UserInfo, Expired);
}
bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
std::lock_guard G(Mutex_);
Expired = false;
std::string TToken{Token}, UserId;
SecurityObjects::WebToken WT;
uint64_t RevocationDate=0;
if(StorageService()->SubTokenDB().GetToken(TToken, WT, UserId, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (WT.created_ + WT.expires_in_) < std::time(nullptr);
if(StorageService()->SubDB().GetUserById(UserId,UserInfo)) {
WebToken = WT;
return true;
}
return false;
}
return false;
}
} // end of namespace } // end of namespace

View File

@@ -18,6 +18,7 @@
#include "Poco/SHA2Engine.h" #include "Poco/SHA2Engine.h"
#include "Poco/Crypto/DigestEngine.h" #include "Poco/Crypto/DigestEngine.h"
#include "Poco/HMACEngine.h" #include "Poco/HMACEngine.h"
#include "Poco/ExpireLRUCache.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
@@ -35,16 +36,6 @@ namespace OpenWifi{
CUSTOM CUSTOM
}; };
enum AUTH_ERROR {
SUCCESS,
PASSWORD_CHANGE_REQUIRED,
INVALID_CREDENTIALS,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR
};
enum EMAIL_REASON { enum EMAIL_REASON {
FORGOT_PASSWORD, FORGOT_PASSWORD,
EMAIL_VERIFICATION EMAIL_VERIFICATION
@@ -53,52 +44,88 @@ namespace OpenWifi{
static ACCESS_TYPE IntToAccessType(int C); static ACCESS_TYPE IntToAccessType(int C);
static int AccessTypeToInt(ACCESS_TYPE T); static int AccessTypeToInt(ACCESS_TYPE T);
static AuthService *instance() { static auto instance() {
if (instance_ == nullptr) { static auto instance_ = new AuthService;
instance_ = new AuthService;
}
return instance_; return instance_;
} }
int Start() override; int Start() override;
void Stop() override; void Stop() override;
[[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ); [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
[[nodiscard]] AUTH_ERROR Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ); [[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); void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo );
[[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
void Logout(const std::string &token, bool EraseFromCache=true); void Logout(const std::string &token, bool EraseFromCache=true);
bool ValidatePassword(const std::string &pwd); [[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
[[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
[[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;};
void SubLogout(const std::string &token, bool EraseFromCache=true);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo); void RemoveTokenSystemWide(const std::string &token);
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
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]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type); [[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type); [[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
[[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::WebToken & UserInfo );
[[nodiscard]] std::string ComputePasswordHash(const std::string &UserName, const std::string &Password); [[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]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
[[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
[[nodiscard]] 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 VerifyEmail(SecurityObjects::UserInfo &UInfo);
[[nodiscard]] static bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason); [[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
[[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
[[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
bool DeleteUserFromCache(const std::string &UserName);
bool DeleteSubUserFromCache(const std::string &UserName);
void RevokeToken(std::string & Token);
void RevokeSubToken(std::string & Token);
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
}
[[nodiscard]] static inline const std::string GetLogoAssetFileName() {
return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
}
inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; }
private: private:
static AuthService *instance_;
bool Secure_ = false ;
std::string DefaultUserName_;
std::string DefaultPassword_;
std::string Mechanism_;
Poco::JWT::Signer Signer_; Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_; Poco::SHA2Engine SHA2_;
SecurityObjects::UserInfoCache UserCache_;
std::string PasswordValidationStr_; std::string AccessPolicy_;
std::regex PasswordValidation_; std::string PasswordPolicy_;
uint64_t TokenAging_ = 30 * 24 * 60 * 60; std::string SubAccessPolicy_;
std::string SubPasswordPolicy_;
std::string PasswordValidationStr_;
std::string SubPasswordValidationStr_;
std::regex PasswordValidation_;
std::regex SubPasswordValidation_;
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
uint64_t HowManyOldPassword_=5; uint64_t HowManyOldPassword_=5;
class SHA256Engine : public Poco::Crypto::DigestEngine class SHA256Engine : public Poco::Crypto::DigestEngine
@@ -125,10 +152,13 @@ namespace OpenWifi{
} }
}; };
inline AuthService * AuthService() { return AuthService::instance(); } inline auto AuthService() { return AuthService::instance(); }
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) { [[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired, bool Sub ) {
return AuthService()->IsAuthorized(Request, SessionToken, UInfo ); if(Sub)
return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired );
else
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
} }
} // end of namespace } // end of namespace

View File

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

View File

@@ -20,7 +20,6 @@
#include "Poco/Crypto/CipherFactory.h" #include "Poco/Crypto/CipherFactory.h"
#include "Poco/Crypto/Cipher.h" #include "Poco/Crypto/Cipher.h"
#include "framework/OpenWifiTypes.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
namespace OpenWifi { namespace OpenWifi {
@@ -44,13 +43,9 @@ namespace OpenWifi {
void initialize(); void initialize();
static Daemon *instance(); static Daemon *instance();
inline const std::string & AssetDir() { return AssetDir_; } inline const std::string & AssetDir() { return AssetDir_; }
inline const std::string & GetPasswordPolicy() const { return PasswordPolicy_; }
inline const std::string & GetAccessPolicy() const { return AccessPolicy_; }
private: private:
static Daemon *instance_; static Daemon *instance_;
std::string AssetDir_; std::string AssetDir_;
std::string PasswordPolicy_;
std::string AccessPolicy_;
}; };
inline Daemon * Daemon() { return Daemon::instance(); } inline Daemon * Daemon() { return Daemon::instance(); }

View File

@@ -6,11 +6,11 @@
#include "SMSSender.h" #include "SMSSender.h"
#include "SMTPMailerService.h" #include "SMTPMailerService.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "AuthService.h"
#include "TotpCache.h"
namespace OpenWifi { namespace OpenWifi {
class MFAServer * MFAServer::instance_ = nullptr;
int MFAServer::Start() { int MFAServer::Start() {
return 0; return 0;
} }
@@ -27,11 +27,12 @@ namespace OpenWifi {
return false; return false;
std::string Challenge = MakeChallenge(); std::string Challenge = MakeChallenge();
std::string uuid = MicroService::instance().CreateUUID(); std::string uuid = MicroService::CreateUUID();
uint64_t Created = std::time(nullptr); uint64_t Created = std::time(nullptr);
ChallengeStart.set("uuid",uuid); ChallengeStart.set("uuid",uuid);
ChallengeStart.set("created", Created); ChallengeStart.set("created", Created);
ChallengeStart.set("question", "mfa challenge");
ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method); ChallengeStart.set("method", UInfo.userinfo.userTypeProprietaryInfo.mfa.method);
Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method }; Cache_[uuid] = MFACacheEntry{ .UInfo = UInfo, .Answer=Challenge, .Created=Created, .Method=UInfo.userinfo.userTypeProprietaryInfo.mfa.method };
@@ -39,18 +40,18 @@ namespace OpenWifi {
} }
bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) { bool MFAServer::SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge) {
if(Method=="sms" && SMSSender()->Enabled() && !UInfo.userinfo.userTypeProprietaryInfo.mobiles.empty()) { 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."; 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); return SMSSender()->Send(UInfo.userinfo.userTypeProprietaryInfo.mobiles[0].number, Message);
} } else if(Method==MFAMETHODS::EMAIL && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) {
MessageAttributes Attrs; MessageAttributes Attrs;
Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email;
Attrs[LOGO] = "logo.jpg"; Attrs[LOGO] = AuthService::GetLogoAssetURI();
Attrs[SUBJECT] = "Login validation code"; Attrs[SUBJECT] = "Login validation code";
Attrs[CHALLENGE_CODE] = Challenge; Attrs[CHALLENGE_CODE] = Challenge;
return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs);
} else if(Method==MFAMETHODS::AUTHENTICATOR && !UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret.empty()) {
return true;
} }
return false; return false;
@@ -72,11 +73,17 @@ namespace OpenWifi {
auto uuid = ChallengeResponse->get("uuid").toString(); auto uuid = ChallengeResponse->get("uuid").toString();
auto Hint = Cache_.find(uuid); auto Hint = Cache_.find(uuid);
if(Hint == end(Cache_)) if(Hint == end(Cache_)) {
return false; return false;
}
auto answer = ChallengeResponse->get("answer").toString(); auto answer = ChallengeResponse->get("answer").toString();
if(Hint->second.Answer!=answer) { std::string Expecting;
if(Hint->second.Method==MFAMETHODS::AUTHENTICATOR) {
if(!TotpCache()->ValidateCode(Hint->second.UInfo.userinfo.userTypeProprietaryInfo.authenticatorSecret,answer, Expecting)) {
return false;
}
} else if(Hint->second.Answer!=answer) {
return false; return false;
} }
@@ -86,12 +93,15 @@ namespace OpenWifi {
} }
bool MFAServer::MethodEnabled(const std::string &Method) { bool MFAServer::MethodEnabled(const std::string &Method) {
if(Method=="sms") if(Method==MFAMETHODS::SMS)
return SMSSender()->Enabled(); return SMSSender()->Enabled();
if(Method=="email") if(Method==MFAMETHODS::EMAIL)
return SMTPMailerService()->Enabled(); return SMTPMailerService()->Enabled();
if(Method==MFAMETHODS::AUTHENTICATOR)
return true;
return false; return false;
} }

View File

@@ -10,6 +10,17 @@
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi { namespace OpenWifi {
namespace MFAMETHODS {
inline const static std::string SMS{"sms"};
inline const static std::string EMAIL{"email"};
inline const static std::string AUTHENTICATOR{"authenticator"};
inline const static std::vector<std::string> Methods{ SMS, EMAIL, AUTHENTICATOR };
inline bool Validate(const std::string &M) {
return std::find(cbegin(Methods), cend(Methods),M)!=Methods.end();
}
}
struct MFACacheEntry { struct MFACacheEntry {
SecurityObjects::UserInfoAndPolicy UInfo; SecurityObjects::UserInfoAndPolicy UInfo;
std::string Answer; std::string Answer;
@@ -17,31 +28,31 @@ namespace OpenWifi {
std::string Method; std::string Method;
}; };
typedef std::map<std::string,MFACacheEntry> MFAChallengeCache; typedef std::map<std::string,MFACacheEntry> MFAChallengeCache;
class MFAServer : public SubSystemServer{ class MFAServer : public SubSystemServer{
public: public:
int Start() override; int Start() override;
void Stop() override; void Stop() override;
static MFAServer *instance() { static auto instance() {
if (instance_ == nullptr) { static auto instance_ = new MFAServer;
instance_ = new MFAServer;
}
return instance_; return instance_;
} }
bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge);
bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo);
bool MethodEnabled(const std::string &Method); static bool MethodEnabled(const std::string &Method);
bool ResendCode(const std::string &uuid); bool ResendCode(const std::string &uuid);
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() { static inline std::string MakeChallenge() {
return std::to_string(rand() % 999999); char buf[16];
std::sprintf(buf,"%06llu",MicroService::instance().Random(1,999999));
return buf;
} }
private: private:
static MFAServer * instance_;
MFAChallengeCache Cache_; MFAChallengeCache Cache_;
MFAServer() noexcept: MFAServer() noexcept:
SubSystemServer("MFServer", "MFA-SVR", "mfa") SubSystemServer("MFServer", "MFA-SVR", "mfa")
@@ -51,7 +62,7 @@ namespace OpenWifi {
void CleanCache(); void CleanCache();
}; };
inline MFAServer & MFAServer() { return *MFAServer::instance(); } inline auto MFAServer() { return MFAServer::instance(); }
} }
#endif //OWSEC_MFASERVER_H #endif //OWSEC_MFASERVER_H

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ namespace OpenWifi {
if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) { if(SMSSender()->StartValidation(Number, UserInfo_.userinfo.email)) {
return OK(); return OK();
} }
return BadRequest("SMS could not be sent to validate device, try later or change the phone number."); return BadRequest(RESTAPI::Errors::SMSCouldNotBeSentRetry);
} }
std::string Code; std::string Code;
@@ -30,7 +30,13 @@ namespace OpenWifi {
if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) { if(SMSSender()->CompleteValidation(Number, Code, UserInfo_.userinfo.email)) {
return OK(); return OK();
} }
return BadRequest("Code and number could not be validated"); return BadRequest(RESTAPI::Errors::SMSCouldNotValidate);
}
if( UserInfo_.userinfo.userRole!=SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole!=SecurityObjects::PARTNER &&
UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights,ACCESS_DENIED);
} }
if (Obj->has("to") && if (Obj->has("to") &&
@@ -41,7 +47,7 @@ namespace OpenWifi {
if(SMSSender()->Send(PhoneNumber, Text)) if(SMSSender()->Send(PhoneNumber, Text))
return OK(); return OK();
return InternalError("SMS Message could not be sent."); return InternalError(RESTAPI::Errors::SMSCouldNotBeSentRetry);
} }
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
} }

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,129 @@
//
// Created by stephane bourque on 2021-12-01.
//
#include "RESTAPI_submfa_handler.h"
#include "StorageService.h"
#include "SMSSender.h"
namespace OpenWifi {
void RESTAPI_submfa_handler::DoGet() {
SecurityObjects::UserInfo User;
// std::cout << "submfa get " << UserInfo_.userinfo.Id << " user:" << UserInfo_.userinfo.email << std::endl;
if (StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id,User)) {
Poco::JSON::Object Answer;
SecurityObjects::SubMfaConfig MFC;
MFC.id = User.id;
if(User.userTypeProprietaryInfo.mfa.enabled) {
if(User.userTypeProprietaryInfo.mfa.method == "sms") {
MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
MFC.type = "sms";
} else if(User.userTypeProprietaryInfo.mfa.method == "email") {
MFC.email = User.email;
MFC.type = "email";
}
} else {
MFC.type = "disabled";
}
MFC.to_json(Answer);
return ReturnObject(Answer);
}
NotFound();
}
void RESTAPI_submfa_handler::DoPut() {
try {
auto Body = ParseStream();
SecurityObjects::SubMfaConfig MFC;
if (!MFC.from_json(Body)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
if (MFC.type == "disabled") {
SecurityObjects::UserInfo User;
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
User.userTypeProprietaryInfo.mfa.enabled = false;
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
Poco::JSON::Object Answer;
MFC.to_json(Answer);
return ReturnObject(Answer);
} else if (MFC.type == "email") {
SecurityObjects::UserInfo User;
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
User.userTypeProprietaryInfo.mfa.enabled = true;
User.userTypeProprietaryInfo.mfa.method = "email";
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
MFC.sms = MFC.sms;
MFC.type = "email";
MFC.email = UserInfo_.userinfo.email;
MFC.id = MicroService::instance().CreateUUID();
Poco::JSON::Object Answer;
MFC.to_json(Answer);
return ReturnObject(Answer);
} else if (MFC.type == "sms") {
if (GetBoolParameter("startValidation", false)) {
if (MFC.sms.empty()) {
return BadRequest("Missing phone number");
}
if (SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
return OK();
} else {
return InternalError("SMS could not be sent. Verify the number or try again later.");
}
} else if (GetBoolParameter("completeValidation", false)) {
auto ChallengeCode = GetParameter("challengeCode", "");
if (ChallengeCode.empty()) {
return BadRequest("Missing 'challengeCode'");
}
if (MFC.sms.empty()) {
return BadRequest("Missing phone number");
}
if (SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) {
SecurityObjects::UserInfo User;
StorageService()->SubDB().GetUserById(UserInfo_.userinfo.id, User);
User.userTypeProprietaryInfo.mfa.enabled = true;
User.userTypeProprietaryInfo.mfa.method = "sms";
SecurityObjects::MobilePhoneNumber PhoneNumber;
PhoneNumber.number = MFC.sms;
PhoneNumber.primary = true;
PhoneNumber.verified = true;
User.userTypeProprietaryInfo.mobiles.clear();
User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email, UserInfo_.userinfo.id, User);
MFC.sms = MFC.sms;
MFC.type = "sms";
MFC.email = UserInfo_.userinfo.email;
MFC.id = MicroService::instance().CreateUUID();
Poco::JSON::Object Answer;
MFC.to_json(Answer);
return ReturnObject(Answer);
} else {
return InternalError("SMS could not be sent. Verify the number or try again later.");
}
}
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,259 @@
//
// Created by stephane bourque on 2021-11-30.
//
#include "RESTAPI_subuser_handler.h"
#include "StorageService.h"
#include "framework/RESTAPI_errors.h"
#include "SMSSender.h"
#include "ACLProcessor.h"
#include "AuthService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
#include "MFAServer.h"
#include "TotpCache.h"
namespace OpenWifi {
void RESTAPI_subuser_handler::DoGet() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
Poco::toLowerInPlace(Id);
std::string Arg;
SecurityObjects::UserInfo UInfo;
if(HasParameter("byEmail",Arg) && Arg=="true") {
if(!StorageService()->SubDB().GetUserByEmail(Id,UInfo)) {
return NotFound();
}
} else if(!StorageService()->SubDB().GetUserById(Id,UInfo)) {
return NotFound();
}
Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, UInfo);
UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
}
void RESTAPI_subuser_handler::DoDelete() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
SecurityObjects::UserInfo TargetUser;
if(!StorageService()->SubDB().GetUserById(Id,TargetUser)) {
return NotFound();
}
if(TargetUser.userRole != SecurityObjects::SUBSCRIBER) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
if(!ACLProcessor::Can(UserInfo_.userinfo, TargetUser,ACLProcessor::DELETE)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(!StorageService()->SubDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
return NotFound();
}
AuthService()->DeleteSubUserFromCache(Id);
StorageService()->SubTokenDB().RevokeAllTokens(TargetUser.email);
StorageService()->SubPreferencesDB().DeleteRecord("id", Id);
StorageService()->SubAvatarDB().DeleteRecord("id", Id);
Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
OK();
}
void RESTAPI_subuser_handler::DoPost() {
std::string Id = GetBinding("id", "");
if(Id!="0") {
return BadRequest(RESTAPI::Errors::IdMustBe0);
}
SecurityObjects::UserInfo NewUser;
RESTAPI_utils::from_request(NewUser,*Request);
if(NewUser.userRole == SecurityObjects::UNKNOWN || NewUser.userRole != SecurityObjects::SUBSCRIBER) {
return BadRequest(RESTAPI::Errors::EntityMustExist);
}
if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Poco::toLowerInPlace(NewUser.email);
if(!Utils::ValidEMailAddress(NewUser.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
}
if(!NewUser.currentPassword.empty()) {
if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
return BadRequest(RESTAPI::Errors::InvalidPassword);
}
}
if(NewUser.name.empty())
NewUser.name = NewUser.email;
// You cannot enable MFA during user creation
NewUser.userTypeProprietaryInfo.mfa.enabled = false;
NewUser.userTypeProprietaryInfo.mfa.method = "";
NewUser.userTypeProprietaryInfo.mobiles.clear();
NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
if(!StorageService()->SubDB().CreateUser(NewUser.email, NewUser)) {
Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email));
return BadRequest(RESTAPI::Errors::RecordNotCreated);
}
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifySubEmail(NewUser))
Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email));
StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
}
if(!StorageService()->SubDB().GetUserByEmail(NewUser.email, NewUser)) {
Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email));
return NotFound();
}
Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, NewUser);
NewUser.to_json(UserInfoObject);
ReturnObject(UserInfoObject);
Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email));
}
void RESTAPI_subuser_handler::DoPut() {
std::string Id = GetBinding("id", "");
if(Id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUserID);
}
SecurityObjects::UserInfo Existing;
if(!StorageService()->SubDB().GetUserById(Id,Existing)) {
return NotFound();
}
if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
SecurityObjects::UserInfo NewUser;
auto RawObject = ParseStream();
if(!NewUser.from_json(RawObject)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}
// some basic validations
if(RawObject->has("userRole") &&
(SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN ||
SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::SUBSCRIBER)) {
return BadRequest(RESTAPI::Errors::InvalidUserRole);
}
// The only valid things to change are: changePassword, name,
AssignIfPresent(RawObject,"name", Existing.name);
AssignIfPresent(RawObject,"description", Existing.description);
AssignIfPresent(RawObject,"owner", Existing.owner);
AssignIfPresent(RawObject,"location", Existing.location);
AssignIfPresent(RawObject,"locale", Existing.locale);
AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole")) {
auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
if(NewRole!=Existing.userRole) {
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(Id==UserInfo_.userinfo.id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Existing.userRole = NewRole;
}
}
if(RawObject->has("notes")) {
SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note};
Existing.notes.push_back(ii);
}
}
if(RawObject->has("currentPassword")) {
if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
return BadRequest(RESTAPI::Errors::InvalidPassword);
}
if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) {
return BadRequest(RESTAPI::Errors::PasswordRejected);
}
}
if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifySubEmail(Existing))
Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email));
}
if(RawObject->has("userTypeProprietaryInfo")) {
if(NewUser.userTypeProprietaryInfo.mfa.enabled) {
if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
return BadRequest(RESTAPI::Errors::BadMFAMethod);
}
bool ChangingMFA =
NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled;
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
auto PropInfo = RawObject->get("userTypeProprietaryInfo");
if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>();
if (PInfo->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
}
if (NewUser.userTypeProprietaryInfo.mobiles.empty() ||
!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,
UserInfo_.userinfo.email)) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
} else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
std::string Secret;
Existing.userTypeProprietaryInfo.mobiles.clear();
if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
// we allow someone to use their old secret
} else {
return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
}
} else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
// nothing to do for email.
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
}
Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
Existing.userTypeProprietaryInfo.mfa.enabled = true;
} else {
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.mfa.enabled = false;
}
}
if(StorageService()->SubDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
SecurityObjects::UserInfo NewUserInfo;
StorageService()->SubDB().GetUserById(Id,NewUserInfo);
Poco::JSON::Object ModifiedObject;
Sanitize(UserInfo_, NewUserInfo);
NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject);
}
BadRequest(RESTAPI::Errors::RecordNotUpdated);
}
}

View File

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

View File

@@ -0,0 +1,55 @@
//
// Created by stephane bourque on 2021-11-30.
//
#include "RESTAPI_subusers_handler.h"
#include "StorageService.h"
#include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
namespace OpenWifi {
void RESTAPI_subusers_handler::DoGet() {
std::vector<SecurityObjects::UserInfo> Users;
bool IdOnly = (GetParameter("idOnly","false")=="true");
if(QB_.Select.empty()) {
Poco::JSON::Array ArrayObj;
Poco::JSON::Object Answer;
if (StorageService()->SubDB().GetUsers(QB_.Offset, QB_.Limit, Users)) {
for (auto &i : Users) {
Poco::JSON::Object Obj;
if (IdOnly) {
ArrayObj.add(i.id);
} else {
Sanitize(UserInfo_, i);
i.to_json(Obj);
ArrayObj.add(Obj);
}
}
Answer.set(RESTAPI::Protocol::USERS, ArrayObj);
}
return ReturnObject(Answer);
} else {
Poco::JSON::Array ArrayObj;
for(auto &i:SelectedRecords()) {
SecurityObjects::UserInfo UInfo;
auto tI{i};
if(StorageService()->SubDB().GetUserById(tI,UInfo)) {
Poco::JSON::Object Obj;
if (IdOnly) {
ArrayObj.add(UInfo.id);
} else {
Sanitize(UserInfo_, UInfo);
UInfo.to_json(Obj);
ArrayObj.add(Obj);
}
}
}
Poco::JSON::Object RetObj;
RetObj.set(RESTAPI::Protocol::USERS, ArrayObj);
return ReturnObject(RetObj);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,11 +4,16 @@
#include "RESTAPI_user_handler.h" #include "RESTAPI_user_handler.h"
#include "StorageService.h" #include "StorageService.h"
#include "Poco/JSON/Parser.h"
#include "framework/RESTAPI_errors.h" #include "framework/RESTAPI_errors.h"
#include "SMSSender.h" #include "SMSSender.h"
#include "ACLProcessor.h"
#include "AuthService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
#include "MFAServer.h"
#include "TotpCache.h"
namespace OpenWifi { namespace OpenWifi {
void RESTAPI_user_handler::DoGet() { void RESTAPI_user_handler::DoGet() {
std::string Id = GetBinding("id", ""); std::string Id = GetBinding("id", "");
if(Id.empty()) { if(Id.empty()) {
@@ -19,13 +24,19 @@ namespace OpenWifi {
std::string Arg; std::string Arg;
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(HasParameter("byEmail",Arg) && Arg=="true") { if(HasParameter("byEmail",Arg) && Arg=="true") {
if(!StorageService()->GetUserByEmail(Id,UInfo)) { if(!StorageService()->UserDB().GetUserByEmail(Id,UInfo)) {
return NotFound(); return NotFound();
} }
} else if(!StorageService()->GetUserById(Id,UInfo)) { } else if(!StorageService()->UserDB().GetUserById(Id,UInfo)) {
return NotFound(); return NotFound();
} }
if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::READ)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Poco::JSON::Object UserInfoObject; Poco::JSON::Object UserInfoObject;
Sanitize(UserInfo_, UInfo);
UInfo.to_json(UserInfoObject); UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject); ReturnObject(UserInfoObject);
} }
@@ -37,18 +48,22 @@ namespace OpenWifi {
} }
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(Id,UInfo)) { if(!StorageService()->UserDB().GetUserById(Id,UInfo)) {
return NotFound(); return NotFound();
} }
if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(!StorageService()->UserDB().DeleteUser(UserInfo_.userinfo.email,Id)) {
return NotFound(); return NotFound();
} }
if(AuthService()->DeleteUserFromCache(UInfo.email)) AuthService()->DeleteUserFromCache(Id);
; StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id);
Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id);
StorageService()->RevokeAllTokens(UInfo.email); StorageService()->UserTokenDB().RevokeAllTokens(Id);
Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email)); Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
OK(); OK();
} }
@@ -59,49 +74,63 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::IdMustBe0); return BadRequest(RESTAPI::Errors::IdMustBe0);
} }
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo NewUser;
RESTAPI_utils::from_request(UInfo,*Request); RESTAPI_utils::from_request(NewUser,*Request);
if(NewUser.userRole == SecurityObjects::UNKNOWN) {
if(UInfo.userRole == SecurityObjects::UNKNOWN) {
return BadRequest(RESTAPI::Errors::InvalidUserRole); return BadRequest(RESTAPI::Errors::InvalidUserRole);
} }
Poco::toLowerInPlace(UInfo.email); if(UserInfo_.userinfo.userRole==SecurityObjects::ROOT) {
if(!Utils::ValidEMailAddress(UInfo.email)) { NewUser.owner = GetParameter("entity","");
} else {
NewUser.owner = UserInfo_.userinfo.owner;
}
if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Poco::toLowerInPlace(NewUser.email);
if(!Utils::ValidEMailAddress(NewUser.email)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress); return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
} }
if(!UInfo.currentPassword.empty()) { if(!NewUser.currentPassword.empty()) {
if(!AuthService()->ValidatePassword(UInfo.currentPassword)) { if(!AuthService()->ValidatePassword(NewUser.currentPassword)) {
return BadRequest(RESTAPI::Errors::InvalidPassword); return BadRequest(RESTAPI::Errors::InvalidPassword);
} }
} }
if(UInfo.name.empty()) if(NewUser.name.empty())
UInfo.name = UInfo.email; NewUser.name = NewUser.email;
if(!StorageService()->CreateUser(UInfo.email,UInfo)) { // You cannot enable MFA during user creation
Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email)); NewUser.userTypeProprietaryInfo.mfa.enabled = false;
NewUser.userTypeProprietaryInfo.mfa.method = "";
NewUser.userTypeProprietaryInfo.mobiles.clear();
NewUser.userTypeProprietaryInfo.authenticatorSecret.clear();
if(!StorageService()->UserDB().CreateUser(NewUser.email,NewUser)) {
Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email));
return BadRequest(RESTAPI::Errors::RecordNotCreated); return BadRequest(RESTAPI::Errors::RecordNotCreated);
} }
if(GetParameter("email_verification","false")=="true") { if(GetParameter("email_verification","false")=="true") {
if(AuthService::VerifyEmail(UInfo)) if(AuthService::VerifyEmail(NewUser))
Logger_.information(Poco::format("Verification e-mail requested for %s",UInfo.email)); Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email));
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UInfo.Id,UInfo); StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,NewUser.id,NewUser);
} }
if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) { if(!StorageService()->UserDB().GetUserByEmail(NewUser.email, NewUser)) {
Logger_.information(Poco::format("User '%s' but not retrieved.",UInfo.email)); Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email));
return NotFound(); return NotFound();
} }
Poco::JSON::Object UserInfoObject; Poco::JSON::Object UserInfoObject;
UInfo.to_json(UserInfoObject); Sanitize(UserInfo_, NewUser);
NewUser.to_json(UserInfoObject);
ReturnObject(UserInfoObject); ReturnObject(UserInfoObject);
Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email));
Logger_.information(Poco::format("User '%s' has been added by '%s')",UInfo.email, UserInfo_.userinfo.email));
} }
void RESTAPI_user_handler::DoPut() { void RESTAPI_user_handler::DoPut() {
@@ -111,10 +140,14 @@ namespace OpenWifi {
} }
SecurityObjects::UserInfo Existing; SecurityObjects::UserInfo Existing;
if(!StorageService()->GetUserById(Id,Existing)) { if(!StorageService()->UserDB().GetUserById(Id,Existing)) {
return NotFound(); return NotFound();
} }
if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
SecurityObjects::UserInfo NewUser; SecurityObjects::UserInfo NewUser;
auto RawObject = ParseStream(); auto RawObject = ParseStream();
if(!NewUser.from_json(RawObject)) { if(!NewUser.from_json(RawObject)) {
@@ -126,18 +159,34 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidUserRole); return BadRequest(RESTAPI::Errors::InvalidUserRole);
} }
if(RawObject->has("owner")) {
if (UserInfo_.userinfo.userRole == SecurityObjects::ROOT && Existing.owner.empty()) {
AssignIfPresent(RawObject, "owner", Existing.owner);
}
}
// The only valid things to change are: changePassword, name, // The only valid things to change are: changePassword, name,
AssignIfPresent(RawObject,"name", Existing.name); AssignIfPresent(RawObject,"name", Existing.name);
AssignIfPresent(RawObject,"description", Existing.description); AssignIfPresent(RawObject,"description", Existing.description);
AssignIfPresent(RawObject,"owner", Existing.owner);
AssignIfPresent(RawObject,"location", Existing.location); AssignIfPresent(RawObject,"location", Existing.location);
AssignIfPresent(RawObject,"locale", Existing.locale); AssignIfPresent(RawObject,"locale", Existing.locale);
AssignIfPresent(RawObject,"changePassword", Existing.changePassword); AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
AssignIfPresent(RawObject,"suspended", Existing.suspended); AssignIfPresent(RawObject,"suspended", Existing.suspended);
AssignIfPresent(RawObject,"blackListed", Existing.blackListed); AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
if(RawObject->has("userRole")) if(RawObject->has("userRole")) {
Existing.userRole = 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) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(Id==UserInfo_.userinfo.id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
Existing.userRole = NewRole;
}
}
if(RawObject->has("notes")) { if(RawObject->has("notes")) {
SecurityObjects::NoteInfoVec NIV; SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
@@ -161,33 +210,56 @@ namespace OpenWifi {
} }
if(RawObject->has("userTypeProprietaryInfo")) { if(RawObject->has("userTypeProprietaryInfo")) {
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; if(NewUser.userTypeProprietaryInfo.mfa.enabled) {
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") { if (!MFAMETHODS::Validate(NewUser.userTypeProprietaryInfo.mfa.method)) {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
auto MobileStruct = RawObject->get("userTypeProprietaryInfo");
auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>();
if(Info->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
}
if(!NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
} else if(NewUser.userTypeProprietaryInfo.mfa.method=="email") {
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
} else {
if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest(RESTAPI::Errors::BadMFAMethod); return BadRequest(RESTAPI::Errors::BadMFAMethod);
} }
bool ChangingMFA =
NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled;
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
auto PropInfo = RawObject->get("userTypeProprietaryInfo");
if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::SMS) {
auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>();
if (PInfo->isArray("mobiles")) {
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
}
if (NewUser.userTypeProprietaryInfo.mobiles.empty() ||
!SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,
UserInfo_.userinfo.email)) {
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
}
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
} else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::AUTHENTICATOR) {
std::string Secret;
Existing.userTypeProprietaryInfo.mobiles.clear();
if(Existing.userTypeProprietaryInfo.authenticatorSecret.empty() && TotpCache()->CompleteValidation(UserInfo_.userinfo,false,Secret)) {
Existing.userTypeProprietaryInfo.authenticatorSecret = Secret;
} else if (!Existing.userTypeProprietaryInfo.authenticatorSecret.empty()) {
// we allow someone to use their old secret
} else {
return BadRequest(RESTAPI::Errors::AuthenticatorVerificationIncomplete);
}
} else if (ChangingMFA && NewUser.userTypeProprietaryInfo.mfa.method == MFAMETHODS::EMAIL) {
// nothing to do for email.
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
}
Existing.userTypeProprietaryInfo.mfa.method = NewUser.userTypeProprietaryInfo.mfa.method;
Existing.userTypeProprietaryInfo.mfa.enabled = true;
} else {
Existing.userTypeProprietaryInfo.authenticatorSecret.clear();
Existing.userTypeProprietaryInfo.mobiles.clear();
Existing.userTypeProprietaryInfo.mfa.enabled = false;
} }
} }
if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { if(StorageService()->UserDB().UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
SecurityObjects::UserInfo NewUserInfo; SecurityObjects::UserInfo NewUserInfo;
StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); StorageService()->UserDB().GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject; Poco::JSON::Object ModifiedObject;
Sanitize(UserInfo_, NewUserInfo);
NewUserInfo.to_json(ModifiedObject); NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject); return ReturnObject(ModifiedObject);
} }

View File

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

View File

@@ -6,6 +6,7 @@
#include "StorageService.h" #include "StorageService.h"
#include "framework/RESTAPI_protocol.h" #include "framework/RESTAPI_protocol.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_db_helpers.h"
namespace OpenWifi { namespace OpenWifi {
void RESTAPI_users_handler::DoGet() { void RESTAPI_users_handler::DoGet() {
@@ -15,12 +16,13 @@ namespace OpenWifi {
if(QB_.Select.empty()) { if(QB_.Select.empty()) {
Poco::JSON::Array ArrayObj; Poco::JSON::Array ArrayObj;
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) { if (StorageService()->UserDB().GetUsers(QB_.Offset, QB_.Limit, Users)) {
for (const auto &i : Users) { for (auto &i : Users) {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
if (IdOnly) { if (IdOnly) {
ArrayObj.add(i.Id); ArrayObj.add(i.id);
} else { } else {
Sanitize(UserInfo_, i);
i.to_json(Obj); i.to_json(Obj);
ArrayObj.add(Obj); ArrayObj.add(Obj);
} }
@@ -29,15 +31,16 @@ namespace OpenWifi {
} }
return ReturnObject(Answer); return ReturnObject(Answer);
} else { } else {
Types::StringVec IDs = Utils::Split(QB_.Select);
Poco::JSON::Array ArrayObj; Poco::JSON::Array ArrayObj;
for(auto &i:IDs) { for(auto &i:SelectedRecords()) {
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(StorageService()->GetUserById(i,UInfo)) { auto tI{i};
if(StorageService()->UserDB().GetUserById(i,UInfo)) {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
if (IdOnly) { if (IdOnly) {
ArrayObj.add(UInfo.Id); ArrayObj.add(UInfo.id);
} else { } else {
Sanitize(UserInfo_, UInfo);
UInfo.to_json(Obj); UInfo.to_json(Obj);
ArrayObj.add(Obj); ArrayObj.add(Obj);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ namespace OpenWifi::FMSObjects {
std::string location; std::string location;
std::string uploader; std::string uploader;
std::string digest; std::string digest;
bool latest=false; bool latest=0;
SecurityObjects::NoteInfoVec notes; SecurityObjects::NoteInfoVec notes;
uint64_t created=0; uint64_t created=0;

View File

@@ -12,6 +12,7 @@
#include "Daemon.h" #include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
#include "DeviceRegistry.h" #include "DeviceRegistry.h"
#include "CapabilitiesCache.h"
#endif #endif
#include "RESTAPI_GWobjects.h" #include "RESTAPI_GWobjects.h"
@@ -26,7 +27,7 @@ namespace OpenWifi::GWObjects {
void Device::to_json(Poco::JSON::Object &Obj) const { void Device::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber); field_to_json(Obj,"serialNumber", SerialNumber);
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible)); field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible));
#endif #endif
field_to_json(Obj,"macAddress", MACAddress); field_to_json(Obj,"macAddress", MACAddress);
field_to_json(Obj,"manufacturer", Manufacturer); field_to_json(Obj,"manufacturer", Manufacturer);
@@ -68,7 +69,7 @@ namespace OpenWifi::GWObjects {
#endif #endif
} }
bool Device::from_json(Poco::JSON::Object::Ptr Obj) { bool Device::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"serialNumber",SerialNumber); field_from_json(Obj,"serialNumber",SerialNumber);
field_from_json(Obj,"deviceType",DeviceType); field_from_json(Obj,"deviceType",DeviceType);
@@ -145,9 +146,10 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"custom", Custom); field_to_json(Obj,"custom", Custom);
field_to_json(Obj,"waitingForFile", WaitingForFile); field_to_json(Obj,"waitingForFile", WaitingForFile);
field_to_json(Obj,"attachFile", AttachDate); field_to_json(Obj,"attachFile", AttachDate);
field_to_json(Obj,"executionTime", executionTime);
} }
bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) { bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"name",Name); field_from_json(Obj,"name",Name);
field_from_json(Obj,"configuration",Configuration); field_from_json(Obj,"configuration",Configuration);
@@ -166,7 +168,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"created", created); field_to_json(Obj,"created", created);
} }
bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr Obj) { bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"serialNumber",serialNumber); field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"author",author); field_from_json(Obj,"author",author);
@@ -179,7 +181,6 @@ namespace OpenWifi::GWObjects {
} }
void ConnectionState::to_json(Poco::JSON::Object &Obj) const { void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber);
field_to_json(Obj,"ipAddress", Address); field_to_json(Obj,"ipAddress", Address);
field_to_json(Obj,"txBytes", TX); field_to_json(Obj,"txBytes", TX);
field_to_json(Obj,"rxBytes", RX); field_to_json(Obj,"rxBytes", RX);
@@ -190,6 +191,10 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"lastContact", LastContact); field_to_json(Obj,"lastContact", LastContact);
field_to_json(Obj,"associations_2G", Associations_2G); field_to_json(Obj,"associations_2G", Associations_2G);
field_to_json(Obj,"associations_5G", Associations_5G); field_to_json(Obj,"associations_5G", Associations_5G);
field_to_json(Obj,"webSocketClients", webSocketClients);
field_to_json(Obj,"websocketPackets", websocketPackets);
field_to_json(Obj,"kafkaClients", kafkaClients);
field_to_json(Obj,"kafkaPackets", kafkaPackets);
switch(VerifiedCertificate) { switch(VerifiedCertificate) {
case NO_CERTIFICATE: case NO_CERTIFICATE:

View File

@@ -6,8 +6,7 @@
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#ifndef UCENTRAL_RESTAPI_OBJECTS_H #pragma once
#define UCENTRAL_RESTAPI_OBJECTS_H
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include "RESTAPI_SecurityObjects.h" #include "RESTAPI_SecurityObjects.h"
@@ -23,7 +22,6 @@ namespace OpenWifi::GWObjects {
struct ConnectionState { struct ConnectionState {
uint64_t MessageCount = 0 ; uint64_t MessageCount = 0 ;
std::string SerialNumber;
std::string Address; std::string Address;
uint64_t UUID = 0 ; uint64_t UUID = 0 ;
uint64_t PendingUUID = 0 ; uint64_t PendingUUID = 0 ;
@@ -35,6 +33,10 @@ namespace OpenWifi::GWObjects {
std::string Firmware; std::string Firmware;
CertificateValidation VerifiedCertificate = NO_CERTIFICATE; CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
std::string Compatible; std::string Compatible;
uint64_t kafkaClients=0;
uint64_t webSocketClients=0;
uint64_t kafkaPackets=0;
uint64_t websocketPackets=0;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
@@ -50,40 +52,40 @@ namespace OpenWifi::GWObjects {
std::string Firmware; std::string Firmware;
std::string Compatible; std::string Compatible;
std::string FWUpdatePolicy; std::string FWUpdatePolicy;
uint64_t UUID; uint64_t UUID = 0 ;
uint64_t CreationTimestamp; uint64_t CreationTimestamp = 0 ;
uint64_t LastConfigurationChange; uint64_t LastConfigurationChange = 0 ;
uint64_t LastConfigurationDownload; uint64_t LastConfigurationDownload = 0 ;
uint64_t LastFWUpdate; uint64_t LastFWUpdate = 0 ;
std::string Venue; std::string Venue;
std::string DevicePassword; std::string DevicePassword;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const; void to_json_with_status(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj); bool from_json(Poco::JSON::Object::Ptr &Obj);
void Print() const; void Print() const;
}; };
struct Statistics { struct Statistics {
std::string SerialNumber; std::string SerialNumber;
uint64_t UUID; uint64_t UUID = 0 ;
std::string Data; std::string Data;
uint64_t Recorded; uint64_t Recorded = 0;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct HealthCheck { struct HealthCheck {
std::string SerialNumber; std::string SerialNumber;
uint64_t UUID; uint64_t UUID = 0 ;
std::string Data; std::string Data;
uint64_t Recorded; uint64_t Recorded = 0 ;
uint64_t Sanity; uint64_t Sanity = 0 ;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct Capabilities { struct Capabilities {
std::string Capabilities; std::string Capabilities;
uint64_t FirstUpdate; uint64_t FirstUpdate = 0 ;
uint64_t LastUpdate; uint64_t LastUpdate = 0 ;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
@@ -101,22 +103,22 @@ namespace OpenWifi::GWObjects {
std::string SerialNumber; std::string SerialNumber;
std::string Log; std::string Log;
std::string Data; std::string Data;
uint64_t Severity; uint64_t Severity = 0 ;
uint64_t Recorded; uint64_t Recorded = 0 ;
uint64_t LogType; uint64_t LogType = 0 ;
uint64_t UUID; uint64_t UUID = 0 ;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct DefaultConfiguration { struct DefaultConfiguration {
std::string Name; std::string Name;
std::string Configuration; std::string Configuration;
std::string Models; Types::StringVec Models;
std::string Description; std::string Description;
uint64_t Created; uint64_t Created;
uint64_t LastModified; uint64_t LastModified;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj); bool from_json(Poco::JSON::Object::Ptr &Obj);
}; };
struct CommandDetails { struct CommandDetails {
@@ -138,6 +140,7 @@ namespace OpenWifi::GWObjects {
uint64_t AttachDate = 0 ; uint64_t AttachDate = 0 ;
uint64_t AttachSize = 0 ; uint64_t AttachSize = 0 ;
std::string AttachType; std::string AttachType;
double executionTime = 0.0;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
@@ -147,26 +150,26 @@ namespace OpenWifi::GWObjects {
std::string author; std::string author;
uint64_t created; uint64_t created;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj); bool from_json(Poco::JSON::Object::Ptr &Obj);
}; };
struct RttySessionDetails { struct RttySessionDetails {
std::string SerialNumber; std::string SerialNumber;
std::string Server; std::string Server;
uint64_t Port; uint64_t Port = 0 ;
std::string Token; std::string Token;
uint64_t TimeOut; uint64_t TimeOut = 0 ;
std::string ConnectionId; std::string ConnectionId;
uint64_t Started; uint64_t Started = 0 ;
std::string CommandUUID; std::string CommandUUID;
uint64_t ViewPort; uint64_t ViewPort = 0 ;
std::string DevicePassword; std::string DevicePassword;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct Dashboard { struct Dashboard {
uint64_t snapshot; uint64_t snapshot = 0 ;
uint64_t numberOfDevices; uint64_t numberOfDevices = 0 ;
Types::CountedMap commands; Types::CountedMap commands;
Types::CountedMap upTimes; Types::CountedMap upTimes;
Types::CountedMap memoryUsed; Types::CountedMap memoryUsed;
@@ -191,5 +194,3 @@ namespace OpenWifi::GWObjects {
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
} }
#endif //UCENTRAL_RESTAPI_OBJECTS_H

View File

@@ -10,27 +10,30 @@
#include "RESTAPI_ProvObjects.h" #include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h" #include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::ProvObjects { namespace OpenWifi::ProvObjects {
void ObjectInfo::to_json(Poco::JSON::Object &Obj) const { void ObjectInfo::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj,"id",id); field_to_json(Obj,"id",id);
RESTAPI_utils::field_to_json(Obj,"name",name); field_to_json(Obj,"name",name);
RESTAPI_utils::field_to_json(Obj,"description",description); field_to_json(Obj,"description",description);
RESTAPI_utils::field_to_json(Obj,"created",created); field_to_json(Obj,"created",created);
RESTAPI_utils::field_to_json(Obj,"modified",modified); field_to_json(Obj,"modified",modified);
RESTAPI_utils::field_to_json(Obj,"notes",notes); field_to_json(Obj,"notes",notes);
RESTAPI_utils::field_to_json(Obj,"tags",tags); field_to_json(Obj,"tags",tags);
} }
bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json(Obj,"id",id); field_from_json(Obj,"id",id);
RESTAPI_utils::field_from_json(Obj,"name",name); field_from_json(Obj,"name",name);
RESTAPI_utils::field_from_json(Obj,"description",description); field_from_json(Obj,"description",description);
RESTAPI_utils::field_from_json(Obj,"created",created); field_from_json(Obj,"created",created);
RESTAPI_utils::field_from_json(Obj,"modified",modified); field_from_json(Obj,"modified",modified);
RESTAPI_utils::field_from_json(Obj,"notes",notes); field_from_json(Obj,"notes",notes);
RESTAPI_utils::field_from_json(Obj,"tags",tags); field_from_json(Obj,"tags",tags);
return true; return true;
} catch(...) { } catch(...) {
@@ -39,18 +42,18 @@ namespace OpenWifi::ProvObjects {
} }
void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const { void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"users",users); field_to_json( Obj,"users",users);
RESTAPI_utils::field_to_json( Obj,"resources",resources); field_to_json( Obj,"resources",resources);
RESTAPI_utils::field_to_json( Obj,"access",access); field_to_json( Obj,"access",access);
RESTAPI_utils::field_to_json( Obj,"policy",policy); field_to_json( Obj,"policy",policy);
} }
bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"users",users); field_from_json( Obj,"users",users);
RESTAPI_utils::field_from_json( Obj,"resources",resources); field_from_json( Obj,"resources",resources);
RESTAPI_utils::field_from_json( Obj,"access",access); field_from_json( Obj,"access",access);
RESTAPI_utils::field_from_json( Obj,"policy",policy); field_from_json( Obj,"policy",policy);
return true; return true;
} catch(...) { } catch(...) {
@@ -60,17 +63,17 @@ namespace OpenWifi::ProvObjects {
void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const { void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json(Obj, "entries", entries); field_to_json(Obj, "entries", entries);
RESTAPI_utils::field_to_json(Obj, "inUse", inUse); field_to_json(Obj, "inUse", inUse);
RESTAPI_utils::field_to_json(Obj, "entity", entity); field_to_json(Obj, "entity", entity);
} }
bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json(Obj, "entries", entries); field_from_json(Obj, "entries", entries);
RESTAPI_utils::field_from_json(Obj, "inUse", inUse); field_from_json(Obj, "inUse", inUse);
RESTAPI_utils::field_from_json(Obj, "entity", entity); field_from_json(Obj, "entity", entity);
return true; return true;
} catch(...) { } catch(...) {
@@ -80,31 +83,31 @@ namespace OpenWifi::ProvObjects {
void Entity::to_json(Poco::JSON::Object &Obj) const { void Entity::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"venues",venues); field_to_json( Obj,"venues",venues);
RESTAPI_utils::field_to_json( Obj,"children",children); field_to_json( Obj,"children",children);
RESTAPI_utils::field_to_json( Obj,"contacts",contacts); field_to_json( Obj,"contacts",contacts);
RESTAPI_utils::field_to_json( Obj,"locations",locations); field_to_json( Obj,"locations",locations);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"devices",devices); field_to_json( Obj,"devices",devices);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP); field_to_json( Obj,"sourceIP",sourceIP);
} }
bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"venues",venues); field_from_json( Obj,"venues",venues);
RESTAPI_utils::field_from_json( Obj,"children",children); field_from_json( Obj,"children",children);
RESTAPI_utils::field_from_json( Obj,"contacts",contacts); field_from_json( Obj,"contacts",contacts);
RESTAPI_utils::field_from_json( Obj,"locations",locations); field_from_json( Obj,"locations",locations);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"devices",devices); field_from_json( Obj,"devices",devices);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP); field_from_json( Obj,"sourceIP",sourceIP);
return true; return true;
} catch(...) { } catch(...) {
@@ -113,14 +116,14 @@ namespace OpenWifi::ProvObjects {
} }
void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const { void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"child",child); field_to_json( Obj,"child",child);
} }
bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"child",child); field_from_json( Obj,"child",child);
return true; return true;
} catch (...) { } catch (...) {
@@ -130,37 +133,37 @@ namespace OpenWifi::ProvObjects {
void Venue::to_json(Poco::JSON::Object &Obj) const { void Venue::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"children",children); field_to_json( Obj,"children",children);
RESTAPI_utils::field_to_json( Obj,"devices",devices); field_to_json( Obj,"devices",devices);
RESTAPI_utils::field_to_json( Obj,"topology",topology); field_to_json( Obj,"topology",topology);
RESTAPI_utils::field_to_json( Obj,"parent",parent); field_to_json( Obj,"parent",parent);
RESTAPI_utils::field_to_json( Obj,"design",design); field_to_json( Obj,"design",design);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"contact",contact); field_to_json( Obj,"contact",contact);
RESTAPI_utils::field_to_json( Obj,"location",location); field_to_json( Obj,"location",location);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP); field_to_json( Obj,"sourceIP",sourceIP);
} }
bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"children",children); field_from_json( Obj,"children",children);
RESTAPI_utils::field_from_json( Obj,"devices",devices); field_from_json( Obj,"devices",devices);
RESTAPI_utils::field_from_json( Obj,"topology",topology); field_from_json( Obj,"topology",topology);
RESTAPI_utils::field_from_json( Obj,"parent",parent); field_from_json( Obj,"parent",parent);
RESTAPI_utils::field_from_json( Obj,"design",design); field_from_json( Obj,"design",design);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"contact",contact); field_from_json( Obj,"contact",contact);
RESTAPI_utils::field_from_json( Obj,"location",location); field_from_json( Obj,"location",location);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP); field_from_json( Obj,"sourceIP",sourceIP);
return true; return true;
} catch (...) { } catch (...) {
@@ -169,16 +172,16 @@ namespace OpenWifi::ProvObjects {
} }
void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"id",id); field_to_json( Obj,"id",id);
RESTAPI_utils::field_to_json( Obj,"entity",loginId); field_to_json( Obj,"entity",loginId);
RESTAPI_utils::field_to_json( Obj,"children",userType); field_to_json( Obj,"children",userType);
} }
bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) { bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"id",id); field_from_json( Obj,"id",id);
RESTAPI_utils::field_from_json( Obj,"entity",loginId); field_from_json( Obj,"entity",loginId);
RESTAPI_utils::field_from_json( Obj,"children",userType); field_from_json( Obj,"children",userType);
return true; return true;
} catch(...) { } catch(...) {
} }
@@ -187,17 +190,17 @@ namespace OpenWifi::ProvObjects {
void ManagementRole::to_json(Poco::JSON::Object &Obj) const { void ManagementRole::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"users",users); field_to_json( Obj,"users",users);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
} }
bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"users",users); field_from_json( Obj,"users",users);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
return true; return true;
} catch(...) { } catch(...) {
} }
@@ -206,39 +209,39 @@ namespace OpenWifi::ProvObjects {
void Location::to_json(Poco::JSON::Object &Obj) const { void Location::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type)); field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type));
RESTAPI_utils::field_to_json( Obj,"buildingName",buildingName); field_to_json( Obj,"buildingName",buildingName);
RESTAPI_utils::field_to_json( Obj,"addressLines",addressLines); field_to_json( Obj,"addressLines",addressLines);
RESTAPI_utils::field_to_json( Obj,"city",city); field_to_json( Obj,"city",city);
RESTAPI_utils::field_to_json( Obj,"state",state); field_to_json( Obj,"state",state);
RESTAPI_utils::field_to_json( Obj,"postal",postal); field_to_json( Obj,"postal",postal);
RESTAPI_utils::field_to_json( Obj,"country",country); field_to_json( Obj,"country",country);
RESTAPI_utils::field_to_json( Obj,"phones",phones); field_to_json( Obj,"phones",phones);
RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles); field_to_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_to_json( Obj,"geoCode",geoCode); field_to_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
} }
bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
std::string tmp_type; std::string tmp_type;
RESTAPI_utils::field_from_json( Obj,"type", tmp_type); field_from_json( Obj,"type", tmp_type);
type = location_from_string(tmp_type); type = location_from_string(tmp_type);
RESTAPI_utils::field_from_json( Obj,"buildingName",buildingName); field_from_json( Obj,"buildingName",buildingName);
RESTAPI_utils::field_from_json( Obj,"addressLines",addressLines); field_from_json( Obj,"addressLines",addressLines);
RESTAPI_utils::field_from_json( Obj,"city",city); field_from_json( Obj,"city",city);
RESTAPI_utils::field_from_json( Obj,"state",state); field_from_json( Obj,"state",state);
RESTAPI_utils::field_from_json( Obj,"postal",postal); field_from_json( Obj,"postal",postal);
RESTAPI_utils::field_from_json( Obj,"country",country); field_from_json( Obj,"country",country);
RESTAPI_utils::field_from_json( Obj,"phones",phones); field_from_json( Obj,"phones",phones);
RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles); field_from_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode); field_from_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
return true; return true;
} catch (...) { } catch (...) {
@@ -248,43 +251,43 @@ namespace OpenWifi::ProvObjects {
void Contact::to_json(Poco::JSON::Object &Obj) const { void Contact::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"type", to_string(type)); field_to_json( Obj,"type", to_string(type));
RESTAPI_utils::field_to_json( Obj,"title",title); field_to_json( Obj,"title",title);
RESTAPI_utils::field_to_json( Obj,"salutation",salutation); field_to_json( Obj,"salutation",salutation);
RESTAPI_utils::field_to_json( Obj,"firstname",firstname); field_to_json( Obj,"firstname",firstname);
RESTAPI_utils::field_to_json( Obj,"lastname",lastname); field_to_json( Obj,"lastname",lastname);
RESTAPI_utils::field_to_json( Obj,"initials",initials); field_to_json( Obj,"initials",initials);
RESTAPI_utils::field_to_json( Obj,"visual",visual); field_to_json( Obj,"visual",visual);
RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles); field_to_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_to_json( Obj,"phones",phones); field_to_json( Obj,"phones",phones);
RESTAPI_utils::field_to_json( Obj,"primaryEmail",primaryEmail); field_to_json( Obj,"primaryEmail",primaryEmail);
RESTAPI_utils::field_to_json( Obj,"secondaryEmail",secondaryEmail); field_to_json( Obj,"secondaryEmail",secondaryEmail);
RESTAPI_utils::field_to_json( Obj,"accessPIN",accessPIN); field_to_json( Obj,"accessPIN",accessPIN);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"entity",entity); field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
} }
bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) { bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
std::string tmp_type; std::string tmp_type;
RESTAPI_utils::field_from_json( Obj,"type", tmp_type); field_from_json( Obj,"type", tmp_type);
type = contact_from_string(tmp_type); type = contact_from_string(tmp_type);
RESTAPI_utils::field_from_json( Obj,"title",title); field_from_json( Obj,"title",title);
RESTAPI_utils::field_from_json( Obj,"salutation",salutation); field_from_json( Obj,"salutation",salutation);
RESTAPI_utils::field_from_json( Obj,"firstname",firstname); field_from_json( Obj,"firstname",firstname);
RESTAPI_utils::field_from_json( Obj,"lastname",lastname); field_from_json( Obj,"lastname",lastname);
RESTAPI_utils::field_from_json( Obj,"initials",initials); field_from_json( Obj,"initials",initials);
RESTAPI_utils::field_from_json( Obj,"visual",visual); field_from_json( Obj,"visual",visual);
RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles); field_from_json( Obj,"mobiles",mobiles);
RESTAPI_utils::field_from_json( Obj,"phones",phones); field_from_json( Obj,"phones",phones);
RESTAPI_utils::field_from_json( Obj,"primaryEmail",primaryEmail); field_from_json( Obj,"primaryEmail",primaryEmail);
RESTAPI_utils::field_from_json( Obj,"secondaryEmail",secondaryEmail); field_from_json( Obj,"secondaryEmail",secondaryEmail);
RESTAPI_utils::field_from_json( Obj,"accessPIN",accessPIN); field_from_json( Obj,"accessPIN",accessPIN);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
return true; return true;
} catch (...) { } catch (...) {
@@ -294,35 +297,37 @@ namespace OpenWifi::ProvObjects {
void InventoryTag::to_json(Poco::JSON::Object &Obj) const { void InventoryTag::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json(Obj, "serialNumber", serialNumber); field_to_json(Obj, "serialNumber", serialNumber);
RESTAPI_utils::field_to_json(Obj, "venue", venue); field_to_json(Obj, "venue", venue);
RESTAPI_utils::field_to_json(Obj, "entity", entity); field_to_json(Obj, "entity", entity);
RESTAPI_utils::field_to_json(Obj, "subscriber", subscriber); field_to_json(Obj, "subscriber", subscriber);
RESTAPI_utils::field_to_json(Obj, "deviceType", deviceType); field_to_json(Obj, "deviceType", deviceType);
RESTAPI_utils::field_to_json(Obj, "qrCode", qrCode); field_to_json(Obj, "qrCode", qrCode);
RESTAPI_utils::field_to_json(Obj, "geoCode", geoCode); field_to_json(Obj, "geoCode", geoCode);
RESTAPI_utils::field_to_json(Obj, "location", location); field_to_json(Obj, "location", location);
RESTAPI_utils::field_to_json(Obj, "contact", contact); field_to_json(Obj, "contact", contact);
RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
field_to_json( Obj,"state",state);
} }
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"serialNumber",serialNumber); field_from_json( Obj,"serialNumber",serialNumber);
RESTAPI_utils::field_from_json( Obj,"venue",venue); field_from_json( Obj,"venue",venue);
RESTAPI_utils::field_from_json( Obj,"entity",entity); field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"subscriber",subscriber); field_from_json( Obj,"subscriber",subscriber);
RESTAPI_utils::field_from_json( Obj,"deviceType",deviceType); field_from_json( Obj,"deviceType",deviceType);
RESTAPI_utils::field_from_json(Obj, "qrCode", qrCode); field_from_json(Obj, "qrCode", qrCode);
RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode); field_from_json( Obj,"geoCode",geoCode);
RESTAPI_utils::field_from_json( Obj,"location",location); field_from_json( Obj,"location",location);
RESTAPI_utils::field_from_json( Obj,"contact",contact); field_from_json( Obj,"contact",contact);
RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"deviceConfiguration",deviceConfiguration);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
field_from_json( Obj,"state",state);
return true; return true;
} catch(...) { } catch(...) {
@@ -330,19 +335,33 @@ namespace OpenWifi::ProvObjects {
return false; return false;
} }
void InventoryTagList::to_json(Poco::JSON::Object &Obj) const {
field_to_json( Obj,"taglist",taglist);
}
bool InventoryTagList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json( Obj,"taglist",taglist);
return false;
} catch (...) {
}
return false;
};
void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"name", name); field_to_json( Obj,"name", name);
RESTAPI_utils::field_to_json( Obj,"description", description); field_to_json( Obj,"description", description);
RESTAPI_utils::field_to_json( Obj,"weight", weight); field_to_json( Obj,"weight", weight);
RESTAPI_utils::field_to_json( Obj,"configuration", configuration); field_to_json( Obj,"configuration", configuration);
} }
bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"name",name); field_from_json( Obj,"name",name);
RESTAPI_utils::field_from_json( Obj,"description",description); field_from_json( Obj,"description",description);
RESTAPI_utils::field_from_json( Obj,"weight",weight); field_from_json( Obj,"weight",weight);
RESTAPI_utils::field_from_json( Obj,"configuration",configuration); field_from_json( Obj,"configuration",configuration);
return true; return true;
} catch(...) { } catch(...) {
@@ -352,27 +371,27 @@ namespace OpenWifi::ProvObjects {
void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const { void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj); info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_to_json( Obj,"deviceTypes",deviceTypes); field_to_json( Obj,"deviceTypes",deviceTypes);
RESTAPI_utils::field_to_json( Obj,"configuration",configuration); field_to_json( Obj,"configuration",configuration);
RESTAPI_utils::field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"inUse",inUse);
RESTAPI_utils::field_to_json( Obj,"variables",variables); field_to_json( Obj,"variables",variables);
RESTAPI_utils::field_to_json( Obj,"rrm",rrm); field_to_json( Obj,"rrm",rrm);
RESTAPI_utils::field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
RESTAPI_utils::field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
} }
bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
info.from_json(Obj); info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"managementPolicy",managementPolicy);
RESTAPI_utils::field_from_json( Obj,"deviceTypes",deviceTypes); field_from_json( Obj,"deviceTypes",deviceTypes);
RESTAPI_utils::field_from_json( Obj,"configuration",configuration); field_from_json( Obj,"configuration",configuration);
RESTAPI_utils::field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"inUse",inUse);
RESTAPI_utils::field_from_json( Obj,"variables",variables); field_from_json( Obj,"variables",variables);
RESTAPI_utils::field_from_json( Obj,"rrm",rrm); field_from_json( Obj,"rrm",rrm);
RESTAPI_utils::field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
RESTAPI_utils::field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
return true; return true;
} catch(...) { } catch(...) {
@@ -381,8 +400,8 @@ namespace OpenWifi::ProvObjects {
} }
void Report::to_json(Poco::JSON::Object &Obj) const { void Report::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "snapshot", snapShot); field_to_json(Obj, "snapshot", snapShot);
RESTAPI_utils::field_to_json(Obj, "devices", tenants); field_to_json(Obj, "devices", tenants);
}; };
void Report::reset() { void Report::reset() {
@@ -390,16 +409,16 @@ namespace OpenWifi::ProvObjects {
} }
void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const { void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "uuid", uuid); field_to_json(Obj, "uuid", uuid);
RESTAPI_utils::field_to_json(Obj, "name", name); field_to_json(Obj, "name", name);
RESTAPI_utils::field_to_json(Obj, "description", description); field_to_json(Obj, "description", description);
} }
bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"uuid",uuid); field_from_json( Obj,"uuid",uuid);
RESTAPI_utils::field_from_json( Obj,"name",name); field_from_json( Obj,"name",name);
RESTAPI_utils::field_from_json( Obj,"description",description); field_from_json( Obj,"description",description);
return true; return true;
} catch(...) { } catch(...) {
@@ -408,14 +427,14 @@ namespace OpenWifi::ProvObjects {
} }
void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const { void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "type", type); field_to_json(Obj, "type", type);
RESTAPI_utils::field_to_json(Obj, "entries", entries); field_to_json(Obj, "entries", entries);
} }
bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"type",type); field_from_json( Obj,"type",type);
RESTAPI_utils::field_from_json( Obj,"entries",entries); field_from_json( Obj,"entries",entries);
return true; return true;
} catch(...) { } catch(...) {
@@ -424,12 +443,157 @@ namespace OpenWifi::ProvObjects {
} }
void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const { void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "entries", entries); field_to_json(Obj, "entries", entries);
} }
bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
RESTAPI_utils::field_from_json( Obj,"entries",entries); field_from_json( Obj,"entries",entries);
return true;
} catch(...) {
}
return false;
}
void UuidList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "list", list);
}
bool UuidList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "list", list);
return true;
} catch(...) {
}
return false;
}
void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, ACLACCESS A) {
switch(A) {
case READ: Obj.set(FieldName,"read"); break;
case MODIFY: Obj.set(FieldName,"modify"); break;
case CREATE: Obj.set(FieldName,"create"); break;
case DELETE: Obj.set(FieldName,"delete"); break;
case NONE:
default:
Obj.set(FieldName,"none");
}
}
void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, ACLACCESS &A) {
if(Obj->has(FieldName)) {
auto V = Obj->getValue<std::string>(FieldName);
if(V=="read")
A = READ;
else if(V=="modify")
A = MODIFY;
else if(V=="create")
A = CREATE;
else if(V=="delete")
A = DELETE;
else if(V=="none")
A = NONE;
else
throw Poco::Exception("invalid JSON");
}
}
void ObjectACL::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "users", users);
RESTAPI_utils::field_to_json(Obj, "roles", roles);
field_to_json(Obj, "access", access);
}
bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json(Obj, "users", users);
RESTAPI_utils::field_from_json(Obj, "roles", roles);
field_from_json(Obj, "access", access);
return true;
} catch(...) {
}
return false;
}
void ObjectACLList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json(Obj, "list", list);
}
bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json(Obj, "list", list);
return true;
} catch(...) {
}
return false;
}
std::string to_string(VISIBILITY A) {
switch(A) {
case PUBLIC: return "public";
case SELECT: return "select";
case PRIVATE:
default:
return "private";
}
}
void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, VISIBILITY A) {
Obj.set(FieldName,to_string(A));
}
VISIBILITY visibility_from_string(const std::string &V) {
if(V=="public")
return PUBLIC;
else if(V=="select")
return SELECT;
else if(V=="private")
return PRIVATE;
throw Poco::Exception("invalid json");
}
void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, VISIBILITY &A) {
if(Obj->has(FieldName)) {
auto V = Obj->getValue<std::string>(FieldName);
A = visibility_from_string(V);
}
}
void Map::to_json(Poco::JSON::Object &Obj) const {
info.to_json(Obj);
RESTAPI_utils::field_to_json( Obj,"data",data);
RESTAPI_utils::field_to_json( Obj,"entity",entity);
RESTAPI_utils::field_to_json( Obj,"creator",creator);
field_to_json( Obj,"visibility",visibility);
RESTAPI_utils::field_to_json( Obj,"access",access);
}
bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
info.from_json(Obj);
RESTAPI_utils::field_from_json( Obj,"data",data);
RESTAPI_utils::field_from_json( Obj,"entity",entity);
RESTAPI_utils::field_from_json( Obj,"creator",creator);
field_from_json( Obj,"visibility",visibility);
RESTAPI_utils::field_from_json( Obj,"access",access);
return true;
} catch(...) {
}
return false;
}
void MapList::to_json(Poco::JSON::Object &Obj) const {
RESTAPI_utils::field_to_json( Obj,"list",list);
}
bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
RESTAPI_utils::field_from_json( Obj,"list",list);
return true; return true;
} catch(...) { } catch(...) {
@@ -438,13 +602,48 @@ namespace OpenWifi::ProvObjects {
} }
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = std::time(nullptr);
if(O->has("name")) if(O->has("name"))
I.name = O->get("name").toString(); I.name = O->get("name").toString();
if(I.name.empty())
return false;
if(O->has("description")) if(O->has("description"))
I.description = O->get("description").toString(); I.description = O->get("description").toString();
SecurityObjects::MergeNotes(O,U,I.notes); SecurityObjects::MergeNotes(O,U,I.notes);
I.modified = std::time(nullptr); SecurityObjects::NoteInfoVec N;
for(auto &i:I.notes) {
if(i.note.empty())
continue;
N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note});
}
I.modified = Now;
return true; return true;
} }
}; bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = std::time(nullptr);
if(O->has("name"))
I.name = O->get("name").toString();
if(I.name.empty())
return false;
if(O->has("description"))
I.description = O->get("description").toString();
SecurityObjects::NoteInfoVec N;
for(auto &i:I.notes) {
if(i.note.empty())
continue;
N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note});
}
I.notes = N;
I.modified = I.created = Now;
I.id = MicroService::CreateUUID();
return true;
}
}

View File

@@ -6,15 +6,20 @@
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#pragma once
#ifndef OWPROV_RESTAPI_PROVOBJECTS_H
#define OWPROV_RESTAPI_PROVOBJECTS_H
#include <string> #include <string>
#include "RESTAPI_SecurityObjects.h" #include "RESTAPI_SecurityObjects.h"
namespace OpenWifi::ProvObjects { namespace OpenWifi::ProvObjects {
enum FIRMWARE_UPGRADE_RULES {
dont_upgrade,
upgrade_inherit,
upgrade_release_only,
upgrade_latest
};
struct ObjectInfo { struct ObjectInfo {
Types::UUID_t id; Types::UUID_t id;
std::string name; std::string name;
@@ -279,12 +284,22 @@ namespace OpenWifi::ProvObjects {
std::string deviceConfiguration; std::string deviceConfiguration;
std::string rrm; std::string rrm;
Types::UUID_t managementPolicy; Types::UUID_t managementPolicy;
std::string state;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
typedef std::vector<InventoryTag> InventoryTagVec; typedef std::vector<InventoryTag> InventoryTagVec;
struct InventoryTagList {
InventoryTagVec taglist;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Report { struct Report {
uint64_t snapShot=0; uint64_t snapShot=0;
Types::CountedMap tenants; Types::CountedMap tenants;
@@ -317,8 +332,59 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
struct UuidList {
std::vector<std::string> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum ACLACCESS {
NONE, READ, MODIFY, CREATE, DELETE
};
struct ObjectACL {
UuidList users;
UuidList roles;
ACLACCESS access = NONE;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ObjectACLList {
std::vector<ObjectACL> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum VISIBILITY {
PUBLIC, PRIVATE, SELECT
};
std::string to_string(VISIBILITY A);
VISIBILITY visibility_from_string(const std::string &V);
struct Map {
ObjectInfo info;
std::string data;
std::string entity;
std::string creator;
VISIBILITY visibility = PRIVATE;
ObjectACLList access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct MapList {
std::vector<Map> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
}; };
#endif //OWPROV_RESTAPI_PROVOBJECTS_H

View File

@@ -54,6 +54,8 @@ namespace OpenWifi::SecurityObjects {
return ADMIN; return ADMIN;
else if (!Poco::icompare(U,"subscriber")) else if (!Poco::icompare(U,"subscriber"))
return SUBSCRIBER; return SUBSCRIBER;
else if (!Poco::icompare(U,"partner"))
return PARTNER;
else if (!Poco::icompare(U,"csr")) else if (!Poco::icompare(U,"csr"))
return CSR; return CSR;
else if (!Poco::icompare(U, "system")) else if (!Poco::icompare(U, "system"))
@@ -72,6 +74,7 @@ namespace OpenWifi::SecurityObjects {
case ROOT: return "root"; case ROOT: return "root";
case ADMIN: return "admin"; case ADMIN: return "admin";
case SUBSCRIBER: return "subscriber"; case SUBSCRIBER: return "subscriber";
case PARTNER: return "partner";
case CSR: return "csr"; case CSR: return "csr";
case SYSTEM: return "system"; case SYSTEM: return "system";
case INSTALLER: return "installer"; case INSTALLER: return "installer";
@@ -138,7 +141,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"primary", primary); field_to_json(Obj,"primary", primary);
} }
bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) { bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"number",number); field_from_json(Obj,"number",number);
field_from_json(Obj,"verified",verified); field_from_json(Obj,"verified",verified);
@@ -155,7 +158,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"method", method); field_to_json(Obj,"method", method);
} }
bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) { bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"enabled",enabled); field_from_json(Obj,"enabled",enabled);
field_from_json(Obj,"method",method); field_from_json(Obj,"method",method);
@@ -169,12 +172,14 @@ namespace OpenWifi::SecurityObjects {
void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const { void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "mobiles", mobiles); field_to_json(Obj, "mobiles", mobiles);
field_to_json(Obj, "mfa", mfa); field_to_json(Obj, "mfa", mfa);
field_to_json(Obj, "authenticatorSecret", authenticatorSecret);
} }
bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr Obj) { bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"mobiles",mobiles); field_from_json(Obj, "mobiles",mobiles);
field_from_json(Obj,"mfa",mfa); field_from_json(Obj, "mfa",mfa);
field_from_json(Obj, "authenticatorSecret", authenticatorSecret);
return true; return true;
} catch (...) { } catch (...) {
@@ -189,7 +194,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "method", method); field_to_json(Obj, "method", method);
} }
bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) { bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"question",question); field_from_json(Obj,"question",question);
@@ -208,7 +213,7 @@ namespace OpenWifi::SecurityObjects {
} }
bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr Obj) { bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"uuid",uuid);
field_from_json(Obj,"answer",answer); field_from_json(Obj,"answer",answer);
@@ -221,7 +226,7 @@ namespace OpenWifi::SecurityObjects {
} }
void UserInfo::to_json(Poco::JSON::Object &Obj) const { void UserInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"Id",Id); field_to_json(Obj,"id",id);
field_to_json(Obj,"name",name); field_to_json(Obj,"name",name);
field_to_json(Obj,"description", description); field_to_json(Obj,"description", description);
field_to_json(Obj,"avatar", avatar); field_to_json(Obj,"avatar", avatar);
@@ -251,11 +256,12 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"lastPasswords",lastPasswords); field_to_json(Obj,"lastPasswords",lastPasswords);
field_to_json(Obj,"oauthType",oauthType); field_to_json(Obj,"oauthType",oauthType);
field_to_json(Obj,"oauthUserInfo",oauthUserInfo); field_to_json(Obj,"oauthUserInfo",oauthUserInfo);
field_to_json(Obj,"modified",modified);
}; };
bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"Id",Id); field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name); field_from_json(Obj,"name",name);
field_from_json(Obj,"description",description); field_from_json(Obj,"description",description);
field_from_json(Obj,"avatar",avatar); field_from_json(Obj,"avatar",avatar);
@@ -265,6 +271,8 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"currentLoginURI",currentLoginURI); field_from_json(Obj,"currentLoginURI",currentLoginURI);
field_from_json(Obj,"locale",locale); field_from_json(Obj,"locale",locale);
field_from_json(Obj,"notes",notes); field_from_json(Obj,"notes",notes);
field_from_json(Obj,"location", location);
field_from_json(Obj,"owner", owner);
field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString); field_from_json<USER_ROLE>(Obj,"userRole",userRole, UserTypeFromString);
field_from_json(Obj,"securityPolicy",securityPolicy); field_from_json(Obj,"securityPolicy",securityPolicy);
field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo); field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo);
@@ -283,6 +291,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"lastPasswords",lastPasswords); field_from_json(Obj,"lastPasswords",lastPasswords);
field_from_json(Obj,"oauthType",oauthType); field_from_json(Obj,"oauthType",oauthType);
field_from_json(Obj,"oauthUserInfo",oauthUserInfo); field_from_json(Obj,"oauthUserInfo",oauthUserInfo);
field_from_json(Obj,"modified",modified);
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
@@ -387,11 +396,12 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"note", note); field_to_json(Obj,"note", note);
} }
bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) { bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"created",created); field_from_json(Obj,"created",created);
field_from_json(Obj,"createdBy",createdBy); field_from_json(Obj,"createdBy",createdBy);
field_from_json(Obj,"note",note); field_from_json(Obj,"note",note);
return true;
} catch(...) { } catch(...) {
} }
@@ -428,10 +438,11 @@ namespace OpenWifi::SecurityObjects {
field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
} }
bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) { bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"resource",resource); field_from_json(Obj,"resource",resource);
field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString );
return true;
} catch(...) { } catch(...) {
} }
@@ -447,7 +458,7 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"notes", notes); field_to_json(Obj,"notes", notes);
} }
bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) { bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"id",id); field_from_json(Obj,"id",id);
field_from_json(Obj,"name",name); field_from_json(Obj,"name",name);
@@ -455,6 +466,7 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj,"policy",policy); field_from_json(Obj,"policy",policy);
field_from_json(Obj,"role",role); field_from_json(Obj,"role",role);
field_from_json(Obj,"notes",notes); field_from_json(Obj,"notes",notes);
return true;
} catch(...) { } catch(...) {
} }
@@ -465,13 +477,126 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "profiles", profiles); field_to_json(Obj, "profiles", profiles);
} }
bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) { bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"profiles",profiles); field_from_json(Obj,"profiles",profiles);
return true;
} catch(...) { } catch(...) {
} }
return false; return false;
} }
void ActionLink::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"action",action);
field_to_json(Obj,"userId",userId);
field_to_json(Obj,"actionTemplate",actionTemplate);
field_to_json(Obj,"variables",variables);
field_to_json(Obj,"locale",locale);
field_to_json(Obj,"message",message);
field_to_json(Obj,"sent",sent);
field_to_json(Obj,"created",created);
field_to_json(Obj,"expires",expires);
field_to_json(Obj,"completed",completed);
field_to_json(Obj,"canceled",canceled);
field_to_json(Obj,"userAction",userAction);
}
bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"action",action);
field_from_json(Obj,"userId",userId);
field_from_json(Obj,"actionTemplate",actionTemplate);
field_from_json(Obj,"variables",variables);
field_from_json(Obj,"locale",locale);
field_from_json(Obj,"message",message);
field_from_json(Obj,"sent",sent);
field_from_json(Obj,"created",created);
field_from_json(Obj,"expires",expires);
field_from_json(Obj,"completed",completed);
field_from_json(Obj,"canceled",canceled);
field_from_json(Obj,"userAction",userAction);
return true;
} catch(...) {
}
return false;
}
void Preferences::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"modified",modified);
field_to_json(Obj,"data",data);
}
bool Preferences::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"modified",modified);
field_from_json(Obj,"data",data);
return true;
} catch(...) {
}
return false;
}
void SubMfaConfig::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id",id);
field_to_json(Obj,"type",type);
field_to_json(Obj,"sms",sms);
field_to_json(Obj,"email",email);
}
bool SubMfaConfig::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id",id);
field_from_json(Obj,"type",type);
field_from_json(Obj,"sms",sms);
field_from_json(Obj,"email",email);
return true;
} catch(...) {
}
return false;
}
void Token::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"token",token);
field_to_json(Obj,"refreshToken",refreshToken);
field_to_json(Obj,"tokenType",tokenType);
field_to_json(Obj,"userName",userName);
field_to_json(Obj,"created",created);
field_to_json(Obj,"expires",expires);
field_to_json(Obj,"idleTimeout",idleTimeout);
field_to_json(Obj,"revocationDate",revocationDate);
}
bool Token::from_json(Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"token",token);
field_from_json(Obj,"refreshToken",refreshToken);
field_from_json(Obj,"tokenType",tokenType);
field_from_json(Obj,"userName",userName);
field_from_json(Obj,"created",created);
field_from_json(Obj,"expires",expires);
field_from_json(Obj,"idleTimeout",idleTimeout);
field_from_json(Obj,"revocationDate",revocationDate);
return true;
} catch(...) {
}
return false;
}
void LoginRecordInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"sessionId",sessionId);
field_to_json(Obj,"userId",userId);
field_to_json(Obj,"email",email);
field_to_json(Obj,"login",login);
field_to_json(Obj,"logout",logout);
}
} }

View File

@@ -6,221 +6,303 @@
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#ifndef UCENTRAL_RESTAPI_SECURITYOBJECTS_H #pragma once
#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H
#include <string>
#include "framework/OpenWifiTypes.h"
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include "../framework/OpenWifiTypes.h" #include "Poco/Data/LOB.h"
#include "Poco/Data/LOBStream.h"
namespace OpenWifi::SecurityObjects { namespace OpenWifi {
namespace SecurityObjects {
struct AclTemplate { typedef std::string USER_ID_TYPE;
bool Read_ = true;
bool ReadWrite_ = true;
bool ReadWriteCreate_ = true;
bool Delete_ = true;
bool PortalLogin_ = true;
void to_json(Poco::JSON::Object &Obj) const; struct AclTemplate {
bool from_json(const Poco::JSON::Object::Ptr &Obj); }; bool Read_ = true;
bool ReadWrite_ = true;
bool ReadWriteCreate_ = true;
bool Delete_ = true;
bool PortalLogin_ = true;
struct WebToken { void to_json(Poco::JSON::Object &Obj) const;
std::string access_token_; bool from_json(const Poco::JSON::Object::Ptr &Obj); };
std::string refresh_token_;
std::string id_token_;
std::string token_type_;
std::string username_;
bool userMustChangePassword=false;
uint64_t errorCode=0;
uint64_t expires_in_=0;
uint64_t idle_timeout_=0;
AclTemplate acl_template_;
uint64_t created_=0;
void to_json(Poco::JSON::Object &Obj) const; struct WebToken {
bool from_json(const Poco::JSON::Object::Ptr &Obj); std::string access_token_;
}; std::string refresh_token_;
std::string id_token_;
std::string token_type_;
std::string username_;
bool userMustChangePassword=false;
uint64_t errorCode=0;
uint64_t expires_in_=0;
uint64_t idle_timeout_=0;
AclTemplate acl_template_;
uint64_t created_=0;
enum USER_ROLE { void to_json(Poco::JSON::Object &Obj) const;
UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
USER_ROLE UserTypeFromString(const std::string &U); enum USER_ROLE {
std::string UserTypeToString(USER_ROLE U); UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING, PARTNER
};
struct NoteInfo { USER_ROLE UserTypeFromString(const std::string &U);
uint64_t created = std::time(nullptr); std::string UserTypeToString(USER_ROLE U);
std::string createdBy;
std::string note;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj);
};
typedef std::vector<NoteInfo> NoteInfoVec;
struct MobilePhoneNumber { struct NoteInfo {
std::string number; uint64_t created = std::time(nullptr);
bool verified; std::string createdBy;
bool primary; std::string note;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<NoteInfo> NoteInfoVec;
void to_json(Poco::JSON::Object &Obj) const; struct MobilePhoneNumber {
bool from_json(Poco::JSON::Object::Ptr Obj); std::string number;
}; bool verified = false;
bool primary = false;
struct MfaAuthInfo { void to_json(Poco::JSON::Object &Obj) const;
bool enabled; bool from_json(Poco::JSON::Object::Ptr &Obj);
std::string method; };
void to_json(Poco::JSON::Object &Obj) const; struct MfaAuthInfo {
bool from_json(Poco::JSON::Object::Ptr Obj); bool enabled = false;
}; std::string method;
struct UserLoginLoginExtensions { void to_json(Poco::JSON::Object &Obj) const;
std::vector<MobilePhoneNumber> mobiles; bool from_json(Poco::JSON::Object::Ptr &Obj);
struct MfaAuthInfo mfa; };
void to_json(Poco::JSON::Object &Obj) const; struct UserLoginLoginExtensions {
bool from_json(Poco::JSON::Object::Ptr Obj); std::vector<MobilePhoneNumber> mobiles;
}; struct MfaAuthInfo mfa;
std::string authenticatorSecret;
struct MFAChallengeRequest { void to_json(Poco::JSON::Object &Obj) const;
std::string uuid; bool from_json(Poco::JSON::Object::Ptr &Obj);
std::string question; };
std::string method;
uint64_t created;
void to_json(Poco::JSON::Object &Obj) const; struct MFAChallengeRequest {
bool from_json(Poco::JSON::Object::Ptr Obj); std::string uuid;
}; std::string question;
std::string method;
uint64_t created = std::time(nullptr);
struct MFAChallengeResponse { void to_json(Poco::JSON::Object &Obj) const;
std::string uuid; bool from_json(Poco::JSON::Object::Ptr &Obj);
std::string answer; };
void to_json(Poco::JSON::Object &Obj) const; struct MFAChallengeResponse {
bool from_json(Poco::JSON::Object::Ptr Obj); std::string uuid;
}; std::string answer;
struct UserInfo { void to_json(Poco::JSON::Object &Obj) const;
std::string Id; bool from_json(Poco::JSON::Object::Ptr &Obj);
std::string name; };
std::string description;
std::string avatar;
std::string email;
bool validated = false;
std::string validationEmail;
uint64_t validationDate = 0;
uint64_t creationDate = 0;
std::string validationURI;
bool changePassword = false;
uint64_t lastLogin = 0;
std::string currentLoginURI;
uint64_t lastPasswordChange = 0;
uint64_t lastEmailCheck = 0;
bool waitingForEmailCheck = false;
std::string locale;
NoteInfoVec notes;
std::string location;
std::string owner;
bool suspended = false;
bool blackListed = false;
USER_ROLE userRole;
UserLoginLoginExtensions userTypeProprietaryInfo;
std::string securityPolicy;
uint64_t securityPolicyChange = 0 ;
std::string currentPassword;
Types::StringVec lastPasswords;
std::string oauthType;
std::string oauthUserInfo;
void to_json(Poco::JSON::Object &Obj) const; struct UserInfo {
bool from_json(const Poco::JSON::Object::Ptr &Obj); std::string id;
}; std::string name;
typedef std::vector<UserInfo> UserInfoVec; std::string description;
std::string avatar;
std::string email;
bool validated = false;
std::string validationEmail;
uint64_t validationDate = 0;
uint64_t creationDate = 0;
std::string validationURI;
bool changePassword = false;
uint64_t lastLogin = 0;
std::string currentLoginURI;
uint64_t lastPasswordChange = 0;
uint64_t lastEmailCheck = 0;
bool waitingForEmailCheck = false;
std::string locale;
NoteInfoVec notes;
std::string location;
std::string owner;
bool suspended = false;
bool blackListed = false;
USER_ROLE userRole;
UserLoginLoginExtensions userTypeProprietaryInfo;
std::string securityPolicy;
uint64_t securityPolicyChange = 0 ;
std::string currentPassword;
OpenWifi::Types::StringVec lastPasswords;
std::string oauthType;
std::string oauthUserInfo;
uint64_t modified;
// bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); void to_json(Poco::JSON::Object &Obj) const;
bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); };
typedef std::vector<UserInfo> UserInfoVec;
struct InternalServiceInfo { // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes);
std::string privateURI; bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes);
std::string publicURI; bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes);
std::string token;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<InternalServiceInfo> InternalServiceInfoVec;
struct InternalSystemServices { struct InternalServiceInfo {
std::string key; std::string privateURI;
std::string version; std::string publicURI;
InternalServiceInfoVec services; std::string token;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
typedef std::vector<InternalServiceInfo> InternalServiceInfoVec;
struct SystemEndpoint { struct InternalSystemServices {
std::string type; std::string key;
uint64_t id = 0; std::string version;
std::string vendor{"OpenWiFi"}; InternalServiceInfoVec services;
std::string uri; void to_json(Poco::JSON::Object &Obj) const;
std::string authenticationType{"internal_v1"}; bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const; };
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<SystemEndpoint> SystemEndpointVec;
struct SystemEndpointList { struct SystemEndpoint {
SystemEndpointVec endpoints; std::string type;
void to_json(Poco::JSON::Object &Obj) const; uint64_t id = 0;
bool from_json(const Poco::JSON::Object::Ptr &Obj); std::string vendor{"OpenWiFi"};
}; std::string uri;
std::string authenticationType{"internal_v1"};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<SystemEndpoint> SystemEndpointVec;
struct UserInfoAndPolicy { struct SystemEndpointList {
WebToken webtoken; SystemEndpointVec endpoints;
UserInfo userinfo; void to_json(Poco::JSON::Object &Obj) const;
void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj);
bool from_json(const Poco::JSON::Object::Ptr &Obj); };
};
typedef std::map<std::string,SecurityObjects::UserInfoAndPolicy> UserInfoCache;
enum ResourceAccessType { struct UserInfoAndPolicy {
NONE, WebToken webtoken;
READ, UserInfo userinfo;
MODIFY, void to_json(Poco::JSON::Object &Obj) const;
DELETE, bool from_json(const Poco::JSON::Object::Ptr &Obj);
CREATE, };
TEST, typedef std::map<std::string,SecurityObjects::UserInfoAndPolicy> UserInfoCache;
MOVE
};
ResourceAccessType ResourceAccessTypeFromString(const std::string &s); enum ResourceAccessType {
std::string ResourceAccessTypeToString(const ResourceAccessType & T); NONE,
READ,
MODIFY,
DELETE,
CREATE,
TEST,
MOVE
};
struct ProfileAction { ResourceAccessType ResourceAccessTypeFromString(const std::string &s);
std::string resource; std::string ResourceAccessTypeToString(const ResourceAccessType & T);
ResourceAccessType access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj);
};
typedef std::vector<ProfileAction> ProfileActionVec;
struct SecurityProfile { struct ProfileAction {
uint64_t id=0; std::string resource;
std::string name; ResourceAccessType access;
std::string description; void to_json(Poco::JSON::Object &Obj) const;
ProfileActionVec policy; bool from_json(Poco::JSON::Object::Ptr &Obj);
std::string role; };
NoteInfoVec notes; typedef std::vector<ProfileAction> ProfileActionVec;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr Obj);
};
typedef std::vector<SecurityProfile> SecurityProfileVec;
struct SecurityProfileList { struct SecurityProfile {
SecurityProfileVec profiles; uint64_t id=0;
void to_json(Poco::JSON::Object &Obj) const; std::string name;
bool from_json(Poco::JSON::Object::Ptr Obj); std::string description;
}; ProfileActionVec policy;
std::string role;
NoteInfoVec notes;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
typedef std::vector<SecurityProfile> SecurityProfileVec;
struct SecurityProfileList {
SecurityProfileVec profiles;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
enum LinkActions {
FORGOT_PASSWORD=1,
VERIFY_EMAIL,
SUB_FORGOT_PASSWORD,
SUB_VERIFY_EMAIL
};
struct ActionLink {
std::string id;
uint64_t action;
std::string userId;
std::string actionTemplate;
Types::StringPairVec variables;
std::string locale;
std::string message;
uint64_t sent=0;
uint64_t created=std::time(nullptr);
uint64_t expires=0;
uint64_t completed=0;
uint64_t canceled=0;
bool userAction=true;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
struct Preferences {
std::string id;
uint64_t modified;
Types::StringPairVec data;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
struct SubMfaConfig {
std::string id;
std::string type;
std::string sms;
std::string email;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
struct Token {
std::string token;
std::string refreshToken;
std::string tokenType;
std::string userName;
uint64_t created=0;
uint64_t expires=0;
uint64_t idleTimeout=0;
uint64_t revocationDate=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(Poco::JSON::Object::Ptr &Obj);
};
struct Avatar {
std::string id;
std::string type;
uint64_t created=0;
std::string name;
Poco::Data::LOB<char> avatar;
};
struct LoginRecordInfo {
std::string sessionId;
std::string userId;
std::string email;
uint64_t login=0;
uint64_t logout=0;
void to_json(Poco::JSON::Object &Obj) const;
};
}
} }
#endif //UCENTRAL_RESTAPI_SECURITYOBJECTS_H

View File

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

View File

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

View File

@@ -14,16 +14,19 @@
#include "framework/MicroService.h" #include "framework/MicroService.h"
namespace OpenWifi { namespace OpenWifi {
class SMSSender * SMSSender::instance_ = nullptr;
int SMSSender::Start() { int SMSSender::Start() {
Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws"); Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false);
if(Provider_=="aws") { if(Enabled_) {
ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws");
} else if(Provider_=="twilio") { if(Provider_=="aws") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger());
} else if(Provider_=="twilio") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger());
}
Enabled_ = ProviderImpl_->Initialize();
} }
Enabled_ = ProviderImpl_->Initialize();
return 0; return 0;
} }
@@ -74,7 +77,7 @@ namespace OpenWifi {
bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) { bool SMSSender::Send(const std::string &PhoneNumber, const std::string &Message) {
if(!Enabled_) { if(!Enabled_) {
Logger_.information("SMS has not been enabled. Messages cannot be sent."); Logger().information("SMS has not been enabled. Messages cannot be sent.");
return false; return false;
} }
return ProviderImpl_->Send(PhoneNumber,Message); return ProviderImpl_->Send(PhoneNumber,Message);

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ namespace OpenWifi {
PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber",""); PhoneNumber_ = MicroService::instance().ConfigGetString("smssender.twilio.phonenumber","");
if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) { if(Sid_.empty() || Token_.empty() || PhoneNumber_.empty()) {
Logger_.debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER."); Logger().debug("SMSSender is disabled. Please provide SID, TOKEN, and PHONE NUMBER.");
return false; return false;
} }
Running_=true; Running_=true;
@@ -64,12 +64,12 @@ namespace OpenWifi {
std::istream& rs = session.receiveResponse(res); std::istream& rs = session.receiveResponse(res);
if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { if(res.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
Logger_.information(Poco::format("Message sent to %s", PhoneNumber)); Logger().information(Poco::format("Message sent to %s", PhoneNumber));
return true; return true;
} else { } else {
std::ostringstream os; std::ostringstream os;
Poco::StreamCopier::copyStream(rs,os); Poco::StreamCopier::copyStream(rs,os);
Logger_.information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str())); Logger().information(Poco::format("Message was not to %s: Error:%s", PhoneNumber, os.str()));
return false; return false;
} }
} }

View File

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

View File

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

View File

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

37
src/SpecialUserHelpers.h Normal file
View File

@@ -0,0 +1,37 @@
//
// Created by stephane bourque on 2021-12-28.
//
#pragma once
#include "StorageService.h"
namespace OpenWifi {
namespace SpecialUserHelpers {
static inline std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"};
inline bool InitializeDefaultUser() {
SecurityObjects::UserInfo U;
bool DefaultUserCreated = false;
AppServiceRegistry().Get("defaultusercreated", DefaultUserCreated);
if (!StorageService()->UserDB().GetUserById(NewDefaultUseridStockUUID, U) && !DefaultUserCreated) {
U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password", "");
U.lastPasswords.push_back(U.currentPassword);
U.email = MicroService::instance().ConfigGetString("authentication.default.username", "");
U.id = NewDefaultUseridStockUUID;
U.userRole = SecurityObjects::ROOT;
U.creationDate = std::time(nullptr);
U.validated = true;
U.name = "Default User";
U.description = "Default user should be deleted.";
U.changePassword = true;
StorageService()->UserDB().CreateUser("SYSTEM", U, true);
AppServiceRegistry().Set("defaultusercreated", true);
return true;
}
return false;
}
}
}

View File

@@ -7,22 +7,69 @@
// //
#include "StorageService.h" #include "StorageService.h"
#include "SpecialUserHelpers.h"
namespace OpenWifi { namespace OpenWifi {
class Storage *Storage::instance_ = nullptr; int StorageService::Start() {
int Storage::Start() {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
StorageClass::Start(); StorageClass::Start();
Create_Tables();
UserCache_ = std::make_unique<OpenWifi::UserCache>(64,1200000,true);
SubCache_ = std::make_unique<OpenWifi::UserCache>(2048,1200000,false);
UserTokenCache_ = std::make_unique<OpenWifi::TokenCache>(64,1200000, true);
SubTokenCache_ = std::make_unique<OpenWifi::TokenCache>(2048,1200000,false);
UserDB_ = std::make_unique<OpenWifi::BaseUserDB>("Users", "usr", dbType_,*Pool_, Logger(), UserCache_.get(), true);
SubDB_ = std::make_unique<OpenWifi::BaseUserDB>("Subscribers", "sub", dbType_,*Pool_, Logger(), SubCache_.get(), false);
UserTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("Tokens", "tok", dbType_,*Pool_, Logger(), UserTokenCache_.get(), true);
SubTokenDB_ = std::make_unique<OpenWifi::BaseTokenDB>("SubTokens", "stk", dbType_,*Pool_, Logger(), SubTokenCache_.get(), false);
PreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("Preferences", "pre", dbType_,*Pool_, Logger());
SubPreferencesDB_ = std::make_unique<OpenWifi::PreferencesDB>("SubPreferences", "prs", dbType_,*Pool_, Logger());
ActionLinksDB_ = std::make_unique<OpenWifi::ActionLinkDB>("Actions", "act", dbType_,*Pool_, Logger());
AvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("Avatars", "ava", dbType_,*Pool_, Logger());
SubAvatarDB_ = std::make_unique<OpenWifi::AvatarDB>("SubAvatars", "avs", dbType_,*Pool_, Logger());
LoginDB_ = std::make_unique<OpenWifi::LoginDB>("Logins", "lin", dbType_,*Pool_, Logger());
SubLoginDB_ = std::make_unique<OpenWifi::LoginDB>("SubLogins", "lis", dbType_,*Pool_, Logger());
UserDB_->Create();
SubDB_->Create();
UserTokenDB_->Create();
SubTokenDB_->Create();
ActionLinksDB_->Create();
PreferencesDB_->Create();
SubPreferencesDB_->Create();
AvatarDB_->Create();
SubAvatarDB_->Create();
LoginDB_->Create();
SubLoginDB_->Create();
OpenWifi::SpecialUserHelpers::InitializeDefaultUser();
Archivercallback_ = std::make_unique<Poco::TimerCallback<Archiver>>(Archiver_,&Archiver::onTimer);
Timer_.setStartInterval( 5 * 60 * 1000); // first run in 5 minutes
Timer_.setPeriodicInterval(1 * 60 * 60 * 1000); // 1 hours
Timer_.start(*Archivercallback_);
return 0; return 0;
} }
void Storage::Stop() { void StorageService::Stop() {
Logger_.notice("Stopping."); Logger().notice("Stopping.");
Timer_.stop();
StorageClass::Stop(); StorageClass::Stop();
} }
void Archiver::onTimer(Poco::Timer &timer) {
Poco::Logger &logger = Poco::Logger::get("STORAGE-ARCHIVER");
logger.information("Squiggy the DB: removing old tokens.");
StorageService()->SubTokenDB().CleanExpiredTokens();
StorageService()->UserTokenDB().CleanExpiredTokens();
logger.information("Squiggy the DB: removing old actionLinks.");
StorageService()->ActionLinksDB().CleanOldActionLinks();
}
} }
// namespace // namespace

View File

@@ -13,151 +13,71 @@
#include "framework/StorageClass.h" #include "framework/StorageClass.h"
#include "AuthService.h" #include "AuthService.h"
#include "Poco/Timer.h"
#include "storage/orm_users.h"
#include "storage/orm_tokens.h"
#include "storage/orm_preferences.h"
#include "storage/orm_actionLinks.h"
#include "storage/orm_avatar.h"
#include "storage/orm_logins.h"
namespace OpenWifi { namespace OpenWifi {
static const std::string AllActionLinksFieldsForSelect { class Archiver {
"Id, " public:
"Action," void onTimer(Poco::Timer & timer);
"UserId," private:
"template,"
"locale,"
"message,"
"sent,"
"created,"
"expires,"
"completed,"
"canceled"
}; };
static const std::string AllActionLinksFieldsForUpdate { class StorageService : public StorageClass {
"Id=?, "
"Action=?,"
"UserId=?,"
"template=?,"
"locale=?,"
"message=?,"
"sent=?,"
"created=?,"
"expires=?,"
"completed=?,"
"canceled=?"
};
static const std::string AllEmailTemplatesFieldsForCreation {
};
static const std::string AllEmailTemplatesFieldsForSelect {
};
static const std::string AllEmailTemplatesFieldsForUpdate {
};
class Storage : public StorageClass {
public: public:
enum AUTH_ERROR { static auto instance() {
SUCCESS, static auto instance_ = new StorageService;
PASSWORD_CHANGE_REQUIRED,
PASSWORD_DOES_NOT_MATCH,
PASSWORD_ALREADY_USED,
USERNAME_PENDING_VERIFICATION,
PASSWORD_INVALID,
INTERNAL_ERROR
};
enum USER_TYPE {
UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, SPECIAL
};
typedef std::string USER_ID_TYPE;
static USER_TYPE to_userType(const std::string &U) {
if (U=="root")
return ROOT;
else if (U=="admin")
return ADMIN;
else if (U=="subscriber")
return SUBSCRIBER;
else if (U=="csr")
return CSR;
else if (U=="system")
return SYSTEM;
else if (U=="SPECIAL")
return SPECIAL;
return UNKNOWN;
}
static const std::string from_userType(USER_TYPE U) {
switch(U) {
case ROOT: return "root";
case ADMIN: return "admin";
case SUBSCRIBER: return "subscriber";
case CSR: return "csr";
case SYSTEM: return "system";
case SPECIAL: return "special";
case UNKNOWN:
default: return "unknown";
}
}
static Storage *instance() {
if (instance_ == nullptr) {
instance_ = new Storage;
}
return instance_; return instance_;
} }
int Start() override; int Start() override;
void Stop() override; void Stop() override;
/* OpenWifi::BaseUserDB & UserDB() { return *UserDB_; }
* All user management functions OpenWifi::BaseUserDB & SubDB() { return *SubDB_; }
*/ OpenWifi::BaseTokenDB & UserTokenDB() { return *UserTokenDB_; }
bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser); OpenWifi::BaseTokenDB & SubTokenDB() { return *SubTokenDB_; }
bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); OpenWifi::PreferencesDB & PreferencesDB() { return *PreferencesDB_; }
bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); OpenWifi::PreferencesDB & SubPreferencesDB() { return *SubPreferencesDB_; }
bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); OpenWifi::ActionLinkDB & ActionLinksDB() { return *ActionLinksDB_; }
bool SetOwner(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Owner); OpenWifi::AvatarDB & AvatarDB() { return *AvatarDB_; }
bool SetLocation(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Location); OpenWifi::AvatarDB & SubAvatarDB() { return *SubAvatarDB_; }
AUTH_ERROR ChangePassword(const std::string & Admin, USER_ID_TYPE & Id, const std::string &OldPassword, const std::string &NewPassword); OpenWifi::LoginDB & LoginDB() { return *LoginDB_; }
bool AddNotes(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Notes); OpenWifi::LoginDB & SubLoginDB() { return *SubLoginDB_; }
bool SetPolicyChange(const std::string & Admin, USER_ID_TYPE & Id, const std::string &NewPolicy);
bool UpdateUserInfo(const std::string & Admin, USER_ID_TYPE & Id, SecurityObjects::UserInfo &UInfo);
bool GetUsers( uint64_t Offset, uint64_t Limit, SecurityObjects::UserInfoVec & Users);
bool SetLastLogin(USER_ID_TYPE & Id);
bool SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name);
bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name);
bool DeleteAvatar(const std::string & Admin, std::string &Id);
bool AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut);
bool RevokeToken( std::string & Token );
bool IsTokenRevoked( std::string & Token );
bool CleanRevokedTokens( uint64_t Oldest );
bool RevokeAllTokens( std::string & UserName );
bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo);
/*
* All ActionLinks functions
*/
bool CreateAction(std::string &ActionId, std::string &Action, USER_ID_TYPE & Id, Types::StringPairVec & Elements );
bool DeleteAction(std::string &ActionId);
bool CompleteAction(std::string &ActionId);
bool CancelAction(std::string &ActionId);
private: private:
static Storage *instance_;
int Create_Tables(); std::unique_ptr<OpenWifi::BaseUserDB> UserDB_;
int Create_UserTable(); std::unique_ptr<OpenWifi::BaseUserDB> SubDB_;
int Create_AvatarTable(); std::unique_ptr<OpenWifi::BaseTokenDB> UserTokenDB_;
int Create_TokensTable(); std::unique_ptr<OpenWifi::BaseTokenDB> SubTokenDB_;
std::unique_ptr<OpenWifi::PreferencesDB> PreferencesDB_;
std::unique_ptr<OpenWifi::PreferencesDB> SubPreferencesDB_;
std::unique_ptr<OpenWifi::ActionLinkDB> ActionLinksDB_;
std::unique_ptr<OpenWifi::AvatarDB> AvatarDB_;
std::unique_ptr<OpenWifi::AvatarDB> SubAvatarDB_;
std::unique_ptr<OpenWifi::LoginDB> LoginDB_;
std::unique_ptr<OpenWifi::LoginDB> SubLoginDB_;
std::unique_ptr<OpenWifi::UserCache> UserCache_;
std::unique_ptr<OpenWifi::UserCache> SubCache_;
std::unique_ptr<OpenWifi::TokenCache> UserTokenCache_;
std::unique_ptr<OpenWifi::TokenCache> SubTokenCache_;
Poco::Timer Timer_;
Archiver Archiver_;
std::unique_ptr<Poco::TimerCallback<Archiver>> Archivercallback_;
}; };
inline Storage * StorageService() { return Storage::instance(); }; inline auto StorageService() { return StorageService::instance(); };
} // namespace } // namespace

173
src/TotpCache.h Normal file
View File

@@ -0,0 +1,173 @@
//
// Created by stephane bourque on 2022-01-31.
//
#ifndef OWSEC_TOTPCACHE_H
#define OWSEC_TOTPCACHE_H
#include "framework/MicroService.h"
#include "seclibs/cpptotp/bytes.h"
#include "seclibs/qrcode/qrcodegen.hpp"
#include "seclibs/cpptotp/otp.h"
namespace OpenWifi {
class TotpCache : public SubSystemServer {
public:
struct Entry {
bool Subscriber=false;
uint64_t Start = 0;
uint64_t Done = 0 ;
uint64_t Verifications = 0 ;
std::string Secret;
std::string QRCode;
std::string LastCode;
};
static auto instance() {
static auto instance = new TotpCache;
return instance;
}
static std::string GenerateSecret(uint Size, std::string & Base32Secret) {
std::string R;
for(;Size;Size--) {
R += (char) MicroService::instance().Random(33,127);
}
Base32Secret = CppTotp::Bytes::toBase32( CppTotp::Bytes::ByteString{ (const u_char *)R.c_str()});
return R;
}
std::string GenerateQRCode(const std::string &Secret, const std::string &email) {
std::string uri{
"otpauth://totp/" + Issuer_ + ":" +
email + "?secret=" + Secret + "&issuer=" + Issuer_
};
qrcodegen::QrCode qr0 = qrcodegen::QrCode::encodeText(uri.c_str(), qrcodegen::QrCode::Ecc::MEDIUM);
std::string svg = qrcodegen::toSvgString(qr0, 4); // See QrCodeGeneratorDemo
return svg;
}
static bool ValidateCode( const std::string &Secret, const std::string &Code, std::string & Expecting) {
uint64_t Now = std::time(nullptr);
uint32_t p = CppTotp::totp(CppTotp::Bytes::ByteString{ (const u_char *)Secret.c_str()}, Now, 0, 30, 6);
char buffer[16];
sprintf(buffer,"%06u",p);
Expecting = buffer;
return Code == buffer;
}
int Start() override {
Issuer_ = MicroService::instance().ConfigGetString("totp.issuer","OpenWiFi");
return 0;
};
void Stop() override {
};
inline bool StartValidation(const SecurityObjects::UserInfo &User, bool Subscriber, std::string & QRCode, bool Reset) {
auto Hint = Cache_.find(User.id);
if(Hint!=Cache_.end() && Hint->second.Subscriber==Subscriber) {
if(Reset) {
std::string Base32Secret;
Hint->second.Subscriber = Subscriber;
Hint->second.Start = std::time(nullptr);
Hint->second.Done = 0;
Hint->second.Verifications = 0;
Hint->second.Secret = GenerateSecret(20,Base32Secret);
Hint->second.QRCode = QRCode = GenerateQRCode(Base32Secret, User.email);
Hint->second.LastCode.clear();
} else {
QRCode = Hint->second.QRCode;
}
return true;
}
std::string Base32Secret;
auto Secret = GenerateSecret(20, Base32Secret);
QRCode = GenerateQRCode(Base32Secret, User.email);
Entry E{ .Subscriber = Subscriber,
.Start = (uint64_t )std::time(nullptr),
.Done = 0,
.Verifications = 0,
.Secret = Secret,
.QRCode = QRCode
};
Cache_[User.id] = E;
return true;
}
inline bool ContinueValidation(const SecurityObjects::UserInfo &User, bool Subscriber, const std::string & Code,
uint64_t &NextIndex, bool &MoreCodes, uint64_t & ErrorCode, std::string & ErrorText ) {
auto Hint = Cache_.find(User.id);
uint64_t Now = std::time(nullptr);
ErrorCode = 0;
if(Hint!=Cache_.end() && Subscriber==Hint->second.Subscriber && (Now-Hint->second.Start)<(15*60)) {
std::string Expecting;
if (NextIndex == 1 && Hint->second.Verifications == 0 && ValidateCode(Hint->second.Secret, Code, Expecting)) {
NextIndex++;
Hint->second.Verifications++;
MoreCodes = true;
Hint->second.LastCode = Code;
return true;
} else if (NextIndex == 2 && Hint->second.Verifications == 1 && Code != Hint->second.LastCode &&
ValidateCode(Hint->second.Secret, Code, Expecting) ) {
MoreCodes = false;
Hint->second.Done = Now;
return true;
} else {
if(!ValidateCode(Hint->second.Secret, Code, Expecting)) {
ErrorCode = 1;
ErrorText = "Invalid code.";
return false;
} else if(NextIndex!=1 && NextIndex != 2) {
ErrorCode = 2;
ErrorText = "Invalid Index";
return false;
} else if(Code == Hint->second.LastCode) {
ErrorCode = 3;
ErrorText = "Code is repeated. Must be new code.";
return false;
}
ErrorCode = 5;
ErrorText = "Invalid protocol sequence.";
return false;
}
} else {
ErrorCode = 4;
ErrorText = "No validation session present.";
}
return false;
}
inline bool CompleteValidation(const SecurityObjects::UserInfo &User, bool Subscriber, std::string & Secret) {
auto Hint = Cache_.find(User.id);
uint64_t Now = std::time(nullptr);
if(Hint!=Cache_.end() && Subscriber==Hint->second.Subscriber && (Now-Hint->second.Start)<(15*60) && Hint->second.Done!=0) {
Secret = Hint->second.Secret;
Cache_.erase(Hint);
return true;
}
return false;
}
private:
std::map<std::string,Entry> Cache_;
std::string Issuer_;
TotpCache() noexcept:
SubSystemServer("TOTP-system", "TOTP-SVR", "totp") {
}
};
inline auto TotpCache() { return TotpCache::instance(); }
}
#endif //OWSEC_TOTPCACHE_H

93
src/framework/API_Proxy.h Normal file
View File

@@ -0,0 +1,93 @@
//
// Created by stephane bourque on 2021-11-30.
//
#pragma once
#include "framework/MicroService.h"
#include "Poco/JSON/Parser.h"
namespace OpenWifi {
inline void API_Proxy( Poco::Logger &Logger,
Poco::Net::HTTPServerRequest *Request,
Poco::Net::HTTPServerResponse *Response,
const char * ServiceType,
const char * PathRewrite,
uint64_t msTimeout_ = 10000 ) {
try {
auto Services = MicroService::instance().GetServices(ServiceType);
for(auto const &Svc:Services) {
Poco::URI SourceURI(Request->getURI());
Poco::URI DestinationURI(Svc.PrivateEndPoint);
DestinationURI.setPath(PathRewrite);
DestinationURI.setQuery(SourceURI.getQuery());
// std::cout << " Source: " << SourceURI.toString() << std::endl;
// std::cout << "Destination: " << DestinationURI.toString() << std::endl;
Poco::Net::HTTPSClientSession Session(DestinationURI.getHost(), DestinationURI.getPort());
Session.setKeepAlive(true);
Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000));
Poco::Net::HTTPRequest ProxyRequest(Request->getMethod(),
DestinationURI.getPathAndQuery(),
Poco::Net::HTTPMessage::HTTP_1_1);
if(Request->has("Authorization")) {
ProxyRequest.add("Authorization", Request->get("Authorization"));
} else {
ProxyRequest.add("X-API-KEY", Svc.AccessKey);
ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint());
}
if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
Session.sendRequest(ProxyRequest);
Poco::Net::HTTPResponse ProxyResponse;
Session.receiveResponse(ProxyResponse);
Response->setStatus(ProxyResponse.getStatus());
Response->send();
return;
} else {
Poco::JSON::Parser P;
std::stringstream SS;
try {
auto Body = P.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>();
Poco::JSON::Stringifier::condense(Body,SS);
SS << "\r\n\r\n";
} catch(const Poco::Exception &E) {
Logger.log(E);
}
if(SS.str().empty()) {
Session.sendRequest(ProxyRequest);
} else {
ProxyRequest.setContentType("application/json");
ProxyRequest.setContentLength(SS.str().size());
std::ostream & os = Session.sendRequest(ProxyRequest);
os << SS.str() ;
}
Poco::Net::HTTPResponse ProxyResponse;
std::stringstream SSR;
try {
std::istream &ProxyResponseStream = Session.receiveResponse(ProxyResponse);
Poco::JSON::Parser P2;
auto ProxyResponseBody = P2.parse(ProxyResponseStream).extract<Poco::JSON::Object::Ptr>();
Poco::JSON::Stringifier::condense(ProxyResponseBody,SSR);
Response->setContentType("application/json");
Response->setContentLength(SSR.str().size());
Response->setStatus(ProxyResponse.getStatus());
Response->sendBuffer(SSR.str().c_str(),SSR.str().size());
return;
} catch( const Poco::Exception & E) {
}
Response->setStatus(ProxyResponse.getStatus());
Response->send();
return;
}
}
} catch (const Poco::Exception &E) {
Logger.log(E);
}
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -2,8 +2,7 @@
// Created by stephane bourque on 2021-10-08. // Created by stephane bourque on 2021-10-08.
// //
#ifndef OWPROV_COUNTRYCODES_H #pragma once
#define OWPROV_COUNTRYCODES_H
#include <vector> #include <vector>
#include <string> #include <string>
@@ -270,4 +269,3 @@ namespace OpenWifi {
} }
#endif //OWPROV_COUNTRYCODES_H

View File

@@ -5,8 +5,8 @@
// Created by Stephane Bourque on 2021-03-04. // Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#ifndef UCENTRALGW_KAFKA_TOPICS_H
#define UCENTRALGW_KAFKA_TOPICS_H #pragma once
namespace OpenWifi::KafkaTopics { namespace OpenWifi::KafkaTopics {
static const std::string HEALTHCHECK{"healthcheck"}; static const std::string HEALTHCHECK{"healthcheck"};
@@ -17,6 +17,7 @@ namespace OpenWifi::KafkaTopics {
static const std::string COMMAND{"command"}; static const std::string COMMAND{"command"};
static const std::string SERVICE_EVENTS{"service_events"}; static const std::string SERVICE_EVENTS{"service_events"};
static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"}; static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"};
static const std::string DEVICE_TELEMETRY{"device_telemetry"};
namespace ServiceEvents { namespace ServiceEvents {
static const std::string EVENT_JOIN{"join"}; static const std::string EVENT_JOIN{"join"};
@@ -37,4 +38,3 @@ namespace OpenWifi::KafkaTopics {
} }
} }
#endif // UCENTRALGW_KAFKA_TOPICS_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,38 @@
// //
// License type: BSD 3-Clause License // Created by stephane bourque on 2021-11-16.
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
//
// Created by Stephane Bourque on 2021-03-04.
// Arilia Wireless Inc.
// //
#ifndef UCENTRALGW_UCENTRALTYPES_H #pragma once
#define UCENTRALGW_UCENTRALTYPES_H
#include <vector>
#include <string>
#include <map> #include <map>
#include <functional>
#include <list>
#include <utility> #include <utility>
#include <vector>
#include <functional>
#include <string>
#include <queue> #include <queue>
#include <list>
#include "Poco/StringTokenizer.h" #include <set>
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/Stringifier.h"
namespace OpenWifi::Types { namespace OpenWifi::Types {
typedef std::pair<std::string,std::string> StringPair; typedef std::pair<std::string,std::string> StringPair;
typedef std::vector<StringPair> StringPairVec; typedef std::vector<StringPair> StringPairVec;
typedef std::queue<StringPair> StringPairQueue; typedef std::queue<StringPair> StringPairQueue;
typedef std::vector<std::string> StringVec; typedef std::vector<std::string> StringVec;
typedef std::set<std::string> StringSet; typedef std::set<std::string> StringSet;
typedef std::map<std::string,std::set<std::string>> StringMapStringSet; typedef std::map<std::string,std::set<std::string>> StringMapStringSet;
typedef std::function<void(std::string, std::string)> TopicNotifyFunction; typedef std::function<void(const std::string &, const std::string &)> TopicNotifyFunction;
typedef std::list<std::pair<TopicNotifyFunction,int>> TopicNotifyFunctionList; typedef std::list<std::pair<TopicNotifyFunction,int>> TopicNotifyFunctionList;
typedef std::map<std::string, TopicNotifyFunctionList> NotifyTable; typedef std::map<std::string, TopicNotifyFunctionList> NotifyTable;
typedef std::map<std::string,uint64_t> CountedMap; typedef std::map<std::string,uint64_t> CountedMap;
typedef std::vector<uint64_t> TagList; typedef std::vector<uint64_t> TagList;
typedef std::string UUID_t; typedef std::string UUID_t;
typedef std::vector<UUID_t> UUIDvec_t; typedef std::vector<UUID_t> UUIDvec_t;
typedef std::map<std::string,std::map<uint32_t,uint64_t>> Counted3DMapSII;
}
inline void UpdateCountedMap(CountedMap &M, const std::string &S, uint64_t Increment=1) { namespace OpenWifi {
inline void UpdateCountedMap(OpenWifi::Types::CountedMap &M, const std::string &S, uint64_t Increment=1) {
auto it = M.find(S); auto it = M.find(S);
if(it==M.end()) if(it==M.end())
M[S] = Increment; M[S] = Increment;
@@ -44,60 +40,21 @@ namespace OpenWifi::Types {
it->second += Increment; it->second += Increment;
} }
inline std::string to_string( const StringVec &V) { inline void UpdateCountedMap(OpenWifi::Types::Counted3DMapSII &M, const std::string &S, uint32_t Index, uint64_t Increment=1) {
Poco::JSON::Array O; auto it = M.find(S);
for(const auto &i:V) { if(it==M.end()) {
O.add(i); std::map<uint32_t,uint64_t> E;
E[Index] = Increment;
M[S] = E;
} }
std::stringstream SS; else {
Poco::JSON::Stringifier::stringify(O,SS); std::map<uint32_t,uint64_t> & IndexMap = it->second;
return SS.str(); auto it_index = IndexMap.find(Index);
} if(it_index == IndexMap.end()) {
IndexMap[Index] = Increment;
inline std::string to_string( const StringPairVec &V) { } else {
Poco::JSON::Array O; it_index->second += Increment;
for(const auto &i:V) {
Poco::JSON::Array OO;
OO.add(i.first);
OO.add(i.second);
O.add(OO);
}
std::stringstream SS;
Poco::JSON::Stringifier::stringify(O,SS);
return SS.str();
}
inline void from_string(const std::string &S, StringPairVec &V) {
try {
Poco::JSON::Parser P;
auto O = P.parse(S).extract<Poco::JSON::Array::Ptr>();
for(const auto &i:*O) {
auto Inner = i.extract<Poco::JSON::Array::Ptr>();
for(const auto &j:*Inner) {
auto S1 = i[0].toString();
auto S2 = i[1].toString();
V.push_back(std::make_pair(S1,S2));
}
} }
} catch (...) {
} }
} }
}
inline void from_string(const std::string &S, StringVec &V) {
try {
Poco::JSON::Parser P;
auto O = P.parse(S).extract<Poco::JSON::Array::Ptr>();
for(auto const &i:*O) {
V.push_back(i.toString());
}
} catch (...) {
}
}
};
#endif // UCENTRALGW_UCENTRALTYPES_H

View File

@@ -2,8 +2,7 @@
// Created by stephane bourque on 2021-09-12. // Created by stephane bourque on 2021-09-12.
// //
#ifndef OWPROV_RESTAPI_ERRORS_H #pragma once
#define OWPROV_RESTAPI_ERRORS_H
namespace OpenWifi::RESTAPI::Errors { namespace OpenWifi::RESTAPI::Errors {
static const std::string MissingUUID{"Missing UUID."}; static const std::string MissingUUID{"Missing UUID."};
@@ -15,7 +14,7 @@ namespace OpenWifi::RESTAPI::Errors {
static const std::string CouldNotBeDeleted{"Element could not be deleted."}; static const std::string CouldNotBeDeleted{"Element could not be deleted."};
static const std::string NameMustBeSet{"The name property must be set."}; static const std::string NameMustBeSet{"The name property must be set."};
static const std::string ConfigBlockInvalid{"Configuration block type invalid."}; static const std::string ConfigBlockInvalid{"Configuration block type invalid."};
static const std::string UnknownId{"Unknown management policy."}; static const std::string UnknownId{"Unknown UUID."};
static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."}; static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."};
static const std::string RecordNotCreated{"Record could not be created."}; static const std::string RecordNotCreated{"Record could not be created."};
static const std::string RecordNotUpdated{"Record could not be updated."}; static const std::string RecordNotUpdated{"Record could not be updated."};
@@ -47,13 +46,23 @@ namespace OpenWifi::RESTAPI::Errors {
static const std::string IdMustBe0{"To create a user, you must set the ID to 0"}; static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
static const std::string InvalidUserRole{"Invalid userRole."}; static const std::string InvalidUserRole{"Invalid userRole."};
static const std::string InvalidEmailAddress{"Invalid email address."}; static const std::string InvalidEmailAddress{"Invalid email address."};
static const std::string InvalidPassword{"Invalid password."};
static const std::string PasswordRejected{"Password was rejected. This maybe an old password."}; static const std::string PasswordRejected{"Password was rejected. This maybe an old password."};
static const std::string InvalidIPRanges{"Invalid IP range specifications."}; static const std::string InvalidIPRanges{"Invalid IP range specifications."};
static const std::string InvalidLOrderBy{"Invalid orderBy specification."}; static const std::string InvalidLOrderBy{"Invalid orderBy specification."};
static const std::string NeedMobileNumber{"You must provide at least one validated phone number."}; static const std::string NeedMobileNumber{"You must provide at least one validated phone number."};
static const std::string BadMFAMethod{"MFA only supports sms or email."}; static const std::string BadMFAMethod{"MFA only supports sms or email."};
static const std::string InvalidCredentials{"Invalid credentials (username/password)."};
static const std::string InvalidPassword{"Password does not conform to basic password rules."};
static const std::string UserPendingVerification{"User access denied pending email verification."};
static const std::string PasswordMustBeChanged{"Password must be changed."};
static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
static const std::string MissingAuthenticationInformation{"Missing authentication information."};
static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
static const std::string ExpiredToken{"Token has expired, user must login."};
static const std::string SubscriberMustExist{"Subscriber must exist."};
static const std::string AuthenticatorVerificationIncomplete{"Authenticator validation is not complete."};
static const std::string SMSCouldNotBeSentRetry{"SMS could not be sent to validate device, try later or change the phone number."};
static const std::string SMSCouldNotValidate{"Code and number could not be validated"};
static const std::string InvalidDeviceClass{"Invalid device class. Must be: any, venue, entity, or subscriber"};
} }
#endif //OWPROV_RESTAPI_ERRORS_H

View File

@@ -6,8 +6,7 @@
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#ifndef UCENTRALGW_RESTAPI_PROTOCOL_H #pragma once
#define UCENTRALGW_RESTAPI_PROTOCOL_H
namespace OpenWifi::RESTAPI::Protocol { namespace OpenWifi::RESTAPI::Protocol {
static const char * CAPABILITIES = "capabilities"; static const char * CAPABILITIES = "capabilities";
@@ -85,11 +84,13 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char * GETSUBSYSTEMNAMES = "getsubsystemnames"; static const char * GETSUBSYSTEMNAMES = "getsubsystemnames";
static const char * GETLOGLEVELNAMES = "getloglevelnames"; static const char * GETLOGLEVELNAMES = "getloglevelnames";
static const char * STATS = "stats"; static const char * STATS = "stats";
static const char * PING = "ping";
static const char * PARAMETERS = "parameters"; static const char * PARAMETERS = "parameters";
static const char * VALUE = "value"; static const char * VALUE = "value";
static const char * LASTONLY = "lastOnly"; static const char * LASTONLY = "lastOnly";
static const char * NEWEST = "newest"; static const char * NEWEST = "newest";
static const char * ACTIVESCAN = "activeScan"; static const char * ACTIVESCAN = "activeScan";
static const char * OVERRIDEDFS = "override_dfs";
static const char * LIST = "list"; static const char * LIST = "list";
static const char * TAG = "tag"; static const char * TAG = "tag";
static const char * TAGLIST = "tagList"; static const char * TAGLIST = "tagList";
@@ -136,5 +137,3 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char * UI = "UI"; static const char * UI = "UI";
} }
#endif // UCENTRALGW_RESTAPI_PROTOCOL_H

View File

@@ -2,8 +2,7 @@
// Created by stephane bourque on 2021-10-06. // Created by stephane bourque on 2021-10-06.
// //
#ifndef OPENWIFI_STORAGE_H #pragma once
#define OPENWIFI_STORAGE_H
#include "Poco/Data/Session.h" #include "Poco/Data/Session.h"
#include "Poco/Data/SessionPool.h" #include "Poco/Data/SessionPool.h"
@@ -26,13 +25,6 @@ namespace OpenWifi {
class StorageClass : public SubSystemServer { class StorageClass : public SubSystemServer {
public: public:
/* static StorageClass *instance() {
if (instance_ == nullptr) {
instance_ = new StorageClass;
}
return instance_;
}
*/
StorageClass() noexcept: StorageClass() noexcept:
SubSystemServer("StorageClass", "STORAGE-SVR", "storage") SubSystemServer("StorageClass", "STORAGE-SVR", "storage")
{ {
@@ -41,8 +33,8 @@ namespace OpenWifi {
int Start() override { int Start() override {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
Logger_.setLevel(Poco::Message::PRIO_NOTICE); Logger().setLevel(Poco::Message::PRIO_INFORMATION);
Logger_.notice("Starting."); Logger().notice("Starting.");
std::string DBType = MicroService::instance().ConfigGetString("storage.type"); std::string DBType = MicroService::instance().ConfigGetString("storage.type");
if (DBType == "sqlite") { if (DBType == "sqlite") {
@@ -56,38 +48,7 @@ namespace OpenWifi {
} }
void Stop() override { void Stop() override {
Pool_->shutdown();
}
[[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
if(dbType_==sqlite) {
return " LIMIT " + std::to_string(From-1) + ", " + std::to_string(HowMany) + " ";
} else if(dbType_==pgsql) {
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " ";
} else if(dbType_==mysql) {
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " ";
}
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " ";
}
inline std::string ConvertParams(const std::string & S) const {
std::string R;
R.reserve(S.size()*2+1);
if(dbType_==pgsql) {
auto Idx=1;
for(auto const & i:S)
{
if(i=='?') {
R += '$';
R.append(std::to_string(Idx++));
} else {
R += i;
}
}
} else {
R = S;
}
return R;
} }
private: private:
@@ -96,34 +57,31 @@ namespace OpenWifi {
inline int Setup_PostgreSQL(); inline int Setup_PostgreSQL();
protected: protected:
std::unique_ptr<Poco::Data::SessionPool> Pool_; Poco::SharedPtr<Poco::Data::SessionPool> Pool_;
std::unique_ptr<Poco::Data::SQLite::Connector> SQLiteConn_; Poco::Data::SQLite::Connector SQLiteConn_;
std::unique_ptr<Poco::Data::PostgreSQL::Connector> PostgresConn_; Poco::Data::PostgreSQL::Connector PostgresConn_;
std::unique_ptr<Poco::Data::MySQL::Connector> MySQLConn_; Poco::Data::MySQL::Connector MySQLConn_;
DBType dbType_ = sqlite; DBType dbType_ = sqlite;
}; };
// inline StorageClass * Storage() { return StorageClass::instance(); }
#ifdef SMALL_BUILD #ifdef SMALL_BUILD
int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; }
#else #else
inline int StorageClass::Setup_SQLite() { inline int StorageClass::Setup_SQLite() {
Logger_.notice("SQLite StorageClass enabled."); Logger().notice("SQLite StorageClass enabled.");
dbType_ = sqlite; dbType_ = sqlite;
auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db");
auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64);
auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60); auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60);
SQLiteConn_ = std::make_unique<Poco::Data::SQLite::Connector>(); SQLiteConn_.registerConnector();
SQLiteConn_->registerConnector(); Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 4, NumSessions, IdleTime));
Pool_ = std::make_unique<Poco::Data::SessionPool>(SQLiteConn_->name(), DBName, 4, NumSessions, IdleTime);
return 0; return 0;
} }
inline int StorageClass::Setup_MySQL() { inline int StorageClass::Setup_MySQL() {
Logger_.notice("MySQL StorageClass enabled."); Logger().notice("MySQL StorageClass enabled.");
dbType_ = mysql; dbType_ = mysql;
auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64); auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64);
auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60); auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60);
@@ -141,15 +99,14 @@ namespace OpenWifi {
";port=" + Port + ";port=" + Port +
";compress=true;auto-reconnect=true"; ";compress=true;auto-reconnect=true";
MySQLConn_ = std::make_unique<Poco::Data::MySQL::Connector>(); MySQLConn_.registerConnector();
MySQLConn_->registerConnector(); Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(MySQLConn_.name(), ConnectionStr, 4, NumSessions, IdleTime));
Pool_ = std::make_unique<Poco::Data::SessionPool>(MySQLConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
return 0; return 0;
} }
inline int StorageClass::Setup_PostgreSQL() { inline int StorageClass::Setup_PostgreSQL() {
Logger_.notice("PostgreSQL StorageClass enabled."); Logger().notice("PostgreSQL StorageClass enabled.");
dbType_ = pgsql; dbType_ = pgsql;
auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64); auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64);
auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60); auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60);
@@ -168,14 +125,11 @@ namespace OpenWifi {
" port=" + Port + " port=" + Port +
" connect_timeout=" + ConnectionTimeout; " connect_timeout=" + ConnectionTimeout;
PostgresConn_ = std::make_unique<Poco::Data::PostgreSQL::Connector>(); PostgresConn_.registerConnector();
PostgresConn_->registerConnector(); Pool_ = Poco::SharedPtr<Poco::Data::SessionPool>(new Poco::Data::SessionPool(PostgresConn_.name(), ConnectionStr, 4, NumSessions, IdleTime));
Pool_ = std::make_unique<Poco::Data::SessionPool>(PostgresConn_->name(), ConnectionStr, 4, NumSessions, IdleTime);
return 0; return 0;
} }
#endif #endif
} }
#endif //OPENWIFI_STORAGE_H

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