Compare commits

...

72 Commits

Author SHA1 Message Date
Dmitry Dunaev
95ea70d5c2 [WIFI-10236] Chg: helm image to the working one
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-07-22 14:57:49 +03:00
TIP Automation User
8b40de4631 Chg: update image tag in helm values to v2.4.2 2022-07-21 15:08:53 +00:00
Dmitry Dunaev
b1740575a5 [WIFI-1998] Add: gracefull ingress deprecationush
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-07-21 17:42:49 +03:00
TIP Automation User
02057624de Chg: update image tag in helm values to v2.4.1 2022-07-21 13:50:28 +00:00
Dmitry Dunaev
2e394d0513 [WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-07-21 16:41:24 +03:00
TIP Automation User
24b022fa60 Chg: update image tag in helm values to v2.4.0 2021-12-17 02:36:54 +00:00
Johann Hoffmann
88922786ff [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:30:30 +01:00
TIP Automation User
4510cd034f Chg: update image tag in helm values to v2.4.0-RC5 2021-12-11 08:12:29 +00:00
stephb9959
af5774ce36 Fix for https://telecominfraproject.atlassian.net/browse/WIFI-6149 2021-12-10 10:29:24 -08:00
stephb9959
2573b8cd4f Merge remote-tracking branch 'origin/release/v2.4.0' into release/v2.4.0
# Conflicts:
#	Dockerfile
2021-12-10 10:25:06 -08:00
stephb9959
9c5b18a536 Fix for https://telecominfraproject.atlassian.net/browse/WIFI-6149 2021-12-10 10:23:15 -08:00
TIP Automation User
768c428a67 Chg: update image tag in helm values to v2.4.0-RC4 2021-12-08 07:42:41 +00:00
Dmitry Dunaev
389ceb8b7d Add: .git dir to build image to expose git hash for version
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2021-12-08 10:28:53 +03:00
stephb9959
157f18c117 Merge remote-tracking branch 'origin/release/v2.4.0' into release/v2.4.0 2021-12-06 09:13:49 -08:00
stephb9959
2538f9c768 Adding Git Hash to version numbers. No Jira. 2021-12-06 09:13:41 -08:00
TIP Automation User
85d998ad76 Chg: update image tag in helm values to v2.4.0-RC3 2021-12-06 15:58:02 +00:00
stephb9959
a407f2e38d Fix for https://telecominfraproject.atlassian.net/browse/WIFI-6048 2021-12-05 12:10:04 -08:00
Dmitry Dunaev
d0d2be0870 Chg: helm image in values to new release candidate 2021-11-22 14:57:54 +03:00
stephb9959
78cba562e6 Solving https://telecominfraproject.atlassian.net/browse/WIFI-5780 2021-11-19 11:02:29 -08:00
Leonid Mirsky
350df38c3f Update Helm values to v2.4.0-RC1
Signed-off-by: Leonid Mirsky <leonid@opsfleet.com>
2021-11-16 23:34:10 +02: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
44 changed files with 3307 additions and 439 deletions

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

@@ -30,9 +30,20 @@ else()
file(WRITE build ${BUILD_NUM}) file(WRITE build ${BUILD_NUM})
endif() endif()
set(BUILD_SHARED_LIBS 1) 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)
add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}") set(BUILD_SHARED_LIBS 1)
add_definitions(-DTIP_SECURITY_SERVICE="1") add_definitions(-DTIP_SECURITY_SERVICE="1")
set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_STATIC_LIBS OFF)
@@ -50,8 +61,11 @@ 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
@@ -90,7 +104,7 @@ add_executable( owsec
src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
src/storage/storage_tokens.h src/storage/storage_tokens.h
src/ActionLinkManager.cpp src/ActionLinkManager.h src/ActionLinkManager.cpp src/ActionLinkManager.h
) src/ACLProcessor.h)
if(NOT SMALL_BUILD) if(NOT SMALL_BUILD)
target_link_libraries(owsec PUBLIC target_link_libraries(owsec PUBLIC

View File

@@ -53,9 +53,12 @@ RUN cmake ..
RUN make RUN make
RUN make install RUN make 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
WORKDIR /owsec WORKDIR /owsec
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -75,7 +78,7 @@ 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 RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates libcurl curl-dev bash jq curl postgresql-client
COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec COPY --from=builder /owsec/cmake-build/owsec /openwifi/owsec
COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/ COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/
COPY --from=builder /poco/cmake-build/lib/* /lib/ COPY --from=builder /poco/cmake-build/lib/* /lib/
@@ -87,10 +90,12 @@ 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 readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
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.

2
build
View File

@@ -1 +1 @@
47 109

1
helm/.gitignore vendored
View File

@@ -1 +1,2 @@
*.swp *.swp
charts

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

@@ -30,3 +30,13 @@ Create chart name and version as used by the chart label.
{{- define "owsec.chart" -}} {{- define "owsec.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}} {{- end -}}
{{- define "owsec.ingress.apiVersion" -}}
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}}
{{- print "networking.k8s.io/v1" -}}
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
{{- print "networking.k8s.io/v1beta1" -}}
{{- else -}}
{{- print "extensions/v1beta1" -}}
{{- end -}}
{{- end -}}

View File

@@ -2,7 +2,7 @@
{{- range $ingress, $ingressValue := .Values.ingresses }} {{- range $ingress, $ingressValue := .Values.ingresses }}
{{- if $ingressValue.enabled }} {{- if $ingressValue.enabled }}
--- ---
apiVersion: extensions/v1beta1 apiVersion: {{ include "owsec.ingress.apiVersion" $root }}
kind: Ingress kind: Ingress
metadata: metadata:
name: {{ include "owsec.fullname" $root }}-{{ $ingress }} name: {{ include "owsec.fullname" $root }}-{{ $ingress }}
@@ -36,11 +36,25 @@ spec:
paths: paths:
{{- range $ingressValue.paths }} {{- range $ingressValue.paths }}
- path: {{ .path }} - path: {{ .path }}
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
pathType: {{ .pathType | default "ImplementationSpecific" }}
{{- end }}
backend: backend:
{{- if $root.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
service:
name: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
port:
{{- if kindIs "string" .servicePort }}
name: {{ .servicePort }}
{{- else }}
number: {{ .servicePort }}
{{- end }}
{{- else }}
serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }} serviceName: {{ include "owsec.fullname" $root }}-{{ .serviceName }}
servicePort: {{ .servicePort }} servicePort: {{ .servicePort }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- end }}
{{- end }} {{- end }}

View File

@@ -8,7 +8,7 @@ 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.4.0
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # registry: tip-tip-wlan-cloud-ucentral.jfrog.io
@@ -50,6 +50,7 @@ ingresses:
- restapi.chart-example.local - restapi.chart-example.local
paths: paths:
- path: / - path: /
pathType: ImplementationSpecific
serviceName: owsec serviceName: owsec
servicePort: restapi servicePort: restapi

View File

@@ -61,6 +61,8 @@ components:
- 6 # INTERNAL_ERROR, - 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED, - 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN - 8 # INVALID_TOKEN
- 9 # expired token
- 10 # rate limit exceeded
ErrorDetails: ErrorDetails:
type: string type: string
ErrorDescription: ErrorDescription:

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 = ************************

45
src/ACLProcessor.h Normal file
View File

@@ -0,0 +1,45 @@
//
// 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
};
static inline bool Can( const SecurityObjects::UserInfo & User, const SecurityObjects::UserInfo & Target, ACL_OPS Op) {
if(User.Id == Target.Id && Op==DELETE)
return false;
if(User.userRole==SecurityObjects::ROOT)
return true;
if(User.Id == Target.Id)
return true;
if(User.userRole!=SecurityObjects::ADMIN && User.userRole!=SecurityObjects::ROOT && Op!=READ)
return false;
if(Target.userRole==SecurityObjects::ROOT && Op!=READ)
return false;
return true;
}
private:
};
}
#endif //OWSEC_ACLPROCESSOR_H

View File

@@ -18,8 +18,8 @@ namespace OpenWifi {
}; };
static ActionLinkManager * instance() { static ActionLinkManager * instance() {
static ActionLinkManager instance; static auto * instance_ = new ActionLinkManager;
return &instance; return instance_;
} }
int Start() final; int Start() final;

View File

@@ -56,9 +56,10 @@ namespace OpenWifi {
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 )
{ {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
Expired = false;
try { try {
std::string CallToken; std::string CallToken;
Poco::Net::OAuth20Credentials Auth(Request); Poco::Net::OAuth20Credentials Auth(Request);
@@ -67,27 +68,29 @@ namespace OpenWifi {
} }
if(!CallToken.empty()) { if(!CallToken.empty()) {
if(StorageService()->IsTokenRevoked(CallToken)) auto Client = UserCache_.get(CallToken);
if( Client.isNull() ) {
SecurityObjects::UserInfoAndPolicy UInfo2;
uint64_t RevocationDate=0;
if(StorageService()->GetToken(CallToken,UInfo2,RevocationDate)) {
if(RevocationDate!=0)
return false; return false;
auto Client = UserCache_.find(CallToken); Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr);
if( Client == UserCache_.end() ) { if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) {
if(StorageService()->GetToken(SessionToken,UInfo)) { UInfo.webtoken = UInfo2.webtoken;
if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) { UserCache_.update(CallToken, UInfo);
UserCache_[UInfo.webtoken.access_token_] = UInfo;
return true;
}
}
return false;
}
if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) {
SessionToken = CallToken; SessionToken = CallToken;
UInfo = Client->second ;
return true; return true;
} }
}
UserCache_.erase(Client); return false;
StorageService()->RevokeToken(CallToken); }
if(!Expired) {
SessionToken = CallToken;
UInfo = *Client ;
return true;
}
RevokeToken(CallToken);
return false; return false;
} }
} catch(const Poco::Exception &E) { } catch(const Poco::Exception &E) {
@@ -96,16 +99,24 @@ namespace OpenWifi {
return false; return false;
} }
void AuthService::RevokeToken(std::string & Token) {
UserCache_.remove(Token);
StorageService()->RevokeToken(Token);
}
bool AuthService::DeleteUserFromCache(const std::string &UserName) { bool AuthService::DeleteUserFromCache(const std::string &UserName) {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
for(auto i=UserCache_.begin();i!=UserCache_.end();) { std::vector<std::string> OldTokens;
if (i->second.userinfo.email==UserName) {
Logout(i->first, false); UserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void
i = UserCache_.erase(i); { if(O.userinfo.email==UserName)
} else { OldTokens.push_back(token);
++i; });
}
for(const auto &i:OldTokens) {
Logout(i,false);
UserCache_.remove(i);
} }
return true; return true;
} }
@@ -121,9 +132,6 @@ namespace OpenWifi {
void AuthService::Logout(const std::string &token, bool EraseFromCache) { void AuthService::Logout(const std::string &token, bool EraseFromCache) {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
if(EraseFromCache)
UserCache_.erase(token);
try { try {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
Obj.set("event", "remove-token"); Obj.set("event", "remove-token");
@@ -132,7 +140,7 @@ namespace OpenWifi {
std::stringstream ResultText; std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText); Poco::JSON::Stringifier::stringify(Obj, ResultText);
std::string Tmp{token}; std::string Tmp{token};
StorageService()->RevokeToken(Tmp); RevokeToken(Tmp);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(), KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(),
false); false);
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
@@ -183,9 +191,9 @@ namespace OpenWifi {
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; UserCache_.update(UInfo.webtoken.access_token_,UInfo);
StorageService()->SetLastLogin(UInfo.userinfo.Id); StorageService()->SetLastLogin(UInfo.userinfo.Id);
StorageService()->AddToken(UInfo.webtoken.username_, UInfo.webtoken.access_token_, StorageService()->AddToken(UInfo.userinfo.Id, 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_);
} }
@@ -253,7 +261,7 @@ namespace OpenWifi {
return false; return false;
} }
UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ) 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_);
@@ -291,6 +299,7 @@ namespace OpenWifi {
UInfo.userinfo.lastLogin=std::time(nullptr); UInfo.userinfo.lastLogin=std::time(nullptr);
StorageService()->SetLastLogin(UInfo.userinfo.Id); StorageService()->SetLastLogin(UInfo.userinfo.Id);
CreateToken(UserName, UInfo ); CreateToken(UserName, UInfo );
return SUCCESS; return SUCCESS;
} }
@@ -337,7 +346,7 @@ namespace OpenWifi {
A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
A.userId = UInfo.email; A.userId = UInfo.email;
A.id = MicroService::instance().CreateUUID(); A.id = MicroService::CreateUUID();
A.created = std::time(nullptr); A.created = std::time(nullptr);
A.expires = A.created + 24*60*60; A.expires = A.created + 24*60*60;
StorageService()->CreateAction(A); StorageService()->CreateAction(A);
@@ -345,16 +354,39 @@ namespace OpenWifi {
return true; return true;
} }
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo) { bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
auto It = UserCache_.find(Token);
if(It==UserCache_.end()) Expired = false;
return false;
WebToken = It->second.webtoken; auto Client = UserCache_.get(Token);
UserInfo = It->second.userinfo; if(!Client.isNull()) {
Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr);
WebToken = Client->webtoken;
UserInfo = Client->userinfo;
return true; return true;
} }
std::string TToken{Token};
if(StorageService()->IsTokenRevoked(TToken)) {
return false;
}
// get the token from disk...
SecurityObjects::UserInfoAndPolicy UInfo;
uint64_t RevocationDate=0;
if(StorageService()->GetToken(TToken, UInfo, RevocationDate)) {
if(RevocationDate!=0)
return false;
Expired = (UInfo.webtoken.created_ + UInfo.webtoken.expires_in_) < std::time(nullptr);
if(StorageService()->GetUserById(UInfo.userinfo.Id,UInfo.userinfo)) {
WebToken = UInfo.webtoken;
UserCache_.update(UInfo.webtoken.access_token_, UInfo);
return true;
}
}
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"
@@ -44,15 +45,15 @@ namespace OpenWifi{
static int AccessTypeToInt(ACCESS_TYPE T); static int AccessTypeToInt(ACCESS_TYPE T);
static AuthService *instance() { static AuthService *instance() {
static AuthService instance; static auto * 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]] UNAUTHORIZED_REASON 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 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_;};
@@ -60,8 +61,7 @@ namespace OpenWifi{
bool ValidatePassword(const std::string &pwd); bool ValidatePassword(const std::string &pwd);
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo); [[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
[[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);
@@ -75,19 +75,21 @@ namespace OpenWifi{
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason); [[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
[[nodiscard]] bool DeleteUserFromCache(const std::string &UserName); [[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo); [[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
void RevokeToken(std::string & Token);
[[nodiscard]] static inline const std::string GetLogoAssetURI() { [[nodiscard]] static inline const std::string GetLogoAssetURI() {
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
} }
[[nodiscard]] static inline const std::string GetLogoAssetFileName() { [[nodiscard]] static inline const std::string GetLogoAssetFileName() {
return MicroService::instance().DataDir() + "/wwwassets/the_logo.png"; return MicroService::instance().WWWAssetsDir() + "/the_logo.png";
} }
private: private:
Poco::JWT::Signer Signer_; Poco::JWT::Signer Signer_;
Poco::SHA2Engine SHA2_; Poco::SHA2Engine SHA2_;
SecurityObjects::UserInfoCache UserCache_; Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy> UserCache_{2048,1200000};
// SecurityObjects::UserInfoCache UserCache_;
std::string PasswordValidationStr_; std::string PasswordValidationStr_;
std::regex PasswordValidation_; std::regex PasswordValidation_;
uint64_t TokenAging_ = 30 * 24 * 60 * 60; uint64_t TokenAging_ = 30 * 24 * 60 * 60;
@@ -119,8 +121,8 @@ namespace OpenWifi{
inline AuthService * AuthService() { return AuthService::instance(); } inline AuthService * 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) {
return AuthService()->IsAuthorized(Request, SessionToken, UInfo ); return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
} }
} // end of namespace } // end of namespace

View File

@@ -26,7 +26,7 @@ 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);
@@ -71,8 +71,9 @@ 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) { if(Hint->second.Answer!=answer) {

View File

@@ -24,8 +24,8 @@ namespace OpenWifi {
int Start() override; int Start() override;
void Stop() override; void Stop() override;
static MFAServer *instance() { static MFAServer *instance() {
static MFAServer instance; static auto * 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);
@@ -35,7 +35,7 @@ namespace OpenWifi {
static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge);
static inline std::string MakeChallenge() { static inline std::string MakeChallenge() {
return std::to_string(rand() % 999999); return std::to_string(MicroService::instance().Random(1,999999));
} }
private: private:

View File

@@ -20,7 +20,7 @@ namespace OpenWifi {
Server, Server,
Internal, Internal,
false, false,
true, RateLimit{.Interval=1000,.MaxCalls=5}) {} 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(SecurityObjects::ActionLink &Link); void RequestResetPassword(SecurityObjects::ActionLink &Link);
void CompleteResetPassword(); void CompleteResetPassword();

View File

@@ -17,23 +17,38 @@
#include "StorageService.h" #include "StorageService.h"
namespace OpenWifi { namespace OpenWifi {
static void FilterCredentials(SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
void RESTAPI_oauth2Handler::DoGet() { void RESTAPI_oauth2Handler::DoGet() {
if (!IsAuthorized()) { bool Expired = false;
if (!IsAuthorized(Expired)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation); return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
} }
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false); bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
if(GetMe) { if(GetMe) {
Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email)); Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
Poco::JSON::Object Me; Poco::JSON::Object Me;
UserInfo_.userinfo.to_json(Me); SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
FilterCredentials(ReturnedUser);
ReturnedUser.to_json(Me);
return ReturnObject(Me); return ReturnObject(Me);
} }
BadRequest(RESTAPI::Errors::UnrecognizedRequest); BadRequest(RESTAPI::Errors::UnrecognizedRequest);
} }
void RESTAPI_oauth2Handler::DoDelete() { void RESTAPI_oauth2Handler::DoDelete() {
if (!IsAuthorized()) { bool Expired = false;
return UnAuthorized("Not authorized."); if (!IsAuthorized(Expired)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
} }
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "..."); auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
@@ -71,7 +86,7 @@ namespace OpenWifi {
SecurityObjects::ActionLink NewLink; SecurityObjects::ActionLink NewLink;
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
NewLink.id = MicroService::instance().CreateUUID(); NewLink.id = MicroService::CreateUUID();
NewLink.userId = UInfo1.Id; NewLink.userId = UInfo1.Id;
NewLink.created = std::time(nullptr); NewLink.created = std::time(nullptr);
NewLink.expires = NewLink.created + (24*60*60); NewLink.expires = NewLink.created + (24*60*60);
@@ -93,8 +108,8 @@ namespace OpenWifi {
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) {
Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId)); Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId));
if(Obj->has(RESTAPI::Protocol::UUID)) { if(Obj->has("uuid")) {
auto uuid = Obj->get(RESTAPI::Protocol::UUID).toString(); auto uuid = Obj->get("uuid").toString();
if(MFAServer().ResendCode(uuid)) if(MFAServer().ResendCode(uuid))
return OK(); return OK();
} }
@@ -103,7 +118,7 @@ namespace OpenWifi {
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId)); Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
if(Obj->has(RESTAPI::Protocol::UUID)) { if(Obj->has("uuid")) {
SecurityObjects::UserInfoAndPolicy UInfo; SecurityObjects::UserInfoAndPolicy UInfo;
if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) { if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
Poco::JSON::Object ReturnObj; Poco::JSON::Object ReturnObj;
@@ -115,7 +130,8 @@ namespace OpenWifi {
} }
SecurityObjects::UserInfoAndPolicy UInfo; SecurityObjects::UserInfoAndPolicy UInfo;
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo); bool Expired=false;
auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired);
if (Code==SUCCESS) { if (Code==SUCCESS) {
Poco::JSON::Object ReturnObj; Poco::JSON::Object ReturnObj;
if(AuthService()->RequiresMFA(UInfo)) { if(AuthService()->RequiresMFA(UInfo)) {

View File

@@ -21,7 +21,7 @@ namespace OpenWifi {
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS}, Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, Server,
Internal, false, true , RateLimit{.Interval=2000,.MaxCalls=5}) {} 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;

View File

@@ -7,8 +7,16 @@
#include "Poco/JSON/Parser.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"
namespace OpenWifi { namespace OpenWifi {
static void FilterCredentials(SecurityObjects::UserInfo & U) {
U.currentPassword.clear();
U.lastPasswords.clear();
U.oauthType.clear();
}
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()) {
@@ -27,9 +35,7 @@ namespace OpenWifi {
} }
Poco::JSON::Object UserInfoObject; Poco::JSON::Object UserInfoObject;
UInfo.currentPassword.clear(); FilterCredentials(UInfo);
UInfo.lastPasswords.clear();
UInfo.oauthType.clear();
UInfo.to_json(UserInfoObject); UInfo.to_json(UserInfoObject);
ReturnObject(UserInfoObject); ReturnObject(UserInfoObject);
} }
@@ -40,20 +46,12 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::MissingUserID); return BadRequest(RESTAPI::Errors::MissingUserID);
} }
if(UserInfo_.userinfo.userRole!= SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
if(UserInfo_.userinfo.Id == Id) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
}
SecurityObjects::UserInfo UInfo; SecurityObjects::UserInfo UInfo;
if(!StorageService()->GetUserById(Id,UInfo)) { if(!StorageService()->GetUserById(Id,UInfo)) {
return NotFound(); return NotFound();
} }
if(UInfo.userRole==SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) { if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
} }
@@ -64,6 +62,9 @@ namespace OpenWifi {
if(AuthService()->DeleteUserFromCache(UInfo.email)) { if(AuthService()->DeleteUserFromCache(UInfo.email)) {
// nothing to do // nothing to do
} }
StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id);
Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
StorageService()->RevokeAllTokens(UInfo.email); StorageService()->RevokeAllTokens(UInfo.email);
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));
@@ -76,57 +77,52 @@ 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(UInfo.userRole == SecurityObjects::UNKNOWN) { if(NewUser.userRole == SecurityObjects::UNKNOWN) {
return BadRequest(RESTAPI::Errors::InvalidUserRole); return BadRequest(RESTAPI::Errors::InvalidUserRole);
} }
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
} }
if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && UInfo.userRole == SecurityObjects::ROOT) { Poco::toLowerInPlace(NewUser.email);
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); if(!Utils::ValidEMailAddress(NewUser.email)) {
}
Poco::toLowerInPlace(UInfo.email);
if(!Utils::ValidEMailAddress(UInfo.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)) { if(!StorageService()->CreateUser(NewUser.email,NewUser)) {
Logger_.information(Poco::format("Could not add user '%s'.",UInfo.email)); 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()->UpdateUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser);
} }
if(!StorageService()->GetUserByEmail(UInfo.email, UInfo)) { if(!StorageService()->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); FilterCredentials(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() {
@@ -140,12 +136,8 @@ namespace OpenWifi {
return NotFound(); return NotFound();
} }
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && UserInfo_.userinfo.userRole!=SecurityObjects::ADMIN) { if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
}
if(UserInfo_.userinfo.userRole == SecurityObjects::ADMIN && Existing.userRole == SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
} }
SecurityObjects::UserInfo NewUser; SecurityObjects::UserInfo NewUser;
@@ -224,15 +216,23 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::NeedMobileNumber); return BadRequest(RESTAPI::Errors::NeedMobileNumber);
} }
if(NewUser.userTypeProprietaryInfo.mfa.method=="email") { if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) {
if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) {
return BadRequest("Unknown MFA method");
}
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method; Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
} }
if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
return BadRequest("Illegal MFA method");
}
} }
if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) { if(StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
SecurityObjects::UserInfo NewUserInfo; SecurityObjects::UserInfo NewUserInfo;
StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo); StorageService()->GetUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
Poco::JSON::Object ModifiedObject; Poco::JSON::Object ModifiedObject;
FilterCredentials(NewUserInfo);
NewUserInfo.to_json(ModifiedObject); NewUserInfo.to_json(ModifiedObject);
return ReturnObject(ModifiedObject); return ReturnObject(ModifiedObject);
} }

View File

@@ -13,7 +13,8 @@ namespace OpenWifi {
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

@@ -562,7 +562,7 @@ namespace OpenWifi::ProvObjects {
} }
I.notes = N; I.notes = N;
I.modified = I.created = Now; I.modified = I.created = Now;
I.id = MicroService::instance().CreateUUID(); I.id = MicroService::CreateUUID();
return true; return true;
} }

View File

@@ -59,15 +59,15 @@ namespace OpenWifi::SecurityObjects {
struct MobilePhoneNumber { struct MobilePhoneNumber {
std::string number; std::string number;
bool verified; bool verified = false;
bool primary; bool primary = false;
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 MfaAuthInfo { struct MfaAuthInfo {
bool enabled; bool enabled = false;
std::string method; std::string method;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
@@ -86,7 +86,7 @@ namespace OpenWifi::SecurityObjects {
std::string uuid; std::string uuid;
std::string question; std::string question;
std::string method; std::string method;
uint64_t created; uint64_t created = std::time(nullptr);
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);

View File

@@ -16,13 +16,16 @@
namespace OpenWifi { namespace OpenWifi {
int SMSSender::Start() { int SMSSender::Start() {
Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws"); Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false);
if(Enabled_) {
Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws");
if(Provider_=="aws") { if(Provider_=="aws") {
ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_);
} else if(Provider_=="twilio") { } else if(Provider_=="twilio") {
ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_);
} }
Enabled_ = ProviderImpl_->Initialize(); Enabled_ = ProviderImpl_->Initialize();
}
return 0; return 0;
} }

View File

@@ -18,15 +18,15 @@ 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() {
static SMSSender instance; static auto *instance_ = new SMSSender;
return &instance; return instance_;
} }
int Start() final; int Start() final;

View File

@@ -43,6 +43,7 @@ namespace OpenWifi {
if(!Running_) if(!Running_)
return false; return false;
try {
Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_); Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_);
Aws::SNS::Model::PublishRequest psms_req; Aws::SNS::Model::PublishRequest psms_req;
psms_req.SetMessage(Message.c_str()); psms_req.SetMessage(Message.c_str());
@@ -56,6 +57,11 @@ namespace OpenWifi {
std::string ErrMsg{psms_out.GetError().GetMessage()}; std::string ErrMsg{psms_out.GetError().GetMessage()};
Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg));
return false; return false;
} catch (...) {
}
Logger_.debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber));
return false;
} }
} }

View File

@@ -9,12 +9,9 @@
#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"
@@ -23,6 +20,8 @@
namespace OpenWifi { namespace OpenWifi {
void SMTPMailerService::LoadMyConfig() { void SMTPMailerService::LoadMyConfig() {
Enabled_ = MicroService::instance().ConfigGetBool("mailer.enabled",false);
if(Enabled_) {
MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname"); MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname");
SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username"); SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username");
SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password");
@@ -30,8 +29,11 @@ namespace OpenWifi {
LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod");
MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port");
TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); 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()); Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty());
} }
}
int SMTPMailerService::Start() { int SMTPMailerService::Start() {
LoadMyConfig(); LoadMyConfig();
@@ -53,57 +55,46 @@ namespace OpenWifi {
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)));});
} }
} }
} }
@@ -115,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,7 +122,6 @@ namespace OpenWifi {
} }
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);
@@ -146,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()) {
try {
Poco::File LogoFile(AuthService::GetLogoAssetFileName()); Poco::File LogoFile(AuthService::GetLogoAssetFileName());
std::ifstream IF(LogoFile.path()); std::ifstream IF(LogoFile.path());
std::ostringstream OS; std::ostringstream OS;
Poco::StreamCopier::copyStream(IF, OS); Poco::StreamCopier::copyStream(IF, OS);
Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/jpeg")); 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);
@@ -177,6 +174,9 @@ namespace OpenWifi {
{ {
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,8 +59,8 @@ namespace OpenWifi {
class SMTPMailerService : public SubSystemServer, Poco::Runnable { class SMTPMailerService : public SubSystemServer, Poco::Runnable {
public: public:
static SMTPMailerService *instance() { static SMTPMailerService *instance() {
static SMTPMailerService instance; static auto * instance_ = new SMTPMailerService;
return & instance; return instance_;
} }
struct MessageEvent { struct MessageEvent {
@@ -71,41 +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:
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"};
} }
}; };

View File

@@ -16,12 +16,28 @@ namespace OpenWifi {
StorageClass::Start(); StorageClass::Start();
Create_Tables(); Create_Tables();
InitializeDefaultUser(); 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 Storage::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()->CleanExpiredTokens();
logger.information("Squiggy the DB: removing old actionLinks.");
StorageService()->CleanOldActionLinks();
}
} }
// namespace // namespace

View File

@@ -13,6 +13,8 @@
#include "framework/StorageClass.h" #include "framework/StorageClass.h"
#include "AuthService.h" #include "AuthService.h"
#include "Poco/Timer.h"
namespace OpenWifi { namespace OpenWifi {
static const std::string AllEmailTemplatesFieldsForCreation { static const std::string AllEmailTemplatesFieldsForCreation {
@@ -27,6 +29,12 @@ namespace OpenWifi {
}; };
class Archiver {
public:
void onTimer(Poco::Timer & timer);
private:
};
class Storage : public StorageClass { class Storage : public StorageClass {
public: public:
@@ -76,8 +84,8 @@ namespace OpenWifi {
} }
static Storage *instance() { static Storage *instance() {
static Storage instance; static auto * instance_ = new Storage;
return &instance; return instance_;
} }
int Start() override; int Start() override;
@@ -104,12 +112,12 @@ namespace OpenWifi {
bool GetAvatar(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 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 AddToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut);
bool RevokeToken( std::string & Token ); bool RevokeToken( std::string & Token );
bool IsTokenRevoked( std::string & Token ); bool IsTokenRevoked( std::string & Token );
bool CleanRevokedTokens( uint64_t Oldest ); bool CleanExpiredTokens();
bool RevokeAllTokens( std::string & UserName ); bool RevokeAllTokens( std::string & UserName );
bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo); bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate);
/* /*
* All ActionLinks functions * All ActionLinks functions
@@ -121,6 +129,7 @@ namespace OpenWifi {
bool SentAction(std::string &ActionId); bool SentAction(std::string &ActionId);
bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A); bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A);
bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200); bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200);
void CleanOldActionLinks();
private: private:
int Create_Tables(); int Create_Tables();
@@ -128,6 +137,13 @@ namespace OpenWifi {
int Create_AvatarTable(); int Create_AvatarTable();
int Create_TokensTable(); int Create_TokensTable();
int Create_ActionLinkTable(); int Create_ActionLinkTable();
Poco::Timer Timer_;
Archiver Archiver_;
std::unique_ptr<Poco::TimerCallback<Archiver>> Archivercallback_;
/// This is to support a mistake that was deployed...
void ReplaceOldDefaultUUID();
}; };
inline Storage * StorageService() { return Storage::instance(); }; inline Storage * StorageService() { return Storage::instance(); };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
//
// Created by stephane bourque on 2021-09-14.
//
#ifndef OWPROV_CONFIGURATIONVALIDATOR_H
#define OWPROV_CONFIGURATIONVALIDATOR_H
#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); }
}
#endif //OWPROV_CONFIGURATIONVALIDATOR_H

View File

@@ -69,6 +69,8 @@ using namespace std::chrono_literals;
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "ow_version.h"
namespace OpenWifi { namespace OpenWifi {
enum UNAUTHORIZED_REASON { enum UNAUTHORIZED_REASON {
@@ -80,7 +82,9 @@ namespace OpenWifi {
PASSWORD_INVALID, PASSWORD_INVALID,
INTERNAL_ERROR, INTERNAL_ERROR,
ACCESS_DENIED, ACCESS_DENIED,
INVALID_TOKEN INVALID_TOKEN,
EXPIRED_TOKEN,
RATE_LIMIT_EXCEEDED
}; };
class AppServiceRegistry { class AppServiceRegistry {
@@ -88,8 +92,8 @@ namespace OpenWifi {
inline AppServiceRegistry(); inline AppServiceRegistry();
static AppServiceRegistry & instance() { static AppServiceRegistry & instance() {
static AppServiceRegistry instance; static AppServiceRegistry *instance_= new AppServiceRegistry;
return instance; return *instance_;
} }
inline ~AppServiceRegistry() { inline ~AppServiceRegistry() {
@@ -1433,8 +1437,8 @@ namespace OpenWifi {
}; };
static RESTAPI_RateLimiter *instance() { static RESTAPI_RateLimiter *instance() {
static RESTAPI_RateLimiter instance; static RESTAPI_RateLimiter * instance_ = new RESTAPI_RateLimiter;
return &instance; return instance_;
} }
inline int Start() final { return 0;}; inline int Start() final { return 0;};
@@ -1444,18 +1448,18 @@ namespace OpenWifi {
Poco::URI uri(R.getURI()); Poco::URI uri(R.getURI());
auto H = str_hash(uri.getPath() + R.clientAddress().host().toString()); auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
auto E = Cache_.get(H); auto E = Cache_.get(H);
const auto p1 = std::chrono::system_clock::now(); auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(p1.time_since_epoch()).count();
if(E.isNull()) { if(E.isNull()) {
Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1}); Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString()));
return false; return false;
} }
if((Now-E->Start)<Period) { if((Now-E->Start)<Period) {
E->Count++; E->Count++;
Cache_.update(H,E); Cache_.update(H,E);
if(E->Count > MaxCalls) if(E->Count > MaxCalls) {
Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString()));
return true; return true;
}
return false; return false;
} }
E->Start = Now; E->Start = Now;
@@ -1523,20 +1527,23 @@ namespace OpenWifi {
Request = &RequestIn; Request = &RequestIn;
Response = &ResponseIn; Response = &ResponseIn;
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) {
return; return UnAuthorized("Rate limit exceeded.",RATE_LIMIT_EXCEEDED);
}
if (!ContinueProcessing()) if (!ContinueProcessing())
return; return;
if (AlwaysAuthorize_ && !IsAuthorized()) { bool Expired=false;
return; if (AlwaysAuthorize_ && !IsAuthorized(Expired)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::ExpiredToken, EXPIRED_TOKEN);
return UnAuthorized(RESTAPI::Errors::InvalidCredentials, ACCESS_DENIED);
} }
std::string Reason; std::string Reason;
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) { if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
UnAuthorized(Reason, ACCESS_DENIED); return UnAuthorized(Reason, ACCESS_DENIED);
return;
} }
ParseParameters(); ParseParameters();
@@ -1874,7 +1881,7 @@ namespace OpenWifi {
return true; return true;
} }
inline bool IsAuthorized(); inline bool IsAuthorized(bool & Expired);
inline void ReturnObject(Poco::JSON::Object &Object) { inline void ReturnObject(Poco::JSON::Object &Object) {
PrepareResponse(); PrepareResponse();
@@ -1895,7 +1902,7 @@ namespace OpenWifi {
QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, ""); QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0); QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0);
QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0); QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0);
QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 1); QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0);
QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100); QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100);
QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, ""); QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, "");
QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, ""); QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, "");
@@ -1907,7 +1914,7 @@ namespace OpenWifi {
QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false); QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false);
if(QB_.Offset<1) if(QB_.Offset<1)
QB_.Offset=1; QB_.Offset=0;
return true; return true;
} }
@@ -2076,6 +2083,50 @@ namespace OpenWifi {
Poco::JSON::Object Body_; Poco::JSON::Object Body_;
}; };
class KafkaProducer : public Poco::Runnable {
public:
inline void run();
void Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void Stop() {
if(Running_) {
Running_=false;
Worker_.wakeUp();
Worker_.join();
}
}
private:
std::mutex Mutex_;
Poco::Thread Worker_;
std::atomic_bool Running_=false;
};
class KafkaConsumer : public Poco::Runnable {
public:
inline void run();
void Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void Stop() {
if(Running_) {
Running_=false;
Worker_.wakeUp();
Worker_.join();
}
}
private:
std::mutex Mutex_;
Poco::Thread Worker_;
std::atomic_bool Running_=false;
};
class KafkaManager : public SubSystemServer { class KafkaManager : public SubSystemServer {
public: public:
struct KMessage { struct KMessage {
@@ -2084,33 +2135,32 @@ namespace OpenWifi {
PayLoad; PayLoad;
}; };
friend class KafkaConsumer;
friend class KafkaProducer;
inline void initialize(Poco::Util::Application & self) override; inline void initialize(Poco::Util::Application & self) override;
static KafkaManager *instance() { static KafkaManager *instance() {
static KafkaManager instance; static KafkaManager * instance_ = new KafkaManager;
return &instance; return instance_;
} }
inline int Start() override { inline int Start() override {
if(!KafkaEnabled_) if(!KafkaEnabled_)
return 0; return 0;
ProducerThr_ = std::make_unique<std::thread>([this]() { this->ProducerThr(); }); ConsumerThr_.Start();
ConsumerThr_ = std::make_unique<std::thread>([this]() { this->ConsumerThr(); }); ProducerThr_.Start();
return 0; return 0;
} }
inline void Stop() override { inline void Stop() override {
if(KafkaEnabled_) { if(KafkaEnabled_) {
ProducerRunning_ = ConsumerRunning_ = false; ProducerThr_.Stop();
ProducerThr_->join(); ConsumerThr_.Stop();
ConsumerThr_->join();
return; return;
} }
} }
inline void ProducerThr();
inline void ConsumerThr();
inline void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true ) { inline void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true ) {
if(KafkaEnabled_) { if(KafkaEnabled_) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
@@ -2163,18 +2213,13 @@ namespace OpenWifi {
// void WakeUp(); // void WakeUp();
private: private:
std::mutex ProducerMutex_;
std::mutex ConsumerMutex_;
bool KafkaEnabled_ = false; bool KafkaEnabled_ = false;
std::atomic_bool ProducerRunning_ = false;
std::atomic_bool ConsumerRunning_ = false;
std::queue<KMessage> Queue_; std::queue<KMessage> Queue_;
std::string SystemInfoWrapper_; std::string SystemInfoWrapper_;
std::unique_ptr<std::thread> ConsumerThr_;
std::unique_ptr<std::thread> ProducerThr_;
int FunctionId_=1; int FunctionId_=1;
Types::NotifyTable Notifiers_; Types::NotifyTable Notifiers_;
std::unique_ptr<cppkafka::Configuration> Config_; KafkaProducer ProducerThr_;
KafkaConsumer ConsumerThr_;
inline void PartitionAssignment(const cppkafka::TopicPartitionList& partitions) { inline void PartitionAssignment(const cppkafka::TopicPartitionList& partitions) {
Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition())); Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition()));
@@ -2199,8 +2244,8 @@ namespace OpenWifi {
} }
static AuthClient *instance() { static AuthClient *instance() {
static AuthClient instance; static AuthClient * instance_ = new AuthClient;
return &instance; return instance_;
} }
inline int Start() override { inline int Start() override {
@@ -2208,25 +2253,20 @@ namespace OpenWifi {
} }
inline void Stop() override { inline void Stop() override {
Cache_.clear();
} }
inline void RemovedCachedToken(const std::string &Token) { inline void RemovedCachedToken(const std::string &Token) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
UserCache_.erase(Token); Cache_.remove(Token);
} }
inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) { inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) {
return ((T.expires_in_+T.created_)<std::time(nullptr)); return ((T.expires_in_+T.created_)<std::time(nullptr));
} }
inline bool IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) { inline bool RetrieveTokenInformation(const std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) {
std::lock_guard G(Mutex_); try {
auto User = UserCache_.find(SessionToken);
if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) {
UInfo = User->second;
return true;
} else {
Types::StringPairVec QueryData; Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("token",SessionToken)); QueryData.push_back(std::make_pair("token",SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY, OpenAPIRequestGet Req( uSERVICE_SECURITY,
@@ -2236,49 +2276,39 @@ namespace OpenWifi {
Poco::JSON::Object::Ptr Response; Poco::JSON::Object::Ptr Response;
if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) { if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo")) { if(Response->has("tokenInfo") && Response->has("userInfo")) {
SecurityObjects::UserInfoAndPolicy P; UInfo.from_json(Response);
P.from_json(Response); if(IsTokenExpired(UInfo.webtoken)) {
UserCache_[SessionToken] = P; Expired = true;
UInfo = P; return false;
} }
Expired = false;
Cache_.update(SessionToken, UInfo);
return true; return true;
} }
}
} catch (...) {
} }
Expired = false;
return false; return false;
} }
inline bool IsTokenAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo) { inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) {
std::lock_guard G(Mutex_); auto User = Cache_.get(SessionToken);
if(!User.isNull()) {
auto User = UserCache_.find(SessionToken); if(IsTokenExpired(User->webtoken)) {
if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) { Expired = true;
UInfo = User->second;
return true;
} else {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("token",SessionToken));
OpenAPIRequestGet Req(uSERVICE_SECURITY,
"/api/v1/validateToken",
QueryData,
5000);
Poco::JSON::Object::Ptr Response;
if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo")) {
SecurityObjects::UserInfoAndPolicy P;
P.from_json(Response);
UserCache_[SessionToken] = P;
UInfo = P;
}
return true;
}
}
return false; return false;
} }
Expired = false;
UInfo = *User;
return true;
}
return RetrieveTokenInformation(SessionToken, UInfo, Expired);
}
private: private:
OpenWifi::SecurityObjects::UserInfoCache UserCache_; Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{1024,1200000 };
}; };
inline AuthClient * AuthClient() { return AuthClient::instance(); } inline AuthClient * AuthClient() { return AuthClient::instance(); }
@@ -2338,14 +2368,14 @@ namespace OpenWifi {
} }
static ALBHealthCheckServer *instance() { static ALBHealthCheckServer *instance() {
static ALBHealthCheckServer instance; static ALBHealthCheckServer * instance = new ALBHealthCheckServer;
return &instance; return instance;
} }
inline int Start() override; inline int Start() override;
inline void Stop() override { inline void Stop() override {
if(Server_) if(Running_)
Server_->stop(); Server_->stop();
} }
@@ -2353,6 +2383,7 @@ namespace OpenWifi {
std::unique_ptr<Poco::Net::HTTPServer> Server_; std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_; std::unique_ptr<Poco::Net::ServerSocket> Socket_;
int Port_ = 0; int Port_ = 0;
std::atomic_bool Running_=false;
}; };
inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
@@ -2364,23 +2395,24 @@ namespace OpenWifi {
Poco::Logger & L, RESTAPI_GenericServer & S); Poco::Logger & L, RESTAPI_GenericServer & S);
class RESTAPI_server : public SubSystemServer { class RESTAPI_ExtServer : public SubSystemServer {
public: public:
static RESTAPI_server *instance() { static RESTAPI_ExtServer *instance() {
static RESTAPI_server instance; static RESTAPI_ExtServer *instance_ = new RESTAPI_ExtServer;
return &instance; return instance_;
} }
int Start() override; int Start() override;
inline void Stop() override { inline void Stop() override {
Logger_.information("Stopping "); Logger_.information("Stopping ");
for( const auto & svr : RESTServers_ ) for( const auto & svr : RESTServers_ )
svr->stop(); svr->stop();
Pool_.joinAll();
RESTServers_.clear(); RESTServers_.clear();
} }
inline void reinitialize(Poco::Util::Application &self) override; inline void reinitialize(Poco::Util::Application &self) override;
inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) { inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings; RESTAPIHandler::BindingMap Bindings;
return RESTAPI_external_server(Path, Bindings, Logger_, Server_); return RESTAPI_external_server(Path, Bindings, Logger_, Server_);
} }
@@ -2390,18 +2422,18 @@ namespace OpenWifi {
Poco::ThreadPool Pool_; Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_; RESTAPI_GenericServer Server_;
RESTAPI_server() noexcept: RESTAPI_ExtServer() noexcept:
SubSystemServer("RESTAPIServer", "RESTAPIServer", "openwifi.restapi") SubSystemServer("RESTAPIServer", "RESTAPIServer", "openwifi.restapi")
{ {
} }
}; };
inline RESTAPI_server * RESTAPI_server() { return RESTAPI_server::instance(); }; inline RESTAPI_ExtServer * RESTAPI_ExtServer() { return RESTAPI_ExtServer::instance(); };
class RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { class ExtRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public: public:
RequestHandlerFactory(RESTAPI_GenericServer & Server) : explicit ExtRequestHandlerFactory(RESTAPI_GenericServer & Server) :
Logger_(RESTAPI_server::instance()->Logger()), Logger_(RESTAPI_ExtServer::instance()->Logger()),
Server_(Server) Server_(Server)
{ {
@@ -2410,15 +2442,16 @@ namespace OpenWifi {
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
Poco::URI uri(Request.getURI()); Poco::URI uri(Request.getURI());
auto *Path = uri.getPath().c_str(); auto *Path = uri.getPath().c_str();
return RESTAPI_server()->CallServer(Path); return RESTAPI_ExtServer()->CallServer(Path, TransactionId_++);
} }
private: private:
static inline std::atomic_uint64_t TransactionId_ = 1;
Poco::Logger &Logger_; Poco::Logger &Logger_;
RESTAPI_GenericServer &Server_; RESTAPI_GenericServer &Server_;
}; };
inline int RESTAPI_server::Start() { inline int RESTAPI_ExtServer::Start() {
Logger_.information("Starting."); Logger_.information("Starting.");
Server_.InitLogging(); Server_.InitLogging();
@@ -2432,12 +2465,12 @@ namespace OpenWifi {
if(!Svr.RootCA().empty()) if(!Svr.RootCA().empty())
Svr.LogCas(Logger_); Svr.LogCas(Logger_);
auto Params = new Poco::Net::HTTPServerParams; Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams;
Params->setMaxThreads(50); Params->setMaxThreads(50);
Params->setMaxQueued(200); Params->setMaxQueued(200);
Params->setKeepAlive(true); Params->setKeepAlive(true);
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new RequestHandlerFactory(Server_), Pool_, Sock, Params); auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory(Server_), Pool_, Sock, Params);
NewServer->start(); NewServer->start();
RESTServers_.push_back(std::move(NewServer)); RESTServers_.push_back(std::move(NewServer));
} }
@@ -2445,12 +2478,12 @@ namespace OpenWifi {
return 0; return 0;
} }
class RESTAPI_InternalServer : public SubSystemServer { class RESTAPI_IntServer : public SubSystemServer {
public: public:
static RESTAPI_InternalServer *instance() { static RESTAPI_IntServer *instance() {
static RESTAPI_InternalServer instance; static RESTAPI_IntServer *instance_ = new RESTAPI_IntServer;
return &instance; return instance_;
} }
inline int Start() override; inline int Start() override;
@@ -2458,12 +2491,13 @@ namespace OpenWifi {
Logger_.information("Stopping "); Logger_.information("Stopping ");
for( const auto & svr : RESTServers_ ) for( const auto & svr : RESTServers_ )
svr->stop(); svr->stop();
Pool_.joinAll();
RESTServers_.clear(); RESTServers_.clear();
} }
inline void reinitialize(Poco::Util::Application &self) override; inline void reinitialize(Poco::Util::Application &self) override;
inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) { inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings; RESTAPIHandler::BindingMap Bindings;
return RESTAPI_internal_server(Path, Bindings, Logger_, Server_); return RESTAPI_internal_server(Path, Bindings, Logger_, Server_);
} }
@@ -2472,31 +2506,31 @@ namespace OpenWifi {
Poco::ThreadPool Pool_; Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_; RESTAPI_GenericServer Server_;
RESTAPI_InternalServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi") RESTAPI_IntServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi")
{ {
} }
}; };
inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); }; inline RESTAPI_IntServer * RESTAPI_IntServer() { return RESTAPI_IntServer::instance(); };
class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { class IntRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public: public:
InternalRequestHandlerFactory(RESTAPI_GenericServer & Server) : explicit IntRequestHandlerFactory(RESTAPI_GenericServer & Server) :
Logger_(RESTAPI_InternalServer()->Logger()), Logger_(RESTAPI_IntServer()->Logger()),
Server_(Server){} Server_(Server){}
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
Poco::URI uri(Request.getURI()); Poco::URI uri(Request.getURI());
auto *Path = uri.getPath().c_str(); auto *Path = uri.getPath().c_str();
return RESTAPI_InternalServer()->CallServer(Path); return RESTAPI_IntServer()->CallServer(Path, TransactionId_++);
} }
private: private:
static inline std::atomic_uint64_t TransactionId_ = 1;
Poco::Logger & Logger_; Poco::Logger & Logger_;
RESTAPI_GenericServer & Server_; RESTAPI_GenericServer & Server_;
}; };
inline int RESTAPI_InternalServer::Start() { inline int RESTAPI_IntServer::Start() {
Logger_.information("Starting."); Logger_.information("Starting.");
Server_.InitLogging(); Server_.InitLogging();
@@ -2514,7 +2548,7 @@ namespace OpenWifi {
Params->setMaxQueued(200); Params->setMaxQueued(200);
Params->setKeepAlive(true); Params->setKeepAlive(true);
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new InternalRequestHandlerFactory(Server_), Pool_, Sock, Params); auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory(Server_), Pool_, Sock, Params);
NewServer->start(); NewServer->start();
RESTServers_.push_back(std::move(NewServer)); RESTServers_.push_back(std::move(NewServer));
} }
@@ -2554,11 +2588,13 @@ namespace OpenWifi {
DAEMON_BUS_TIMER(BusTimer), DAEMON_BUS_TIMER(BusTimer),
SubSystems_(std::move(Subsystems)) { SubSystems_(std::move(Subsystems)) {
instance_ = this; instance_ = this;
RandomEngine_.seed(std::chrono::steady_clock::now().time_since_epoch().count());
} }
[[nodiscard]] std::string Version() { return Version_; } [[nodiscard]] std::string Version() { return Version_; }
[[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; } [[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; } [[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; }
[[nodiscard]] bool Debug() const { return DebugMode_; } [[nodiscard]] bool Debug() const { return DebugMode_; }
[[nodiscard]] uint64_t ID() const { return ID_; } [[nodiscard]] uint64_t ID() const { return ID_; }
[[nodiscard]] std::string Hash() const { return MyHash_; }; [[nodiscard]] std::string Hash() const { return MyHash_; };
@@ -2571,6 +2607,13 @@ namespace OpenWifi {
static inline uint64_t GetPID() { return Poco::Process::id(); }; static inline uint64_t GetPID() { return Poco::Process::id(); };
[[nodiscard]] inline const std::string GetPublicAPIEndPoint() { return MyPublicEndPoint_ + "/api/v1"; }; [[nodiscard]] inline const std::string GetPublicAPIEndPoint() { return MyPublicEndPoint_ + "/api/v1"; };
[[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;}; [[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;};
[[nodiscard]] inline uint64_t Random(uint64_t ceiling) {
return (RandomEngine_() % ceiling);
}
[[nodiscard]] inline uint64_t Random(uint64_t min, uint64_t max) {
return ((RandomEngine_() % (max-min)) + min);
}
inline void Exit(int Reason); inline void Exit(int Reason);
inline void BusMessageReceived(const std::string &Key, const std::string & Message); inline void BusMessageReceived(const std::string &Key, const std::string & Message);
@@ -2592,7 +2635,7 @@ namespace OpenWifi {
inline void InitializeSubSystemServers(); inline void InitializeSubSystemServers();
inline void StartSubSystemServers(); inline void StartSubSystemServers();
inline void StopSubSystemServers(); inline void StopSubSystemServers();
[[nodiscard]] inline std::string CreateUUID(); [[nodiscard]] static inline std::string CreateUUID();
inline bool SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level); inline bool SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
inline void Reload(const std::string &Sub); inline void Reload(const std::string &Sub);
inline Types::StringVec GetSubSystems() const; inline Types::StringVec GetSubSystems() const;
@@ -2622,9 +2665,10 @@ namespace OpenWifi {
std::string ConfigFileName_; std::string ConfigFileName_;
Poco::UUIDGenerator UUIDGenerator_; Poco::UUIDGenerator UUIDGenerator_;
uint64_t ID_ = 1; uint64_t ID_ = 1;
Poco::SharedPtr<Poco::Crypto::RSAKey> AppKey_ = nullptr; Poco::SharedPtr<Poco::Crypto::RSAKey> AppKey_;
bool DebugMode_ = false; bool DebugMode_ = false;
std::string DataDir_; std::string DataDir_;
std::string WWWAssetsDir_;
SubSystemVec SubSystems_; SubSystemVec SubSystems_;
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
Poco::Crypto::Cipher * Cipher_ = nullptr; Poco::Crypto::Cipher * Cipher_ = nullptr;
@@ -2634,9 +2678,10 @@ namespace OpenWifi {
std::string MyPrivateEndPoint_; std::string MyPrivateEndPoint_;
std::string MyPublicEndPoint_; std::string MyPublicEndPoint_;
std::string UIURI_; std::string UIURI_;
std::string Version_{std::string(APP_VERSION) + "("+ BUILD_NUMBER + ")"}; std::string Version_{ OW_VERSION::VERSION + "("+ OW_VERSION::BUILD + ")" + " - " + OW_VERSION::HASH };
BusEventManager BusEventManager_; BusEventManager BusEventManager_;
std::mutex InfraMutex_; std::mutex InfraMutex_;
std::default_random_engine RandomEngine_;
std::string DAEMON_PROPERTIES_FILENAME; std::string DAEMON_PROPERTIES_FILENAME;
std::string DAEMON_ROOT_ENV_VAR; std::string DAEMON_ROOT_ENV_VAR;
@@ -2784,8 +2829,8 @@ namespace OpenWifi {
// add the default services // add the default services
SubSystems_.push_back(KafkaManager()); SubSystems_.push_back(KafkaManager());
SubSystems_.push_back(ALBHealthCheckServer()); SubSystems_.push_back(ALBHealthCheckServer());
SubSystems_.push_back(RESTAPI_server()); SubSystems_.push_back(RESTAPI_ExtServer());
SubSystems_.push_back(RESTAPI_InternalServer()); SubSystems_.push_back(RESTAPI_IntServer());
Poco::Net::initializeSSL(); Poco::Net::initializeSSL();
Poco::Net::HTTPStreamFactory::registerFactory(); Poco::Net::HTTPStreamFactory::registerFactory();
@@ -2813,6 +2858,9 @@ namespace OpenWifi {
logger().log(E); logger().log(E);
} }
} }
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets","");
if(WWWAssetsDir_.empty())
WWWAssetsDir_ = DataDir_;
LoadMyConfig(); LoadMyConfig();
@@ -2919,12 +2967,41 @@ namespace OpenWifi {
inline void MicroService::StopSubSystemServers() { inline void MicroService::StopSubSystemServers() {
BusEventManager_.Stop(); BusEventManager_.Stop();
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) {
(*i)->Stop(); (*i)->Stop();
} }
}
[[nodiscard]] inline std::string MicroService::CreateUUID() { [[nodiscard]] inline std::string MicroService::CreateUUID() {
return UUIDGenerator_.create().toString(); static std::random_device rd;
static std::mt19937_64 gen(rd());
static std::uniform_int_distribution<> dis(0, 15);
static std::uniform_int_distribution<> dis2(8, 11);
std::stringstream ss;
int i;
ss << std::hex;
for (i = 0; i < 8; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 4; i++) {
ss << dis(gen);
}
ss << "-4";
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
ss << dis2(gen);
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 12; i++) {
ss << dis(gen);
};
return ss.str();
} }
inline bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) { inline bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
@@ -2938,7 +3015,6 @@ namespace OpenWifi {
} }
return true; return true;
} else { } else {
// std::cout << "Sub:" << SubSystem << " Level:" << Level << std::endl;
for (auto i : SubSystems_) { for (auto i : SubSystems_) {
if (Sub == Poco::toLower(i->Name())) { if (Sub == Poco::toLower(i->Name())) {
i->Logger().setLevel(P); i->Logger().setLevel(P);
@@ -3088,7 +3164,6 @@ namespace OpenWifi {
StartSubSystemServers(); StartSubSystemServers();
waitForTerminationRequest(); waitForTerminationRequest();
StopSubSystemServers(); StopSubSystemServers();
logger.notice(Poco::format("Stopped %s...",DAEMON_APP_NAME)); logger.notice(Poco::format("Stopped %s...",DAEMON_APP_NAME));
} }
@@ -3168,6 +3243,7 @@ namespace OpenWifi {
inline int ALBHealthCheckServer::Start() { inline int ALBHealthCheckServer::Start() {
if(MicroService::instance().ConfigGetBool("alb.enable",false)) { if(MicroService::instance().ConfigGetBool("alb.enable",false)) {
Running_=true;
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_); Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
auto Params = new Poco::Net::HTTPServerParams; auto Params = new Poco::Net::HTTPServerParams;
@@ -3212,41 +3288,42 @@ namespace OpenWifi {
KafkaEnabled_ = MicroService::instance().ConfigGetBool("openwifi.kafka.enable",false); KafkaEnabled_ = MicroService::instance().ConfigGetBool("openwifi.kafka.enable",false);
} }
inline void KafkaManager::ProducerThr() { inline void KafkaProducer::run() {
cppkafka::Configuration Config({ cppkafka::Configuration Config({
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
}); });
SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" + KafkaManager()->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
std::to_string(MicroService::instance().ID()) + std::to_string(MicroService::instance().ID()) +
R"lit( , "host" : ")lit" + MicroService::instance().PrivateEndPoint() + R"lit( , "host" : ")lit" + MicroService::instance().PrivateEndPoint() +
R"lit(" } , "payload" : )lit" ; R"lit(" } , "payload" : )lit" ;
cppkafka::Producer Producer(Config); cppkafka::Producer Producer(Config);
ProducerRunning_ = true; Running_ = true;
while(ProducerRunning_) { while(Running_) {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::this_thread::sleep_for(std::chrono::milliseconds(200));
try try
{ {
std::lock_guard G(ProducerMutex_); std::lock_guard G(Mutex_);
auto Num=0; auto Num=0;
while (!Queue_.empty()) { while (!KafkaManager()->Queue_.empty()) {
const auto M = Queue_.front(); const auto M = KafkaManager()->Queue_.front();
Producer.produce( Producer.produce(
cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad)); cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad));
Queue_.pop(); KafkaManager()->Queue_.pop();
Num++; Num++;
} }
if(Num) if(Num)
Producer.flush(); Producer.flush();
} catch (const cppkafka::HandleException &E ) { } catch (const cppkafka::HandleException &E ) {
Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()})); KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()}));
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
Logger_.log(E); KafkaManager()->Logger_.log(E);
} }
} }
Producer.flush();
} }
inline void KafkaManager::ConsumerThr() { inline void KafkaConsumer::run() {
cppkafka::Configuration Config({ cppkafka::Configuration Config({
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") },
@@ -3266,13 +3343,13 @@ namespace OpenWifi {
cppkafka::Consumer Consumer(Config); cppkafka::Consumer Consumer(Config);
Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) { Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) { if(!partitions.empty()) {
Logger_.information(Poco::format("Partition assigned: %Lu...", KafkaManager()->Logger_.information(Poco::format("Partition assigned: %Lu...",
(uint64_t)partitions.front().get_partition())); (uint64_t)partitions.front().get_partition()));
} }
}); });
Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) { Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) { if(!partitions.empty()) {
Logger_.information(Poco::format("Partition revocation: %Lu...", KafkaManager()->Logger_.information(Poco::format("Partition revocation: %Lu...",
(uint64_t)partitions.front().get_partition())); (uint64_t)partitions.front().get_partition()));
} }
}); });
@@ -3281,13 +3358,13 @@ namespace OpenWifi {
auto BatchSize = MicroService::instance().ConfigGetInt("openwifi.kafka.consumer.batchsize",20); auto BatchSize = MicroService::instance().ConfigGetInt("openwifi.kafka.consumer.batchsize",20);
Types::StringVec Topics; Types::StringVec Topics;
for(const auto &i:Notifiers_) for(const auto &i:KafkaManager()->Notifiers_)
Topics.push_back(i.first); Topics.push_back(i.first);
Consumer.subscribe(Topics); Consumer.subscribe(Topics);
ConsumerRunning_ = true; Running_ = true;
while(ConsumerRunning_) { while(Running_) {
try { try {
std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200)); std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200));
for(auto const &Msg:MsgVec) { for(auto const &Msg:MsgVec) {
@@ -3295,14 +3372,14 @@ namespace OpenWifi {
continue; continue;
if (Msg.get_error()) { if (Msg.get_error()) {
if (!Msg.is_eof()) { if (!Msg.is_eof()) {
Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string())); KafkaManager()->Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string()));
}if(!AutoCommit) }if(!AutoCommit)
Consumer.async_commit(Msg); Consumer.async_commit(Msg);
continue; continue;
} }
std::lock_guard G(ConsumerMutex_); std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Msg.get_topic()); auto It = KafkaManager()->Notifiers_.find(Msg.get_topic());
if (It != Notifiers_.end()) { if (It != KafkaManager()->Notifiers_.end()) {
Types::TopicNotifyFunctionList &FL = It->second; Types::TopicNotifyFunctionList &FL = It->second;
std::string Key{Msg.get_key()}; std::string Key{Msg.get_key()};
std::string Payload{Msg.get_payload()}; std::string Payload{Msg.get_payload()};
@@ -3315,21 +3392,22 @@ namespace OpenWifi {
Consumer.async_commit(Msg); Consumer.async_commit(Msg);
} }
} catch (const cppkafka::HandleException &E) { } catch (const cppkafka::HandleException &E) {
Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()})); KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()}));
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
Logger_.log(E); KafkaManager()->Logger_.log(E);
} }
} }
Consumer.unsubscribe();
} }
inline void RESTAPI_server::reinitialize(Poco::Util::Application &self) { inline void RESTAPI_ExtServer::reinitialize(Poco::Util::Application &self) {
MicroService::instance().LoadConfigurationFile(); MicroService::instance().LoadConfigurationFile();
Logger_.information("Reinitializing."); Logger_.information("Reinitializing.");
Stop(); Stop();
Start(); Start();
} }
void RESTAPI_InternalServer::reinitialize(Poco::Util::Application &self) { void RESTAPI_IntServer::reinitialize(Poco::Util::Application &self) {
MicroService::instance().LoadConfigurationFile(); MicroService::instance().LoadConfigurationFile();
Logger_.information("Reinitializing."); Logger_.information("Reinitializing.");
Stop(); Stop();
@@ -3540,11 +3618,9 @@ namespace OpenWifi {
if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P; Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response OK" << std::endl;
} else { } else {
Poco::JSON::Parser P; Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response: " << Response.getStatus() << std::endl;
} }
return Response.getStatus(); return Response.getStatus();
} }
@@ -3590,11 +3666,9 @@ namespace OpenWifi {
if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P; Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response OK" << std::endl;
} else { } else {
Poco::JSON::Parser P; Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>(); ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
// std::cout << "Response: " << Response.getStatus() << std::endl;
} }
return Response.getStatus(); return Response.getStatus();
} }
@@ -3620,9 +3694,9 @@ namespace OpenWifi {
} }
#ifdef TIP_SECURITY_SERVICE #ifdef TIP_SECURITY_SERVICE
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ); [[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
#endif #endif
inline bool RESTAPIHandler::IsAuthorized() { inline bool RESTAPIHandler::IsAuthorized( bool & Expired ) {
if(Internal_) { if(Internal_) {
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
if(!Allowed) { if(!Allowed) {
@@ -3652,12 +3726,12 @@ namespace OpenWifi {
} }
} }
#ifdef TIP_SECURITY_SERVICE #ifdef TIP_SECURITY_SERVICE
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_)) { if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired)) {
#else #else
if (AuthClient()->IsAuthorized(*Request, SessionToken_, UserInfo_)) { if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired)) {
#endif #endif
if(Server_.LogIt(Request->getMethod(),true)) { if(Server_.LogIt(Request->getMethod(),true)) {
Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s", Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s'",
UserInfo_.userinfo.email, UserInfo_.userinfo.email,
Utils::FormatIPv6(Request->clientAddress().toString()), Utils::FormatIPv6(Request->clientAddress().toString()),
Request->clientAddress().toString(), Request->clientAddress().toString(),
@@ -3667,11 +3741,10 @@ namespace OpenWifi {
return true; return true;
} else { } else {
if(Server_.LogBadTokens(true)) { if(Server_.LogBadTokens(true)) {
Logger_.debug(Poco::format("X-REQ-DENIED(%s): Method='%s' Path='%s", Logger_.debug(Poco::format("X-REQ-DENIED(%s): Method='%s' Path='%s'",
Utils::FormatIPv6(Request->clientAddress().toString()), Utils::FormatIPv6(Request->clientAddress().toString()),
Request->getMethod(), Request->getURI())); Request->getMethod(), Request->getURI()));
} }
UnAuthorized("Invalid token", INVALID_TOKEN);
} }
return false; return false;
} }

View File

@@ -59,6 +59,7 @@ namespace OpenWifi::RESTAPI::Errors {
static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."}; static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."};
static const std::string MissingAuthenticationInformation{"Missing authentication information."}; static const std::string MissingAuthenticationInformation{"Missing authentication information."};
static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."}; static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."};
static const std::string ExpiredToken{"Token has expired, user must login."};
} }
#endif //OWPROV_RESTAPI_ERRORS_H #endif //OWPROV_RESTAPI_ERRORS_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")
{ {
@@ -56,18 +48,18 @@ namespace OpenWifi {
} }
void Stop() override { void Stop() override {
Pool_->shutdown();
} }
[[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) {
if(dbType_==sqlite) { if(dbType_==sqlite) {
return " LIMIT " + std::to_string(From-1) + ", " + std::to_string(HowMany) + " "; return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " ";
} else if(dbType_==pgsql) { } else if(dbType_==pgsql) {
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " ";
} else if(dbType_==mysql) { } 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) + " ";
} }
return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " ";
} }
inline std::string ConvertParams(const std::string & S) const { inline std::string ConvertParams(const std::string & S) const {
@@ -96,10 +88,10 @@ 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;
}; };
@@ -114,9 +106,8 @@ namespace OpenWifi {
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;
} }
@@ -139,9 +130,8 @@ 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;
} }
@@ -166,14 +156,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

13
src/ow_version.h.in Normal file
View File

@@ -0,0 +1,13 @@
//
// Created by stephane bourque on 2021-12-06.
//
#pragma once
#include <string>
namespace OW_VERSION {
inline static const std::string VERSION{"@CMAKE_PROJECT_VERSION@"};
inline static const std::string BUILD{"@BUILD_NUM@"};
inline static const std::string HASH{"@GIT_HASH@"};
}

View File

@@ -183,4 +183,19 @@ namespace OpenWifi {
return false; return false;
} }
void Storage::CleanOldActionLinks() {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess);
uint64_t CutOff = std::time(nullptr) - (30 * 24 * 60 * 60);
std::string St{"DELETE from ActionLinks where Created<=?"};
Delete << ConvertParams(St),
Poco::Data::Keywords::use(CutOff);
Delete.execute();
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
}
} }

View File

@@ -15,7 +15,7 @@ namespace OpenWifi {
"RevocationDate BIGINT " "RevocationDate BIGINT "
*/ */
bool Storage::AddToken(std::string &UserName, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) { bool Storage::AddToken(std::string &UserID, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Insert(Sess); Poco::Data::Statement Insert(Sess);
@@ -29,7 +29,7 @@ namespace OpenWifi {
Poco::Data::Keywords::use(Token), Poco::Data::Keywords::use(Token),
Poco::Data::Keywords::use(RefreshToken), Poco::Data::Keywords::use(RefreshToken),
Poco::Data::Keywords::use(TokenType), Poco::Data::Keywords::use(TokenType),
Poco::Data::Keywords::use(UserName), Poco::Data::Keywords::use(UserID),
Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Now),
Poco::Data::Keywords::use(Expires), Poco::Data::Keywords::use(Expires),
Poco::Data::Keywords::use(TimeOut), Poco::Data::Keywords::use(TimeOut),
@@ -42,29 +42,24 @@ namespace OpenWifi {
return false; return false;
} }
bool Storage::GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo) { bool Storage::GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate) {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess); Poco::Data::Statement Select(Sess);
RevocationDate = 0 ;
uint32_t RevocationDate = 0 ; std::string St2{"SELECT " + AllTokensFieldsForSelect + " From Tokens WHERE Token=?"};
std::string St2{"SELECT " + AllTokensValuesForSelect + " From Tokens WHERE Token=?"};
Select << ConvertParams(St2), Select << ConvertParams(St2),
Poco::Data::Keywords::into(UInfo.webtoken.access_token_), Poco::Data::Keywords::into(UInfo.webtoken.access_token_),
Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_), Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_),
Poco::Data::Keywords::into(UInfo.webtoken.token_type_), Poco::Data::Keywords::into(UInfo.webtoken.token_type_),
Poco::Data::Keywords::into(UInfo.userinfo.email), Poco::Data::Keywords::into(UInfo.userinfo.Id),
Poco::Data::Keywords::into(UInfo.webtoken.created_), Poco::Data::Keywords::into(UInfo.webtoken.created_),
Poco::Data::Keywords::into(UInfo.webtoken.expires_in_), Poco::Data::Keywords::into(UInfo.webtoken.expires_in_),
Poco::Data::Keywords::into(UInfo.webtoken.idle_timeout_), Poco::Data::Keywords::into(UInfo.webtoken.idle_timeout_),
Poco::Data::Keywords::into(RevocationDate), Poco::Data::Keywords::into(RevocationDate),
Poco::Data::Keywords::use(Token); Poco::Data::Keywords::use(Token);
Select.execute(); Select.execute();
if(RevocationDate>0)
return false;
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
Logger_.log(E); Logger_.log(E);
@@ -116,15 +111,15 @@ namespace OpenWifi {
return false; return false;
} }
bool Storage::CleanRevokedTokens(uint64_t Oldest) { bool Storage::CleanExpiredTokens() {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess); Poco::Data::Statement Delete(Sess);
uint64_t Now = std::time(nullptr); uint64_t Now = std::time(nullptr);
std::string St2{"DELETE From Tokens WHERE Created <= ?"}; std::string St2{"DELETE From Tokens WHERE (Created+Expires) <= ?"};
Delete << ConvertParams(St2), Delete << ConvertParams(St2),
Poco::Data::Keywords::use(Oldest); Poco::Data::Keywords::use(Now);
Delete.execute(); Delete.execute();
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
@@ -133,14 +128,14 @@ namespace OpenWifi {
return false; return false;
} }
bool Storage::RevokeAllTokens(std::string & username) { bool Storage::RevokeAllTokens(std::string & UserId) {
try { try {
Poco::Data::Session Sess = Pool_->get(); Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Delete(Sess); Poco::Data::Statement Delete(Sess);
std::string St2{"DELETE From Tokens WHERE Username=?"}; std::string St2{"DELETE From Tokens WHERE Username=?"};
Delete << ConvertParams(St2), Delete << ConvertParams(St2),
Poco::Data::Keywords::use(username); Poco::Data::Keywords::use(UserId);
Delete.execute(); Delete.execute();
return true; return true;
} catch(const Poco::Exception &E) { } catch(const Poco::Exception &E) {

View File

@@ -80,7 +80,23 @@ namespace OpenWifi {
return true; return true;
} }
std::string DefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"}; std::string OldDefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"};
std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"};
void Storage::ReplaceOldDefaultUUID() {
try {
Poco::Data::Session Sess = Pool_->get();
std::string St1{"update users set id=? where id=?"};
Poco::Data::Statement Update(Sess);
Update << ConvertParams(St1),
Poco::Data::Keywords::use(NewDefaultUseridStockUUID),
Poco::Data::Keywords::use(OldDefaultUseridStockUUID);
Update.execute();
} catch (...) {
}
}
// if we do not find a default user, then we need to create one based on the // if we do not find a default user, then we need to create one based on the
// property file. We must set its flag to "must change password", this user has root privilege. // property file. We must set its flag to "must change password", this user has root privilege.
@@ -89,12 +105,13 @@ namespace OpenWifi {
SecurityObjects::UserInfo U; SecurityObjects::UserInfo U;
bool DefaultUserCreated = false; bool DefaultUserCreated = false;
ReplaceOldDefaultUUID();
AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated); AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated);
if(!GetUserById(DefaultUseridStockUUID,U) && !DefaultUserCreated) { if(!GetUserById(NewDefaultUseridStockUUID,U) && !DefaultUserCreated) {
U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password",""); U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password","");
U.lastPasswords.push_back(U.currentPassword); U.lastPasswords.push_back(U.currentPassword);
U.email = MicroService::instance().ConfigGetString("authentication.default.username",""); U.email = MicroService::instance().ConfigGetString("authentication.default.username","");
U.Id = DefaultUseridStockUUID; U.Id = NewDefaultUseridStockUUID;
U.userRole = SecurityObjects::ROOT; U.userRole = SecurityObjects::ROOT;
U.creationDate = std::time(nullptr); U.creationDate = std::time(nullptr);
U.validated = true; U.validated = true;
@@ -132,7 +149,7 @@ namespace OpenWifi {
return false; return false;
if(!PasswordHashedAlready) { if(!PasswordHashedAlready) {
NewUser.Id = MicroService::instance().CreateUUID(); NewUser.Id = MicroService::CreateUUID();
NewUser.creationDate = std::time(nullptr); NewUser.creationDate = std::time(nullptr);
} }

View File

@@ -15,23 +15,23 @@ namespace OpenWifi {
"description varchar," "description varchar,"
"avatar varchar," "avatar varchar,"
"email varchar," "email varchar,"
"validated int," "validated boolean,"
"validationEmail varchar," "validationEmail varchar,"
"validationDate bigint," "validationDate bigint,"
"creationDate bigint," "creationDate bigint,"
"validationURI varchar," "validationURI varchar,"
"changePassword int," "changePassword boolean,"
"lastLogin bigint," "lastLogin bigint,"
"currentLoginURI varchar," "currentLoginURI varchar,"
"lastPasswordChange bigint," "lastPasswordChange bigint,"
"lastEmailCheck bigint," "lastEmailCheck bigint,"
"waitingForEmailCheck int," "waitingForEmailCheck boolean,"
"locale varchar," "locale varchar,"
"notes text," "notes text,"
"location varchar," "location varchar,"
"owner varchar," "owner varchar,"
"suspended int," "suspended boolean,"
"blackListed int," "blackListed boolean,"
"userRole varchar," "userRole varchar,"
"userTypeProprietaryInfo text," "userTypeProprietaryInfo text,"
"securityPolicy text," "securityPolicy text,"
@@ -111,23 +111,23 @@ namespace OpenWifi {
std::string, // description; std::string, // description;
std::string, // avatar; std::string, // avatar;
std::string, // email; std::string, // email;
uint64_t, // bool validated = false; bool, // bool validated = false;
std::string, // validationEmail; std::string, // validationEmail;
uint64_t, // validationDate = 0; uint64_t, // validationDate = 0;
uint64_t, // creationDate = 0; uint64_t, // creationDate = 0;
std::string, // validationURI; std::string, // validationURI;
uint64_t, // bool changePassword = true; bool, // bool changePassword = true;
uint64_t, // lastLogin = 0; uint64_t, // lastLogin = 0;
std::string, // currentLoginURI; std::string, // currentLoginURI;
uint64_t, // lastPasswordChange = 0; uint64_t, // lastPasswordChange = 0;
uint64_t, // lastEmailCheck = 0; uint64_t, // lastEmailCheck = 0;
uint64_t, // bool waitingForEmailCheck = false; bool, // bool waitingForEmailCheck = false;
std::string, // locale; std::string, // locale;
std::string, // notes; std::string, // notes;
std::string, // location; std::string, // location;
std::string, // owner; std::string, // owner;
uint64_t, // bool suspended = false; bool, // bool suspended = false;
uint64_t, // bool blackListed = false; bool, // bool blackListed = false;
std::string, // userRole; std::string, // userRole;
std::string, // userTypeProprietaryInfo; std::string, // userTypeProprietaryInfo;
std::string, // securityPolicy; std::string, // securityPolicy;

View File

@@ -35,7 +35,7 @@ fi
token="" token=""
result_file=result.json result_file=result.json
username="tip@ucentral.com" username="tip@ucentral.com"
password="openwifi" password="Snoopy99!!!"
#username="stephb@incognito.com" #username="stephb@incognito.com"
#password="Snoopy98!" #password="Snoopy98!"
browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl) browser_list=(firefox sensible-browser xdg-open w3m links links2 lynx youtube-dl)

26
wait-for-postgres.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
# wait-for-postgres.sh
set -e
host="$1"
shift
export PGUSER=$(grep 'storage.type.postgresql.username' $OWSEC_CONFIG/owsec.properties | awk -F '= ' '{print $2}')
export PGPASSWORD=$(grep 'storage.type.postgresql.password' $OWSEC_CONFIG/owsec.properties | awk -F '= ' '{print $2}')
until psql -h "$host" -c '\q'; do
>&2 echo "Postgres is unavailable - sleeping"
sleep 1
done
>&2 echo "Postgres is up - executing command"
if [ "$1" = '/openwifi/owsec' -a "$(id -u)" = '0' ]; then
if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$OWSEC_USER": "$OWSEC_ROOT" "$OWSEC_CONFIG"
fi
exec su-exec "$OWSEC_USER" "$@"
fi
exec "$@"