mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-30 18:27:49 +00:00 
			
		
		
		
	Compare commits
	
		
			114 Commits
		
	
	
		
			v2.3.0-RC1
			...
			v2.4.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 02057624de | ||
|   | 2e394d0513 | ||
|   | 24b022fa60 | ||
|   | 88922786ff | ||
|   | 4510cd034f | ||
|   | af5774ce36 | ||
|   | 2573b8cd4f | ||
|   | 9c5b18a536 | ||
|   | 768c428a67 | ||
|   | 389ceb8b7d | ||
|   | 157f18c117 | ||
|   | 2538f9c768 | ||
|   | 85d998ad76 | ||
|   | a407f2e38d | ||
|   | d0d2be0870 | ||
|   | 78cba562e6 | ||
|   | 350df38c3f | ||
|   | 9e79b73e20 | ||
|   | eb4dfc25f2 | ||
|   | bedec254c5 | ||
|   | 96a566a2b5 | ||
|   | ad2eb1711e | ||
|   | 7244bcb455 | ||
|   | 1db5201418 | ||
|   | 1bc635f553 | ||
|   | 257ac42d7c | ||
|   | acb38e5313 | ||
|   | 7940f0bd85 | ||
|   | 62c06d0bad | ||
|   | 494a199610 | ||
|   | 5307b0b35a | ||
|   | c58728f38e | ||
|   | 1f09c3b619 | ||
|   | d9c6388502 | ||
|   | 5e35906aec | ||
|   | 773618ae07 | ||
|   | cca4441ac7 | ||
|   | 730ca7b292 | ||
|   | 5b4dbb088f | ||
|   | bc11a19ee4 | ||
|   | c835e4d0b9 | ||
|   | f1a2ba90f6 | ||
|   | 5b96ef396f | ||
|   | c204d34bf4 | ||
|   | 4b982bf64b | ||
|   | 37298cc600 | ||
|   | 03619cc900 | ||
|   | f4fc6975e1 | ||
|   | 1f1d596c5a | ||
|   | a5802bf631 | ||
|   | 6471eabc82 | ||
|   | ab6fbaca11 | ||
|   | 1e8e5c18b2 | ||
|   | 3cf23af068 | ||
|   | 1a0b549731 | ||
|   | a835d2e571 | ||
|   | ff7455af24 | ||
|   | 48610bac5d | ||
|   | 7bd5b4d4e6 | ||
|   | e1a51c2a91 | ||
|   | cd0222f765 | ||
|   | 12fddd8bc4 | ||
|   | 9095d831db | ||
|   | 4e8f97df9b | ||
|   | 28808eae93 | ||
|   | 6c24a23863 | ||
|   | 5931c91054 | ||
|   | 9d956c13f7 | ||
|   | ea1adde361 | ||
|   | eaac1f1625 | ||
|   | c5f4c067bb | ||
|   | 31a9e4564b | ||
|   | a9affc29bb | ||
|   | 65fc0a1d10 | ||
|   | 82c01ce438 | ||
|   | 5f900883e8 | ||
|   | e97b8e64be | ||
|   | 6c90c75708 | ||
|   | a3d86c7cf9 | ||
|   | 50b6ac9522 | ||
|   | 15b947a34d | ||
|   | 160bd00a99 | ||
|   | 3c7daa537a | ||
|   | c5bab1d749 | ||
|   | 96c3244be0 | ||
|   | 7e4b515f60 | ||
|   | a63f80e497 | ||
|   | 2eae6cc73c | ||
|   | 96f215b3c2 | ||
|   | 9551384358 | ||
|   | b21c5c5e00 | ||
|   | 031d35256c | ||
|   | 5738fa47bb | ||
|   | fe17650333 | ||
|   | 7636568fb4 | ||
|   | c0ef77eb53 | ||
|   | 00742a5d0a | ||
|   | a96f673380 | ||
|   | 53ecdb471e | ||
|   | f80a0c5007 | ||
|   | 9e7d7ba67d | ||
|   | b508c0d054 | ||
|   | 79788dab44 | ||
|   | 8dec946c45 | ||
|   | 43ea5ac424 | ||
|   | 328ff158cb | ||
|   | 2b89d843c3 | ||
|   | 45a50483be | ||
|   | c8ae94a062 | ||
|   | 7b19143d6f | ||
|   | bc0c889098 | ||
|   | 6f8f81866f | ||
|   | f213c99816 | ||
|   | 423aca9892 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -18,3 +18,4 @@ _deps | |||||||
| *.csr | *.csr | ||||||
| /cmake-build/ | /cmake-build/ | ||||||
| /smake-build-debug/ | /smake-build-debug/ | ||||||
|  | test_scripts/curl/result.json | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| cmake_minimum_required(VERSION 3.13) | cmake_minimum_required(VERSION 3.13) | ||||||
| project(owsec VERSION 2.3.0) | project(owsec VERSION 2.4.0) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 17) | set(CMAKE_CXX_STANDARD 17) | ||||||
|  |  | ||||||
| @@ -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) | ||||||
| @@ -42,7 +53,7 @@ find_package(Boost REQUIRED system) | |||||||
| find_package(OpenSSL REQUIRED) | find_package(OpenSSL REQUIRED) | ||||||
| find_package(ZLIB REQUIRED) | find_package(ZLIB REQUIRED) | ||||||
| find_package(AWSSDK     REQUIRED COMPONENTS sns) | find_package(AWSSDK     REQUIRED COMPONENTS sns) | ||||||
|  | find_package(nlohmann_json  REQUIRED) | ||||||
| find_package(CppKafka REQUIRED) | find_package(CppKafka REQUIRED) | ||||||
| find_package(PostgreSQL REQUIRED) | find_package(PostgreSQL REQUIRED) | ||||||
| find_package(MySQL REQUIRED) | find_package(MySQL REQUIRED) | ||||||
| @@ -50,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 | ||||||
| @@ -86,7 +100,11 @@ add_executable( owsec | |||||||
|         src/MFAServer.cpp src/MFAServer.h |         src/MFAServer.cpp src/MFAServer.h | ||||||
|         src/SMS_provider_aws.cpp src/SMS_provider_aws.h |         src/SMS_provider_aws.cpp src/SMS_provider_aws.h | ||||||
|         src/SMS_provider.cpp src/SMS_provider.h |         src/SMS_provider.cpp src/SMS_provider.h | ||||||
|         src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h) |         src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h | ||||||
|  |         src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h | ||||||
|  |         src/storage/storage_tokens.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 | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -11,6 +11,8 @@ RUN apk add --update --no-cache \ | |||||||
|  |  | ||||||
| RUN git clone https://github.com/stephb9959/poco /poco | RUN git clone https://github.com/stephb9959/poco /poco | ||||||
| RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | RUN git clone https://github.com/stephb9959/cppkafka /cppkafka | ||||||
|  | RUN git clone https://github.com/nlohmann/json /json | ||||||
|  | RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator | ||||||
| RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp | ||||||
|  |  | ||||||
| WORKDIR /aws-sdk-cpp | WORKDIR /aws-sdk-cpp | ||||||
| @@ -37,9 +39,26 @@ RUN cmake .. | |||||||
| RUN cmake --build . --config Release -j8 | RUN cmake --build . --config Release -j8 | ||||||
| RUN cmake --build . --target install | RUN cmake --build . --target install | ||||||
|  |  | ||||||
|  | WORKDIR /json | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN make | ||||||
|  | RUN make install | ||||||
|  |  | ||||||
|  | WORKDIR /json-schema-validator | ||||||
|  | RUN mkdir cmake-build | ||||||
|  | WORKDIR cmake-build | ||||||
|  | RUN cmake .. | ||||||
|  | RUN make | ||||||
|  | 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 | ||||||
| @@ -59,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/ | ||||||
| @@ -71,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 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								README.md
									
									
									
									
									
								
							| @@ -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. | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,2 @@ | |||||||
| *.swp | *.swp | ||||||
|  | charts | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -24,6 +24,9 @@ spec: | |||||||
|     metadata: |     metadata: | ||||||
|       annotations: |       annotations: | ||||||
|         checksum/config: {{ include "owsec.config" . | sha256sum }} |         checksum/config: {{ include "owsec.config" . | sha256sum }} | ||||||
|  |         {{- with .Values.podAnnotations }} | ||||||
|  |         {{- toYaml . | nindent 8 }} | ||||||
|  |         {{- end }} | ||||||
|       labels: |       labels: | ||||||
|         app.kubernetes.io/name: {{ include "owsec.name" . }} |         app.kubernetes.io/name: {{ include "owsec.name" . }} | ||||||
|         app.kubernetes.io/instance: {{ .Release.Name }} |         app.kubernetes.io/instance: {{ .Release.Name }} | ||||||
|   | |||||||
| @@ -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.1 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
| #    regcred: | #    regcred: | ||||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
| @@ -95,6 +95,8 @@ tolerations: [] | |||||||
|  |  | ||||||
| affinity: {} | affinity: {} | ||||||
|  |  | ||||||
|  | podAnnotations: {} | ||||||
|  |  | ||||||
| persistence: | persistence: | ||||||
|   enabled: true |   enabled: true | ||||||
|   # storageClassName: "-" |   # storageClassName: "-" | ||||||
|   | |||||||
| @@ -51,6 +51,18 @@ components: | |||||||
|             properties: |             properties: | ||||||
|               ErrorCode: |               ErrorCode: | ||||||
|                 type: integer |                 type: integer | ||||||
|  |                 enum: | ||||||
|  |                   - 0     # Success | ||||||
|  |                   - 1     # PASSWORD_CHANGE_REQUIRED, | ||||||
|  |                   - 2     # INVALID_CREDENTIALS, | ||||||
|  |                   - 3     # PASSWORD_ALREADY_USED, | ||||||
|  |                   - 4     # USERNAME_PENDING_VERIFICATION, | ||||||
|  |                   - 5     # PASSWORD_INVALID, | ||||||
|  |                   - 6     # INTERNAL_ERROR, | ||||||
|  |                   - 7     # ACCESS_DENIED, | ||||||
|  |                   - 8     # INVALID_TOKEN | ||||||
|  |                   - 9     # expired token | ||||||
|  |                   - 10    # rate limit exceeded | ||||||
|               ErrorDetails: |               ErrorDetails: | ||||||
|                 type: string |                 type: string | ||||||
|               ErrorDescription: |               ErrorDescription: | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										45
									
								
								src/ACLProcessor.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										68
									
								
								src/ActionLinkManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/ActionLinkManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-08. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "ActionLinkManager.h" | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     int ActionLinkManager::Start() { | ||||||
|  |         if(!Running_) | ||||||
|  |             Thr_.start(*this); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void ActionLinkManager::Stop() { | ||||||
|  |         if(Running_) { | ||||||
|  |             Running_ = false; | ||||||
|  |             Thr_.wakeUp(); | ||||||
|  |             Thr_.join(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void ActionLinkManager::run() { | ||||||
|  |         Running_ = true ; | ||||||
|  |  | ||||||
|  |         while(Running_) { | ||||||
|  |             Poco::Thread::trySleep(2000); | ||||||
|  |             if(!Running_) | ||||||
|  |                 break; | ||||||
|  |             std::vector<SecurityObjects::ActionLink>    Links; | ||||||
|  |             { | ||||||
|  |                 std::lock_guard G(Mutex_); | ||||||
|  |                 StorageService()->GetActions(Links); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(Links.empty()) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             for(auto &i:Links) { | ||||||
|  |                 if(!Running_) | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 SecurityObjects::UserInfo UInfo; | ||||||
|  |                 if(!StorageService()->GetUserById(i.userId,UInfo)) { | ||||||
|  |                     StorageService()->CancelAction(i.id); | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if(i.action==OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD) { | ||||||
|  |                     if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::FORGOT_PASSWORD)) { | ||||||
|  |                         Logger_.information(Poco::format("Send password reset link to %s",UInfo.email)); | ||||||
|  |                     } | ||||||
|  |                     StorageService()->SentAction(i.id); | ||||||
|  |                 } else if (i.action==OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL) { | ||||||
|  |                     if(AuthService::SendEmailToUser(i.id, UInfo.email, AuthService::EMAIL_VERIFICATION)) { | ||||||
|  |                         Logger_.information(Poco::format("Send email verification link to %s",UInfo.email)); | ||||||
|  |                     } | ||||||
|  |                     StorageService()->SentAction(i.id); | ||||||
|  |                 } else { | ||||||
|  |                     StorageService()->SentAction(i.id); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								src/ActionLinkManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/ActionLinkManager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-08. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef OWSEC_ACTIONLINKMANAGER_H | ||||||
|  | #define OWSEC_ACTIONLINKMANAGER_H | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     class ActionLinkManager : public SubSystemServer, Poco::Runnable { | ||||||
|  |     public: | ||||||
|  |  | ||||||
|  |         enum Actions { | ||||||
|  |             FORGOT_PASSWORD, | ||||||
|  |             VERIFY_EMAIL | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         static ActionLinkManager * instance() { | ||||||
|  |             static auto * instance_ = new ActionLinkManager; | ||||||
|  |             return instance_; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         int Start() final; | ||||||
|  |         void Stop() final; | ||||||
|  |         void run(); | ||||||
|  |  | ||||||
|  |     private: | ||||||
|  |         Poco::Thread        Thr_; | ||||||
|  |         std::atomic_bool    Running_ = false; | ||||||
|  |  | ||||||
|  |         ActionLinkManager() noexcept: | ||||||
|  |             SubSystemServer("ActionLinkManager", "ACTION-SVR", "action.server") | ||||||
|  |                 { | ||||||
|  |                 } | ||||||
|  |     }; | ||||||
|  |     inline ActionLinkManager * ActionLinkManager() { return ActionLinkManager::instance(); } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif //OWSEC_ACTIONLINKMANAGER_H | ||||||
| @@ -11,6 +11,7 @@ | |||||||
| #include "Poco/Net/OAuth20Credentials.h" | #include "Poco/Net/OAuth20Credentials.h" | ||||||
| #include "Poco/JWT/Token.h" | #include "Poco/JWT/Token.h" | ||||||
| #include "Poco/JWT/Signer.h" | #include "Poco/JWT/Signer.h" | ||||||
|  | #include "Poco/StringTokenizer.h" | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| @@ -21,7 +22,6 @@ | |||||||
| #include "MFAServer.h" | #include "MFAServer.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class AuthService *AuthService::instance_ = nullptr; |  | ||||||
|  |  | ||||||
|     AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) { |     AuthService::ACCESS_TYPE AuthService::IntToAccessType(int C) { | ||||||
| 		switch (C) { | 		switch (C) { | ||||||
| @@ -46,10 +46,6 @@ namespace OpenWifi { | |||||||
| 		Signer_.setRSAKey(MicroService::instance().Key()); | 		Signer_.setRSAKey(MicroService::instance().Key()); | ||||||
| 		Signer_.addAllAlgorithms(); | 		Signer_.addAllAlgorithms(); | ||||||
| 		Logger_.notice("Starting..."); | 		Logger_.notice("Starting..."); | ||||||
|         Secure_ = MicroService::instance().ConfigGetBool("authentication.enabled",true); |  | ||||||
|         DefaultPassword_ = MicroService::instance().ConfigGetString("authentication.default.password",""); |  | ||||||
|         DefaultUserName_ = MicroService::instance().ConfigGetString("authentication.default.username",""); |  | ||||||
|         Mechanism_ = MicroService::instance().ConfigGetString("authentication.service.type","internal"); |  | ||||||
|         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); |         PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$"); | ||||||
|         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); |         TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60); | ||||||
|         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); |         HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5); | ||||||
| @@ -60,54 +56,67 @@ 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 ) | ||||||
|     { |     { | ||||||
|         if(!Secure_) |         std::lock_guard	Guard(Mutex_); | ||||||
|             return true; |         Expired = false; | ||||||
|  |  | ||||||
|         std::lock_guard		Guard(Mutex_); |  | ||||||
|  |  | ||||||
| 		std::string CallToken; |  | ||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			Poco::Net::OAuth20Credentials Auth(Request); | 		    std::string CallToken; | ||||||
|  | 		    Poco::Net::OAuth20Credentials Auth(Request); | ||||||
| 			if (Auth.getScheme() == "Bearer") { | 		    if (Auth.getScheme() == "Bearer") { | ||||||
| 				CallToken = Auth.getBearerToken(); | 		        CallToken = Auth.getBearerToken(); | ||||||
| 			} |  | ||||||
| 		} catch(const Poco::Exception &E) { |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if(!CallToken.empty()) { |  | ||||||
| 		    if(StorageService()->IsTokenRevoked(CallToken)) |  | ||||||
| 		        return false; |  | ||||||
| 		    auto Client = UserCache_.find(CallToken); |  | ||||||
| 		    if( Client == UserCache_.end() ) |  | ||||||
| 		        return ValidateToken(CallToken, CallToken, UInfo); |  | ||||||
|  |  | ||||||
| 		    if((Client->second.webtoken.created_ + Client->second.webtoken.expires_in_) > time(nullptr)) { |  | ||||||
| 		        SessionToken = CallToken; |  | ||||||
| 		        UInfo = Client->second ; |  | ||||||
| 		        return true; |  | ||||||
| 		    } | 		    } | ||||||
| 		    UserCache_.erase(CallToken); |  | ||||||
| 		    StorageService()->RevokeToken(CallToken); |  | ||||||
| 		    return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|  | 		    if(!CallToken.empty()) { | ||||||
|  | 		        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; | ||||||
|  | 		                Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr); | ||||||
|  | 		                if(StorageService()->GetUserById(UInfo2.userinfo.Id,UInfo.userinfo)) { | ||||||
|  | 		                    UInfo.webtoken = UInfo2.webtoken; | ||||||
|  | 		                    UserCache_.update(CallToken, UInfo); | ||||||
|  | 		                    SessionToken = CallToken; | ||||||
|  | 		                    return true; | ||||||
|  | 		                } | ||||||
|  | 		            } | ||||||
|  | 		            return false; | ||||||
|  | 		        } | ||||||
|  | 		        if(!Expired) { | ||||||
|  | 		            SessionToken = CallToken; | ||||||
|  | 		            UInfo = *Client ; | ||||||
|  | 		            return true; | ||||||
|  | 		        } | ||||||
|  |                 RevokeToken(CallToken); | ||||||
|  | 		        return false; | ||||||
|  | 		    } | ||||||
|  | 		} catch(const Poco::Exception &E) { | ||||||
|  | 		    Logger_.log(E); | ||||||
|  | 		} | ||||||
| 		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; | ||||||
|     } |     } | ||||||
| @@ -123,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"); | ||||||
| @@ -134,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) { | ||||||
| @@ -143,7 +149,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) { |     [[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) { | ||||||
|         std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr))); |         std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)) + ":" + std::to_string(rand())); | ||||||
|         HMAC_.update(Identity); |         HMAC_.update(Identity); | ||||||
|         return Poco::DigestEngine::digestToHex(HMAC_.digest()); |         return Poco::DigestEngine::digestToHex(HMAC_.digest()); | ||||||
|     } |     } | ||||||
| @@ -168,28 +174,6 @@ namespace OpenWifi { | |||||||
| 		return JWT; | 		return JWT; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	bool AuthService::ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo  ) { |  | ||||||
|         std::lock_guard		Guard(Mutex_); |  | ||||||
|  |  | ||||||
| 		try { |  | ||||||
|             auto E = UserCache_.find(SessionToken); |  | ||||||
|             if(E == UserCache_.end()) { |  | ||||||
|                 if(StorageService()->GetToken(SessionToken,UInfo)) { |  | ||||||
|                     if(StorageService()->GetUserById(UInfo.userinfo.email,UInfo.userinfo)) { |  | ||||||
|                         UserCache_[UInfo.webtoken.access_token_] = UInfo; |  | ||||||
|                         return true; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 UInfo = E->second; |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
| 		} catch (const Poco::Exception &E ) { |  | ||||||
| 			Logger_.log(E); |  | ||||||
| 		} |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|     void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) |     void AuthService::CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo) | ||||||
|     { |     { | ||||||
|         std::lock_guard		Guard(Mutex_); |         std::lock_guard		Guard(Mutex_); | ||||||
| @@ -207,43 +191,88 @@ 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_); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { |     bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) { | ||||||
|         auto NewPasswordHash = ComputePasswordHash(UInfo.email, NewPassword); |         std::lock_guard     G(Mutex_); | ||||||
|         for (auto const &i:UInfo.lastPasswords) { |  | ||||||
|             if (i == NewPasswordHash) { |         Poco::toLowerInPlace(UInfo.email); | ||||||
|                 return false; |         for (const auto &i:UInfo.lastPasswords) { | ||||||
|  |             auto Tokens = Poco::StringTokenizer(i,"|"); | ||||||
|  |             if(Tokens.count()==2) { | ||||||
|  |                 const auto & Salt = Tokens[0]; | ||||||
|  |                 for(const auto &j:UInfo.lastPasswords) { | ||||||
|  |                     auto OldTokens = Poco::StringTokenizer(j,"|"); | ||||||
|  |                     if(OldTokens.count()==2) { | ||||||
|  |                         SHA2_.update(Salt+NewPassword+UInfo.email); | ||||||
|  |                         if(OldTokens[1]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                             return false; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 SHA2_.update(NewPassword+UInfo.email); | ||||||
|  |                 if(Tokens[0]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                     return false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UInfo.lastPasswords.size()==HowManyOldPassword_) { |         if(UInfo.lastPasswords.size()==HowManyOldPassword_) { | ||||||
|             UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); |             UInfo.lastPasswords.erase(UInfo.lastPasswords.begin()); | ||||||
|         } |         } | ||||||
|         UInfo.lastPasswords.push_back(NewPasswordHash); |  | ||||||
|         UInfo.currentPassword = NewPasswordHash; |         auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword); | ||||||
|  |         UInfo.lastPasswords.push_back(NewHash); | ||||||
|  |         UInfo.currentPassword = NewHash; | ||||||
|         UInfo.changePassword = false; |         UInfo.changePassword = false; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     AuthService::AUTH_ERROR AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ) |     static std::string GetMeSomeSalt() { | ||||||
|  |         auto start = std::chrono::high_resolution_clock::now(); | ||||||
|  |         return std::to_string(start.time_since_epoch().count()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     std::string AuthService::ComputeNewPasswordHash(const std::string &UserName, const std::string &Password) { | ||||||
|  |         std::string UName = Poco::trim(Poco::toLower(UserName)); | ||||||
|  |         auto Salt = GetMeSomeSalt(); | ||||||
|  |         SHA2_.update(Salt + Password + UName ); | ||||||
|  |         return Salt + "|" + Utils::ToHex(SHA2_.digest()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool AuthService::ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) { | ||||||
|  |         std::lock_guard G(Mutex_); | ||||||
|  |  | ||||||
|  |         std::string UName = Poco::trim(Poco::toLower(UserName)); | ||||||
|  |         auto Tokens = Poco::StringTokenizer(StoredPassword,"|"); | ||||||
|  |         if(Tokens.count()==1) { | ||||||
|  |             SHA2_.update(Password+UName); | ||||||
|  |             if(Tokens[0]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                 return true; | ||||||
|  |         } else if (Tokens.count()==2) { | ||||||
|  |             SHA2_.update(Tokens[0]+Password+UName); | ||||||
|  |             if(Tokens[1]==Utils::ToHex(SHA2_.digest())) | ||||||
|  |                 return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired ) | ||||||
|     { |     { | ||||||
|         std::lock_guard		Guard(Mutex_); |         std::lock_guard		Guard(Mutex_); | ||||||
|         SecurityObjects::AclTemplate	ACL; |  | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UserName); |         Poco::toLowerInPlace(UserName); | ||||||
|         auto PasswordHash = ComputePasswordHash(UserName, Password); |  | ||||||
|  |  | ||||||
|         if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { |         if(StorageService()->GetUserByEmail(UserName,UInfo.userinfo)) { | ||||||
|             if(UInfo.userinfo.waitingForEmailCheck) { |             if(UInfo.userinfo.waitingForEmailCheck) { | ||||||
|                 return USERNAME_PENDING_VERIFICATION; |                 return USERNAME_PENDING_VERIFICATION; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(PasswordHash != UInfo.userinfo.currentPassword) { |             if(!ValidatePasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) { | ||||||
|                 return INVALID_CREDENTIALS; |                 return INVALID_CREDENTIALS; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -270,54 +299,35 @@ 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; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(((UserName == DefaultUserName_) && (DefaultPassword_== ComputePasswordHash(UserName,Password))) || !Secure_) |  | ||||||
|         { |  | ||||||
|             ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true; |  | ||||||
|             UInfo.webtoken.acl_template_ = ACL; |  | ||||||
|             UInfo.userinfo.email = DefaultUserName_; |  | ||||||
|             UInfo.userinfo.currentPassword = DefaultPassword_; |  | ||||||
|             UInfo.userinfo.name = DefaultUserName_; |  | ||||||
|             UInfo.userinfo.userRole = SecurityObjects::ROOT; |  | ||||||
|             CreateToken(UserName, UInfo ); |  | ||||||
|             return SUCCESS; |  | ||||||
|         } |  | ||||||
|         return INVALID_CREDENTIALS; |         return INVALID_CREDENTIALS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::string AuthService::ComputePasswordHash(const std::string &UserName, const std::string &Password) { |     bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) { | ||||||
|         std::string UName = Poco::trim(Poco::toLower(UserName)); |  | ||||||
|         SHA2_.update(Password + UName); |  | ||||||
|         return Utils::ToHex(SHA2_.digest()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool AuthService::SendEmailToUser(std::string &Email, EMAIL_REASON Reason) { |  | ||||||
|         SecurityObjects::UserInfo   UInfo; |         SecurityObjects::UserInfo   UInfo; | ||||||
|  |  | ||||||
|         if(StorageService()->GetUserByEmail(Email,UInfo)) { |         if(StorageService()->GetUserByEmail(Email,UInfo)) { | ||||||
|             switch (Reason) { |             switch (Reason) { | ||||||
|  |  | ||||||
|                 case FORGOT_PASSWORD: { |                 case FORGOT_PASSWORD: { | ||||||
|                         MessageAttributes Attrs; |                         MessageAttributes Attrs; | ||||||
|  |  | ||||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; |                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                         Attrs[LOGO] = "logo.jpg"; |                         Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                         Attrs[SUBJECT] = "Password reset link"; |                         Attrs[SUBJECT] = "Password reset link"; | ||||||
|                         Attrs[ACTION_LINK] = |                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ; | ||||||
|                                 MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + UInfo.Id ; |  | ||||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); |                         SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs); | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|  |  | ||||||
|                 case EMAIL_VERIFICATION: { |                 case EMAIL_VERIFICATION: { | ||||||
|                         MessageAttributes Attrs; |                         MessageAttributes Attrs; | ||||||
|  |  | ||||||
|                         Attrs[RECIPIENT_EMAIL] = UInfo.email; |                         Attrs[RECIPIENT_EMAIL] = UInfo.email; | ||||||
|                         Attrs[LOGO] = "logo.jpg"; |                         Attrs[LOGO] = GetLogoAssetURI(); | ||||||
|                         Attrs[SUBJECT] = "EMail Address Verification"; |                         Attrs[SUBJECT] = "EMail Address Verification"; | ||||||
|                         Attrs[ACTION_LINK] = |                         Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ; | ||||||
|                                 MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ; |  | ||||||
|                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); |                         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); | ||||||
|                         UInfo.waitingForEmailCheck = true; |                         UInfo.waitingForEmailCheck = true; | ||||||
|                     } |                     } | ||||||
| @@ -326,32 +336,56 @@ namespace OpenWifi { | |||||||
|                 default: |                 default: | ||||||
|                     break; |                     break; | ||||||
|             } |             } | ||||||
|  |             return true; | ||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { |     bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) { | ||||||
|         MessageAttributes Attrs; |         SecurityObjects::ActionLink A; | ||||||
|  |  | ||||||
|         Attrs[RECIPIENT_EMAIL] = UInfo.email; |         A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL; | ||||||
|         Attrs[LOGO] = "logo.jpg"; |         A.userId = UInfo.email; | ||||||
|         Attrs[SUBJECT] = "EMail Address Verification"; |         A.id = MicroService::CreateUUID(); | ||||||
|         Attrs[ACTION_LINK] = |         A.created = std::time(nullptr); | ||||||
|                 MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + UInfo.Id ; |         A.expires = A.created + 24*60*60; | ||||||
|         SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs); |         StorageService()->CreateAction(A); | ||||||
|         UInfo.waitingForEmailCheck = true; |         UInfo.waitingForEmailCheck = true; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo) { |     bool AuthService::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; | ||||||
|  |  | ||||||
|  |         auto Client = UserCache_.get(Token); | ||||||
|  |         if(!Client.isNull()) { | ||||||
|  |             Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr); | ||||||
|  |             WebToken = Client->webtoken; | ||||||
|  |             UserInfo = Client->userinfo; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         std::string TToken{Token}; | ||||||
|  |         if(StorageService()->IsTokenRevoked(TToken)) { | ||||||
|             return false; |             return false; | ||||||
|         WebToken = It->second.webtoken; |         } | ||||||
|         UserInfo = It->second.userinfo; |  | ||||||
|         return true; |         //  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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ | |||||||
| #include "Poco/SHA2Engine.h" | #include "Poco/SHA2Engine.h" | ||||||
| #include "Poco/Crypto/DigestEngine.h" | #include "Poco/Crypto/DigestEngine.h" | ||||||
| #include "Poco/HMACEngine.h" | #include "Poco/HMACEngine.h" | ||||||
|  | #include "Poco/ExpireLRUCache.h" | ||||||
|  |  | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
| @@ -35,16 +36,6 @@ namespace OpenWifi{ | |||||||
|             CUSTOM |             CUSTOM | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         enum AUTH_ERROR { |  | ||||||
|             SUCCESS, |  | ||||||
|             PASSWORD_CHANGE_REQUIRED, |  | ||||||
|             INVALID_CREDENTIALS, |  | ||||||
|             PASSWORD_ALREADY_USED, |  | ||||||
|             USERNAME_PENDING_VERIFICATION, |  | ||||||
|             PASSWORD_INVALID, |  | ||||||
|             INTERNAL_ERROR |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         enum EMAIL_REASON { |         enum EMAIL_REASON { | ||||||
|             FORGOT_PASSWORD, |             FORGOT_PASSWORD, | ||||||
|             EMAIL_VERIFICATION |             EMAIL_VERIFICATION | ||||||
| @@ -54,49 +45,52 @@ namespace OpenWifi{ | |||||||
|         static int AccessTypeToInt(ACCESS_TYPE T); |         static int AccessTypeToInt(ACCESS_TYPE T); | ||||||
|  |  | ||||||
|         static AuthService *instance() { |         static AuthService *instance() { | ||||||
|             if (instance_ == nullptr) { |             static auto * instance_ = new AuthService; | ||||||
|                 instance_ = new AuthService; |  | ||||||
|             } |  | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int Start() override; |         int Start() override; | ||||||
|         void Stop() override; |         void Stop() override; | ||||||
|  |  | ||||||
|         [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ); |         [[nodiscard]] bool IsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired); | ||||||
|         [[nodiscard]] AUTH_ERROR Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo ); |         [[nodiscard]] UNAUTHORIZED_REASON Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); | ||||||
|         void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); |         void CreateToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|         [[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UserInfo  ); |  | ||||||
|         [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); |         [[nodiscard]] bool SetPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo); | ||||||
|         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; |         [[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;}; | ||||||
|         void Logout(const std::string &token, bool EraseFromCache=true); |         void Logout(const std::string &token, bool EraseFromCache=true); | ||||||
|  |  | ||||||
|         bool ValidatePassword(const std::string &pwd); |         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); | ||||||
|         [[nodiscard]] bool ValidateToken(const std::string & Token, std::string & SessionToken, SecurityObjects::WebToken & UserInfo  ); |  | ||||||
|         [[nodiscard]] std::string ComputePasswordHash(const std::string &UserName, const std::string &Password); |         [[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password); | ||||||
|  |         [[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword); | ||||||
|  |  | ||||||
|         [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); |         [[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword); | ||||||
|         [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); |         [[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName); | ||||||
|  |  | ||||||
|         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); |         [[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo); | ||||||
|         [[nodiscard]] static bool SendEmailToUser(std::string &Email, EMAIL_REASON Reason); |         [[nodiscard]] static bool 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() { | ||||||
|  |             return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         [[nodiscard]] static inline const std::string GetLogoAssetFileName() { | ||||||
|  |             return MicroService::instance().WWWAssetsDir() + "/the_logo.png"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
| 		static AuthService *instance_; |  | ||||||
| 		bool    			Secure_ = false ; |  | ||||||
| 		std::string     	DefaultUserName_; |  | ||||||
| 		std::string			DefaultPassword_; |  | ||||||
| 		std::string     	Mechanism_; |  | ||||||
| 		Poco::JWT::Signer	Signer_; | 		Poco::JWT::Signer	Signer_; | ||||||
| 		Poco::SHA2Engine	SHA2_; | 		Poco::SHA2Engine	SHA2_; | ||||||
| 		SecurityObjects::UserInfoCache UserCache_; | 		Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy>    UserCache_{2048,1200000}; | ||||||
|         std::string          PasswordValidationStr_; | 		// SecurityObjects::UserInfoCache UserCache_; | ||||||
|  |         std::string         PasswordValidationStr_; | ||||||
| 		std::regex          PasswordValidation_; | 		std::regex          PasswordValidation_; | ||||||
| 		uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | 		uint64_t            TokenAging_ = 30 * 24 * 60 * 60; | ||||||
|         uint64_t            HowManyOldPassword_=5; |         uint64_t            HowManyOldPassword_=5; | ||||||
| @@ -127,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 | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ | |||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "AuthService.h" | #include "AuthService.h" | ||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
|  | #include "ActionLinkManager.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class Daemon *Daemon::instance_ = nullptr; |     class Daemon *Daemon::instance_ = nullptr; | ||||||
| @@ -44,7 +45,9 @@ namespace OpenWifi { | |||||||
|                                    SubSystemVec{ |                                    SubSystemVec{ | ||||||
|                                            StorageService(), |                                            StorageService(), | ||||||
|                                            SMSSender(), |                                            SMSSender(), | ||||||
|  |                                            ActionLinkManager(), | ||||||
|                                            SMTPMailerService(), |                                            SMTPMailerService(), | ||||||
|  |                                            RESTAPI_RateLimiter(), | ||||||
|                                            AuthService() |                                            AuthService() | ||||||
|                                    }); |                                    }); | ||||||
|         } |         } | ||||||
| @@ -53,8 +56,8 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void Daemon::initialize() { |     void Daemon::initialize() { | ||||||
|         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); |         AssetDir_ = MicroService::instance().ConfigPath("openwifi.restapi.wwwassets"); | ||||||
|         AccessPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.access", "/wwwassets/access_policy.html"); |         AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html"); | ||||||
|         PasswordPolicy_ = MicroService::instance().ConfigGetString("openwifi.document.policy.password", "/wwwassets/password_policy.html"); |         PasswordPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.password", "/wwwassets/password_policy.html"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void MicroServicePostInitialization() { |     void MicroServicePostInitialization() { | ||||||
|   | |||||||
| @@ -6,11 +6,10 @@ | |||||||
| #include "SMSSender.h" | #include "SMSSender.h" | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  | #include "AuthService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     class MFAServer * MFAServer::instance_ = nullptr; |  | ||||||
|  |  | ||||||
|     int MFAServer::Start() { |     int MFAServer::Start() { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
| @@ -27,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); | ||||||
| @@ -47,7 +46,7 @@ namespace OpenWifi { | |||||||
|         if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { |         if(Method=="email" && SMTPMailerService()->Enabled() && !UInfo.userinfo.email.empty()) { | ||||||
|             MessageAttributes Attrs; |             MessageAttributes Attrs; | ||||||
|             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; |             Attrs[RECIPIENT_EMAIL] = UInfo.userinfo.email; | ||||||
|             Attrs[LOGO] = "logo.jpg"; |             Attrs[LOGO] = AuthService::GetLogoAssetURI(); | ||||||
|             Attrs[SUBJECT] = "Login validation code"; |             Attrs[SUBJECT] = "Login validation code"; | ||||||
|             Attrs[CHALLENGE_CODE] = Challenge; |             Attrs[CHALLENGE_CODE] = Challenge; | ||||||
|             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); |             return SMTPMailerService()->SendMessage(UInfo.userinfo.email, "verification_code.txt", Attrs); | ||||||
| @@ -72,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) { | ||||||
|   | |||||||
| @@ -24,24 +24,21 @@ namespace OpenWifi { | |||||||
|         int Start() override; |         int Start() override; | ||||||
|         void Stop() override; |         void Stop() override; | ||||||
|         static MFAServer *instance() { |         static MFAServer *instance() { | ||||||
|             if (instance_ == nullptr) { |             static auto * instance_ = new MFAServer; | ||||||
|                 instance_ = new MFAServer; |  | ||||||
|             } |  | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); |         bool StartMFAChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, Poco::JSON::Object &Challenge); | ||||||
|         bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); |         bool CompleteMFAChallenge(Poco::JSON::Object::Ptr &ChallengeResponse, SecurityObjects::UserInfoAndPolicy &UInfo); | ||||||
|         bool MethodEnabled(const std::string &Method); |         static bool MethodEnabled(const std::string &Method); | ||||||
|         bool ResendCode(const std::string &uuid); |         bool ResendCode(const std::string &uuid); | ||||||
|         bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); |         static bool SendChallenge(const SecurityObjects::UserInfoAndPolicy &UInfo, const std::string &Method, const std::string &Challenge); | ||||||
|  |  | ||||||
|         static inline std::string MakeChallenge() { |         static inline std::string MakeChallenge() { | ||||||
|             return std::to_string(rand() % 999999); |             return std::to_string(MicroService::instance().Random(1,999999)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     private: |     private: | ||||||
|         static MFAServer *  instance_; |  | ||||||
|         MFAChallengeCache   Cache_; |         MFAChallengeCache   Cache_; | ||||||
|         MFAServer() noexcept: |         MFAServer() noexcept: | ||||||
|             SubSystemServer("MFServer", "MFA-SVR", "mfa") |             SubSystemServer("MFServer", "MFA-SVR", "mfa") | ||||||
|   | |||||||
| @@ -11,46 +11,61 @@ | |||||||
| #include "Daemon.h" | #include "Daemon.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::DoGet() { |     void RESTAPI_action_links::DoGet() { | ||||||
|  |  | ||||||
|         auto Action = GetParameter("action",""); |         auto Action = GetParameter("action",""); | ||||||
|         auto Id = GetParameter("id",""); |         auto Id = GetParameter("id",""); | ||||||
|  |  | ||||||
|  |         SecurityObjects::ActionLink Link; | ||||||
|  |         if(!StorageService()->GetActionLink(Id,Link)) | ||||||
|  |             return DoReturnA404(); | ||||||
|  |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
|             return RequestResetPassword(Id); |             return RequestResetPassword(Link); | ||||||
|         else if(Action=="email_verification") |         else if(Action=="email_verification") | ||||||
|             return DoEmailVerification(Id); |             return DoEmailVerification(Link); | ||||||
|         else |         else | ||||||
|             return DoReturnA404(); |             return DoReturnA404(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::DoPost() { |     void RESTAPI_action_links::DoPost() { | ||||||
|         auto Action = GetParameter("action",""); |         auto Action = GetParameter("action",""); | ||||||
|         auto Id = GetParameter("id",""); |  | ||||||
|  |  | ||||||
|         Logger_.information(Poco::format("COMPLETE-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id)); |  | ||||||
|         if(Action=="password_reset") |         if(Action=="password_reset") | ||||||
|             CompleteResetPassword(Id); |             return CompleteResetPassword(); | ||||||
|         else |         else | ||||||
|             DoReturnA404(); |             return DoReturnA404(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::RequestResetPassword(std::string &Id) { |     void RESTAPI_action_links::RequestResetPassword(SecurityObjects::ActionLink &Link) { | ||||||
|         Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Id)); |         Logger_.information(Poco::format("REQUEST-PASSWORD-RESET(%s): For ID=%s", Request->clientAddress().toString(), Link.userId)); | ||||||
|         Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"}; |         Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset.html"}; | ||||||
|         Types::StringPairVec    FormVars{ {"UUID", Id}, |         Types::StringPairVec    FormVars{ {"UUID", Link.id}, | ||||||
|                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; |                                           {"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}}; | ||||||
|         SendHTMLFileBack(FormFile,FormVars); |         SendHTMLFileBack(FormFile,FormVars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::CompleteResetPassword(std::string &Id) { |     void RESTAPI_action_links::CompleteResetPassword() { | ||||||
|         //  form has been posted... |         //  form has been posted... | ||||||
|         RESTAPI_PartHandler PartHandler; |         RESTAPI_PartHandler PartHandler; | ||||||
|         Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler); |         Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler); | ||||||
|         if (!Form.empty()) { |         if (!Form.empty()) { | ||||||
|  |  | ||||||
|             auto Password1 = Form.get("password1","bla"); |             auto Password1 = Form.get("password1","bla"); | ||||||
|             auto Password2 = Form.get("password1","blu"); |             auto Password2 = Form.get("password1","blu"); | ||||||
|             Id = Form.get("id",""); |             auto Id = Form.get("id",""); | ||||||
|  |             auto Now = std::time(nullptr); | ||||||
|  |  | ||||||
|  |             SecurityObjects::ActionLink Link; | ||||||
|  |             if(!StorageService()->GetActionLink(Id,Link)) | ||||||
|  |                 return DoReturnA404(); | ||||||
|  |  | ||||||
|  |             if(Now > Link.expires) { | ||||||
|  |                 StorageService()->CancelAction(Id); | ||||||
|  |                 return DoReturnA404(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) { |             if(Password1!=Password2 || !AuthService()->ValidatePassword(Password2) || !AuthService()->ValidatePassword(Password1)) { | ||||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; |                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, |                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
| @@ -62,7 +77,7 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             SecurityObjects::UserInfo   UInfo; |             SecurityObjects::UserInfo   UInfo; | ||||||
|             if(!StorageService()->GetUserById(Id,UInfo)) { |             if(!StorageService()->GetUserById(Link.userId,UInfo)) { | ||||||
|                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; |                 Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"}; | ||||||
|                 Types::StringPairVec    FormVars{ {"UUID", Id}, |                 Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; |                                                   {"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}}; | ||||||
| @@ -82,37 +97,45 @@ namespace OpenWifi { | |||||||
|                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; |                                                   {"ERROR_TEXT", "You cannot reuse one of your recent passwords."}}; | ||||||
|                 return SendHTMLFileBack(FormFile,FormVars); |                 return SendHTMLFileBack(FormFile,FormVars); | ||||||
|             } |             } | ||||||
|             StorageService()->UpdateUserInfo(UInfo.email,Id,UInfo); |             StorageService()->UpdateUserInfo(UInfo.email,Link.userId,UInfo); | ||||||
|             Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; |             Poco::File  FormFile{ Daemon()->AssetDir() + "/password_reset_success.html"}; | ||||||
|             Types::StringPairVec    FormVars{ {"UUID", Id}, |             Types::StringPairVec    FormVars{ {"UUID", Id}, | ||||||
|                                               {"USERNAME", UInfo.email}, |                                               {"USERNAME", UInfo.email}, | ||||||
|                                               {"ACTION_LINK",MicroService::instance().GetUIURI()}}; |                                               {"ACTION_LINK",MicroService::instance().GetUIURI()}}; | ||||||
|  |             StorageService()->CompleteAction(Id); | ||||||
|             SendHTMLFileBack(FormFile,FormVars); |             SendHTMLFileBack(FormFile,FormVars); | ||||||
|         } else { |         } else { | ||||||
|             DoReturnA404(); |             DoReturnA404(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void RESTAPI_action_links::DoEmailVerification(std::string &Id) { |     void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) { | ||||||
|         SecurityObjects::UserInfo UInfo; |         auto Now = std::time(nullptr); | ||||||
|  |  | ||||||
|         Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), Id)); |         if(Now > Link.expires) { | ||||||
|         if (!StorageService()->GetUserById(Id, UInfo)) { |             StorageService()->CancelAction(Link.id); | ||||||
|             Types::StringPairVec FormVars{{"UUID",       Id}, |             return DoReturnA404(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SecurityObjects::UserInfo UInfo; | ||||||
|  |         if (!StorageService()->GetUserById(Link.userId, UInfo)) { | ||||||
|  |             Types::StringPairVec FormVars{{"UUID",       Link.id}, | ||||||
|                                           {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; |                                           {"ERROR_TEXT", "This does not appear to be a valid email verification link.."}}; | ||||||
|             Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; |             Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_error.html"}; | ||||||
|             return SendHTMLFileBack(FormFile, FormVars); |             return SendHTMLFileBack(FormFile, FormVars); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         Logger_.information(Poco::format("EMAIL-VERIFICATION(%s): For ID=%s", Request->clientAddress().toString(), UInfo.email)); | ||||||
|         UInfo.waitingForEmailCheck = false; |         UInfo.waitingForEmailCheck = false; | ||||||
|         UInfo.validated = true; |         UInfo.validated = true; | ||||||
|         UInfo.lastEmailCheck = std::time(nullptr); |         UInfo.lastEmailCheck = std::time(nullptr); | ||||||
|         UInfo.validationDate = std::time(nullptr); |         UInfo.validationDate = std::time(nullptr); | ||||||
|         StorageService()->UpdateUserInfo(UInfo.email, Id, UInfo); |         StorageService()->UpdateUserInfo(UInfo.email, Link.userId, UInfo); | ||||||
|         Types::StringPairVec FormVars{{"UUID",     Id}, |         Types::StringPairVec FormVars{{"UUID",     Link.id}, | ||||||
|                                       {"USERNAME", UInfo.email}, |                                       {"USERNAME", UInfo.email}, | ||||||
|                                       {"ACTION_LINK",MicroService::instance().GetUIURI()}}; |                                       {"ACTION_LINK",MicroService::instance().GetUIURI()}}; | ||||||
|         Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; |         Poco::File FormFile{Daemon()->AssetDir() + "/email_verification_success.html"}; | ||||||
|  |         StorageService()->CompleteAction(Link.id); | ||||||
|         SendHTMLFileBack(FormFile, FormVars); |         SendHTMLFileBack(FormFile, FormVars); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,11 +19,12 @@ namespace OpenWifi { | |||||||
|                                         Poco::Net::HTTPRequest::HTTP_OPTIONS}, |                                         Poco::Net::HTTPRequest::HTTP_OPTIONS}, | ||||||
|                                         Server, |                                         Server, | ||||||
|                                         Internal, |                                         Internal, | ||||||
|                                         false) {} |                                         false, | ||||||
|  |                                         true, RateLimit{.Interval=1000,.MaxCalls=10}) {} | ||||||
|         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; }; |         static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; }; | ||||||
|         void RequestResetPassword(std::string &Id); |         void RequestResetPassword(SecurityObjects::ActionLink &Link); | ||||||
|         void CompleteResetPassword(std::string &Id); |         void CompleteResetPassword(); | ||||||
|         void DoEmailVerification(std::string &Id); |         void DoEmailVerification(SecurityObjects::ActionLink &Link); | ||||||
|         void DoReturnA404(); |         void DoReturnA404(); | ||||||
|  |  | ||||||
|         void DoGet() final; |         void DoGet() final; | ||||||
|   | |||||||
| @@ -14,26 +14,42 @@ | |||||||
| #include "MFAServer.h" | #include "MFAServer.h" | ||||||
| #include "framework/RESTAPI_protocol.h" | #include "framework/RESTAPI_protocol.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.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; | ||||||
|             return UnAuthorized("Not authorized."); |         if (!IsAuthorized(Expired)) { | ||||||
|  |             if(Expired) | ||||||
|  |                 return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN); | ||||||
|  |             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("Ill-formed request. Please consult documentation."); |         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, "..."); | ||||||
|         if (Token == SessionToken_) { |         if (Token == SessionToken_) { | ||||||
| @@ -63,15 +79,31 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) { | ||||||
|             //  Send an email to the userId |             SecurityObjects::UserInfo UInfo1; | ||||||
|             Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); |             auto UserExists = StorageService()->GetUserByEmail(userId,UInfo1); | ||||||
|             SecurityObjects::UserInfoAndPolicy UInfo; |             if(UserExists) { | ||||||
|             if(AuthService::SendEmailToUser(userId,AuthService::FORGOT_PASSWORD)) |                 Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId)); | ||||||
|                 Logger_.information(Poco::format("Send password reset link to %s",userId)); |                 SecurityObjects::ActionLink NewLink; | ||||||
|             UInfo.webtoken.userMustChangePassword=true; |  | ||||||
|             Poco::JSON::Object ReturnObj; |                 NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD; | ||||||
|             UInfo.webtoken.to_json(ReturnObj); |                 NewLink.id = MicroService::CreateUUID(); | ||||||
|             return ReturnObject(ReturnObj); |                 NewLink.userId = UInfo1.Id; | ||||||
|  |                 NewLink.created = std::time(nullptr); | ||||||
|  |                 NewLink.expires = NewLink.created + (24*60*60); | ||||||
|  |                 StorageService()->CreateAction(NewLink); | ||||||
|  |  | ||||||
|  |                 Poco::JSON::Object ReturnObj; | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true; | ||||||
|  |                 UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                 return ReturnObject(ReturnObj); | ||||||
|  |             } else { | ||||||
|  |                 Poco::JSON::Object ReturnObj; | ||||||
|  |                 SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|  |                 UInfo.webtoken.userMustChangePassword = true; | ||||||
|  |                 UInfo.webtoken.to_json(ReturnObj); | ||||||
|  |                 return ReturnObject(ReturnObj); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) { | ||||||
| @@ -80,9 +112,8 @@ namespace OpenWifi { | |||||||
|                 auto uuid = Obj->get("uuid").toString(); |                 auto uuid = Obj->get("uuid").toString(); | ||||||
|                 if(MFAServer().ResendCode(uuid)) |                 if(MFAServer().ResendCode(uuid)) | ||||||
|                     return OK(); |                     return OK(); | ||||||
|                 return UnAuthorized("Unrecognized credentials (username/password)."); |  | ||||||
|             } |             } | ||||||
|             return UnAuthorized("Unrecognized credentials (username/password)."); |             return UnAuthorized(RESTAPI::Errors::InvalidCredentials); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { |         if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) { | ||||||
| @@ -95,29 +126,37 @@ namespace OpenWifi { | |||||||
|                     return ReturnObject(ReturnObj); |                     return ReturnObject(ReturnObj); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             return UnAuthorized("Unrecognized credentials (username/password)."); |             return UnAuthorized(RESTAPI::Errors::InvalidCredentials); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfoAndPolicy UInfo; |         SecurityObjects::UserInfoAndPolicy UInfo; | ||||||
|         auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo); |         bool Expired=false; | ||||||
|         if (Code==AuthService::SUCCESS) { |         auto Code=AuthService()->Authorize(userId, password, newPassword, UInfo, Expired); | ||||||
|  |         if (Code==SUCCESS) { | ||||||
|             Poco::JSON::Object ReturnObj; |             Poco::JSON::Object ReturnObj; | ||||||
|             if(AuthService()->RequiresMFA(UInfo)) { |             if(AuthService()->RequiresMFA(UInfo)) { | ||||||
|                 if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) { |                 if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) { | ||||||
|                     return ReturnObject(ReturnObj); |                     return ReturnObject(ReturnObj); | ||||||
|                 } |                 } | ||||||
|                 Logger_.warning("MFA Seems ot be broken. Please fix. Disabling MFA checking for now."); |                 Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now."); | ||||||
|             } |             } | ||||||
|             UInfo.webtoken.to_json(ReturnObj); |             UInfo.webtoken.to_json(ReturnObj); | ||||||
|             return ReturnObject(ReturnObj); |             return ReturnObject(ReturnObj); | ||||||
|         } else { |         } else { | ||||||
|  |  | ||||||
|             switch(Code) { |             switch(Code) { | ||||||
|                 case AuthService::INVALID_CREDENTIALS: return UnAuthorized("Unrecognized credentials (username/password)."); break; |                 case INVALID_CREDENTIALS: | ||||||
|                 case AuthService::PASSWORD_INVALID: return UnAuthorized("Invalid password."); break; |                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code); | ||||||
|                 case AuthService::PASSWORD_ALREADY_USED: return UnAuthorized("Password already used previously."); break; |                 case PASSWORD_INVALID: | ||||||
|                 case AuthService::USERNAME_PENDING_VERIFICATION: return UnAuthorized("User access pending email verification."); break; |                     return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code); | ||||||
|                 case AuthService::PASSWORD_CHANGE_REQUIRED: return UnAuthorized("Password change expected."); break; |                 case PASSWORD_ALREADY_USED: | ||||||
|                 default: return UnAuthorized("Unrecognized credentials (username/password)."); break; |                     return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code); | ||||||
|  |                 case USERNAME_PENDING_VERIFICATION: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code); | ||||||
|  |                 case PASSWORD_CHANGE_REQUIRED: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code); | ||||||
|  |                 default: | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break; | ||||||
|             } |             } | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -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) {} | 													  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; | ||||||
|   | |||||||
| @@ -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()) { | ||||||
| @@ -25,7 +33,9 @@ namespace OpenWifi { | |||||||
|         } else if(!StorageService()->GetUserById(Id,UInfo)) { |         } else if(!StorageService()->GetUserById(Id,UInfo)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::JSON::Object  UserInfoObject; |         Poco::JSON::Object  UserInfoObject; | ||||||
|  |         FilterCredentials(UInfo); | ||||||
|         UInfo.to_json(UserInfoObject); |         UInfo.to_json(UserInfoObject); | ||||||
|         ReturnObject(UserInfoObject); |         ReturnObject(UserInfoObject); | ||||||
|     } |     } | ||||||
| @@ -41,12 +51,20 @@ namespace OpenWifi { | |||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) { | ||||||
|  |             return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { |         if(!StorageService()->DeleteUser(UserInfo_.userinfo.email,Id)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(AuthService()->DeleteUserFromCache(UInfo.email)) |         if(AuthService()->DeleteUserFromCache(UInfo.email)) { | ||||||
|             ; |             // 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)); | ||||||
| @@ -59,49 +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); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Poco::toLowerInPlace(UInfo.email); |         if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) { | ||||||
|         if(!Utils::ValidEMailAddress(UInfo.email)) { |             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Poco::toLowerInPlace(NewUser.email); | ||||||
|  |         if(!Utils::ValidEMailAddress(NewUser.email)) { | ||||||
|             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); |             return BadRequest(RESTAPI::Errors::InvalidEmailAddress); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!UInfo.currentPassword.empty()) { |         if(!NewUser.currentPassword.empty()) { | ||||||
|             if(!AuthService()->ValidatePassword(UInfo.currentPassword)) { |             if(!AuthService()->ValidatePassword(NewUser.currentPassword)) { | ||||||
|                 return BadRequest(RESTAPI::Errors::InvalidPassword); |                 return BadRequest(RESTAPI::Errors::InvalidPassword); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(UInfo.name.empty()) |         if(NewUser.name.empty()) | ||||||
|             UInfo.name = UInfo.email; |             NewUser.name = NewUser.email; | ||||||
|  |  | ||||||
|         if(!StorageService()->CreateUser(UInfo.email,UInfo)) { |         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() { | ||||||
| @@ -115,6 +136,10 @@ namespace OpenWifi { | |||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) { | ||||||
|  |             return UnAuthorized("Insufficient access rights.", ACCESS_DENIED); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         SecurityObjects::UserInfo   NewUser; |         SecurityObjects::UserInfo   NewUser; | ||||||
|         auto RawObject = ParseStream(); |         auto RawObject = ParseStream(); | ||||||
|         if(!NewUser.from_json(RawObject)) { |         if(!NewUser.from_json(RawObject)) { | ||||||
| @@ -136,8 +161,19 @@ namespace OpenWifi { | |||||||
|         AssignIfPresent(RawObject,"suspended", Existing.suspended); |         AssignIfPresent(RawObject,"suspended", Existing.suspended); | ||||||
|         AssignIfPresent(RawObject,"blackListed", Existing.blackListed); |         AssignIfPresent(RawObject,"blackListed", Existing.blackListed); | ||||||
|  |  | ||||||
|         if(RawObject->has("userRole")) |         if(RawObject->has("userRole")) { | ||||||
|             Existing.userRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); |             auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString()); | ||||||
|  |             if(NewRole!=Existing.userRole) { | ||||||
|  |                 if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) { | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|  |                 } | ||||||
|  |                 if(Id==UserInfo_.userinfo.Id) { | ||||||
|  |                     return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED); | ||||||
|  |                 } | ||||||
|  |                 Existing.userRole = NewRole; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if(RawObject->has("notes")) { |         if(RawObject->has("notes")) { | ||||||
|             SecurityObjects::NoteInfoVec NIV; |             SecurityObjects::NoteInfoVec NIV; | ||||||
|             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); |             NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString()); | ||||||
| @@ -161,26 +197,34 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(RawObject->has("userTypeProprietaryInfo")) { |         if(RawObject->has("userTypeProprietaryInfo")) { | ||||||
|  |             bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled; | ||||||
|  |  | ||||||
|             Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; |             Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled; | ||||||
|             if(NewUser.userTypeProprietaryInfo.mfa.method=="sms") { |  | ||||||
|  |             auto PropInfo = RawObject->get("userTypeProprietaryInfo"); | ||||||
|  |             auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>(); | ||||||
|  |  | ||||||
|  |             if(PInfo->isArray("mobiles")) { | ||||||
|  |                 Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){ | ||||||
|  |                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) { | ||||||
|  |                 return BadRequest(RESTAPI::Errors::NeedMobileNumber); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             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; | ||||||
|                 auto MobileStruct = RawObject->get("userTypeProprietaryInfo"); |             } | ||||||
|                 auto Info = MobileStruct.extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|                 if(Info->isArray("mobiles")) { |             if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) { | ||||||
|                     Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles; |                 return BadRequest("Illegal MFA method"); | ||||||
|                 } |  | ||||||
|                 if(!NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){ |  | ||||||
|                     return BadRequest(RESTAPI::Errors::NeedMobileNumber); |  | ||||||
|                 } |  | ||||||
|                 if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mobiles.empty()) { |  | ||||||
|                     return BadRequest(RESTAPI::Errors::NeedMobileNumber); |  | ||||||
|                 } |  | ||||||
|             } else if(NewUser.userTypeProprietaryInfo.mfa.method=="email") { |  | ||||||
|                 Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method; |  | ||||||
|             } else { |  | ||||||
|                 if(NewUser.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) { |  | ||||||
|                     return BadRequest(RESTAPI::Errors::BadMFAMethod); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -188,6 +232,7 @@ namespace OpenWifi { | |||||||
|             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); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -16,11 +16,14 @@ namespace OpenWifi { | |||||||
|             Poco::JSON::Array ArrayObj; |             Poco::JSON::Array ArrayObj; | ||||||
|             Poco::JSON::Object Answer; |             Poco::JSON::Object Answer; | ||||||
|             if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) { |             if (StorageService()->GetUsers(QB_.Offset, QB_.Limit, Users)) { | ||||||
|                 for (const auto &i : Users) { |                 for (auto &i : Users) { | ||||||
|                     Poco::JSON::Object Obj; |                     Poco::JSON::Object Obj; | ||||||
|                     if (IdOnly) { |                     if (IdOnly) { | ||||||
|                         ArrayObj.add(i.Id); |                         ArrayObj.add(i.Id); | ||||||
|                     } else { |                     } else { | ||||||
|  |                         i.currentPassword.clear(); | ||||||
|  |                         i.lastPasswords.clear(); | ||||||
|  |                         i.oauthType.clear(); | ||||||
|                         i.to_json(Obj); |                         i.to_json(Obj); | ||||||
|                         ArrayObj.add(Obj); |                         ArrayObj.add(Obj); | ||||||
|                     } |                     } | ||||||
| @@ -38,6 +41,9 @@ namespace OpenWifi { | |||||||
|                     if (IdOnly) { |                     if (IdOnly) { | ||||||
|                         ArrayObj.add(UInfo.Id); |                         ArrayObj.add(UInfo.Id); | ||||||
|                     } else { |                     } else { | ||||||
|  |                         UInfo.currentPassword.clear(); | ||||||
|  |                         UInfo.lastPasswords.clear(); | ||||||
|  |                         UInfo.oauthType.clear(); | ||||||
|                         UInfo.to_json(Obj); |                         UInfo.to_json(Obj); | ||||||
|                         ArrayObj.add(Obj); |                         ArrayObj.add(Obj); | ||||||
|                     } |                     } | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ namespace OpenWifi::GWObjects { | |||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool Device::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool Device::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"serialNumber",SerialNumber); | 			field_from_json(Obj,"serialNumber",SerialNumber); | ||||||
| 			field_from_json(Obj,"deviceType",DeviceType); | 			field_from_json(Obj,"deviceType",DeviceType); | ||||||
| @@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"attachFile", AttachDate); | 		field_to_json(Obj,"attachFile", AttachDate); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"name",Name); | 			field_from_json(Obj,"name",Name); | ||||||
| 			field_from_json(Obj,"configuration",Configuration); | 			field_from_json(Obj,"configuration",Configuration); | ||||||
| @@ -166,7 +166,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"created", created); | 		field_to_json(Obj,"created", created); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"serialNumber",serialNumber); | 			field_from_json(Obj,"serialNumber",serialNumber); | ||||||
| 			field_from_json(Obj,"author",author); | 			field_from_json(Obj,"author",author); | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string DevicePassword; | 		std::string DevicePassword; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		void to_json_with_status(Poco::JSON::Object &Obj) const; | 		void to_json_with_status(Poco::JSON::Object &Obj) const; | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr Obj); | 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
| 		void Print() const; | 		void Print() const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -116,7 +116,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		uint64_t 	Created; | 		uint64_t 	Created; | ||||||
| 		uint64_t 	LastModified; | 		uint64_t 	LastModified; | ||||||
| 		void 		to_json(Poco::JSON::Object &Obj) const; | 		void 		to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		bool 		from_json(Poco::JSON::Object::Ptr Obj); | 		bool 		from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct CommandDetails { | 	struct CommandDetails { | ||||||
| @@ -147,7 +147,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string author; | 		std::string author; | ||||||
| 		uint64_t created; | 		uint64_t created; | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		bool from_json(Poco::JSON::Object::Ptr Obj); | 		bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct RttySessionDetails { | 	struct RttySessionDetails { | ||||||
|   | |||||||
| @@ -10,27 +10,30 @@ | |||||||
| #include "RESTAPI_ProvObjects.h" | #include "RESTAPI_ProvObjects.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  |  | ||||||
| namespace OpenWifi::ProvObjects { | namespace OpenWifi::ProvObjects { | ||||||
|  |  | ||||||
|     void ObjectInfo::to_json(Poco::JSON::Object &Obj) const { |     void ObjectInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj,"id",id); |         field_to_json(Obj,"id",id); | ||||||
|         RESTAPI_utils::field_to_json(Obj,"name",name); |         field_to_json(Obj,"name",name); | ||||||
|         RESTAPI_utils::field_to_json(Obj,"description",description); |         field_to_json(Obj,"description",description); | ||||||
|         RESTAPI_utils::field_to_json(Obj,"created",created); |         field_to_json(Obj,"created",created); | ||||||
|         RESTAPI_utils::field_to_json(Obj,"modified",modified); |         field_to_json(Obj,"modified",modified); | ||||||
|         RESTAPI_utils::field_to_json(Obj,"notes",notes); |         field_to_json(Obj,"notes",notes); | ||||||
|         RESTAPI_utils::field_to_json(Obj,"tags",tags); |         field_to_json(Obj,"tags",tags); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ObjectInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json(Obj,"id",id); |             field_from_json(Obj,"id",id); | ||||||
|             RESTAPI_utils::field_from_json(Obj,"name",name); |             field_from_json(Obj,"name",name); | ||||||
|             RESTAPI_utils::field_from_json(Obj,"description",description); |             field_from_json(Obj,"description",description); | ||||||
|             RESTAPI_utils::field_from_json(Obj,"created",created); |             field_from_json(Obj,"created",created); | ||||||
|             RESTAPI_utils::field_from_json(Obj,"modified",modified); |             field_from_json(Obj,"modified",modified); | ||||||
|             RESTAPI_utils::field_from_json(Obj,"notes",notes); |             field_from_json(Obj,"notes",notes); | ||||||
|             RESTAPI_utils::field_from_json(Obj,"tags",tags); |             field_from_json(Obj,"tags",tags); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -39,18 +42,18 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const { |     void ManagementPolicyEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json( Obj,"users",users); |         field_to_json( Obj,"users",users); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"resources",resources); |         field_to_json( Obj,"resources",resources); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"access",access); |         field_to_json( Obj,"access",access); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"policy",policy); |         field_to_json( Obj,"policy",policy); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ManagementPolicyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"users",users); |             field_from_json( Obj,"users",users); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"resources",resources); |             field_from_json( Obj,"resources",resources); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"access",access); |             field_from_json( Obj,"access",access); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"policy",policy); |             field_from_json( Obj,"policy",policy); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -60,17 +63,17 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const { |     void ManagementPolicy::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "entries", entries); |         field_to_json(Obj, "entries", entries); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "inUse", inUse); |         field_to_json(Obj, "inUse", inUse); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "entity", entity); |         field_to_json(Obj, "entity", entity); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ManagementPolicy::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json(Obj, "entries", entries); |             field_from_json(Obj, "entries", entries); | ||||||
|             RESTAPI_utils::field_from_json(Obj, "inUse", inUse); |             field_from_json(Obj, "inUse", inUse); | ||||||
|             RESTAPI_utils::field_from_json(Obj, "entity", entity); |             field_from_json(Obj, "entity", entity); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -80,31 +83,31 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void Entity::to_json(Poco::JSON::Object &Obj) const { |     void Entity::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"parent",parent); |         field_to_json( Obj,"parent",parent); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"venues",venues); |         field_to_json( Obj,"venues",venues); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"children",children); |         field_to_json( Obj,"children",children); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"contacts",contacts); |         field_to_json( Obj,"contacts",contacts); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"locations",locations); |         field_to_json( Obj,"locations",locations); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"devices",devices); |         field_to_json( Obj,"devices",devices); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"rrm",rrm); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP); |         field_to_json( Obj,"sourceIP",sourceIP); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"parent",parent); |             field_from_json( Obj,"parent",parent); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"venues",venues); |             field_from_json( Obj,"venues",venues); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"children",children); |             field_from_json( Obj,"children",children); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"contacts",contacts); |             field_from_json( Obj,"contacts",contacts); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"locations",locations); |             field_from_json( Obj,"locations",locations); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"devices",devices); |             field_from_json( Obj,"devices",devices); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"rrm",rrm); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP); |             field_from_json( Obj,"sourceIP",sourceIP); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -113,14 +116,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const { |     void DiGraphEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json( Obj,"parent",parent); |         field_to_json( Obj,"parent",parent); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"child",child); |         field_to_json( Obj,"child",child); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool DiGraphEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"parent",parent); |             field_from_json( Obj,"parent",parent); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"child",child); |             field_from_json( Obj,"child",child); | ||||||
|             return true; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |  | ||||||
| @@ -130,37 +133,37 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void Venue::to_json(Poco::JSON::Object &Obj) const { |     void Venue::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"parent",parent); |         field_to_json( Obj,"parent",parent); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); |         field_to_json( Obj,"entity",entity); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"children",children); |         field_to_json( Obj,"children",children); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"devices",devices); |         field_to_json( Obj,"devices",devices); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"topology",topology); |         field_to_json( Obj,"topology",topology); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"parent",parent); |         field_to_json( Obj,"parent",parent); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"design",design); |         field_to_json( Obj,"design",design); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"contact",contact); |         field_to_json( Obj,"contact",contact); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"location",location); |         field_to_json( Obj,"location",location); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"rrm",rrm); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"sourceIP",sourceIP); |         field_to_json( Obj,"sourceIP",sourceIP); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"parent",parent); |             field_from_json( Obj,"parent",parent); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"children",children); |             field_from_json( Obj,"children",children); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"devices",devices); |             field_from_json( Obj,"devices",devices); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"topology",topology); |             field_from_json( Obj,"topology",topology); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"parent",parent); |             field_from_json( Obj,"parent",parent); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"design",design); |             field_from_json( Obj,"design",design); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"contact",contact); |             field_from_json( Obj,"contact",contact); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"location",location); |             field_from_json( Obj,"location",location); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"rrm",rrm); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"sourceIP",sourceIP); |             field_from_json( Obj,"sourceIP",sourceIP); | ||||||
|             return true; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |  | ||||||
| @@ -169,16 +172,16 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { |     void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json( Obj,"id",id); |         field_to_json( Obj,"id",id); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"entity",loginId); |         field_to_json( Obj,"entity",loginId); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"children",userType); |         field_to_json( Obj,"children",userType); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool UserInfoDigest::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"id",id); |             field_from_json( Obj,"id",id); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",loginId); |             field_from_json( Obj,"entity",loginId); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"children",userType); |             field_from_json( Obj,"children",userType); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|         } |         } | ||||||
| @@ -187,17 +190,17 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void ManagementRole::to_json(Poco::JSON::Object &Obj) const { |     void ManagementRole::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"users",users); |         field_to_json( Obj,"users",users); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); |         field_to_json( Obj,"entity",entity); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"users",users); |             field_from_json( Obj,"users",users); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|         } |         } | ||||||
| @@ -206,39 +209,39 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void Location::to_json(Poco::JSON::Object &Obj) const { |     void Location::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type)); |         field_to_json( Obj,"type",OpenWifi::ProvObjects::to_string(type)); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"buildingName",buildingName); |         field_to_json( Obj,"buildingName",buildingName); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"addressLines",addressLines); |         field_to_json( Obj,"addressLines",addressLines); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"city",city); |         field_to_json( Obj,"city",city); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"state",state); |         field_to_json( Obj,"state",state); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"postal",postal); |         field_to_json( Obj,"postal",postal); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"country",country); |         field_to_json( Obj,"country",country); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"phones",phones); |         field_to_json( Obj,"phones",phones); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles); |         field_to_json( Obj,"mobiles",mobiles); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"geoCode",geoCode); |         field_to_json( Obj,"geoCode",geoCode); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"inUse",inUse); |         field_to_json( Obj,"inUse",inUse); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); |         field_to_json( Obj,"entity",entity); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             std::string tmp_type; |             std::string tmp_type; | ||||||
|             RESTAPI_utils::field_from_json( Obj,"type", tmp_type); |             field_from_json( Obj,"type", tmp_type); | ||||||
|             type = location_from_string(tmp_type); |             type = location_from_string(tmp_type); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"buildingName",buildingName); |             field_from_json( Obj,"buildingName",buildingName); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"addressLines",addressLines); |             field_from_json( Obj,"addressLines",addressLines); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"city",city); |             field_from_json( Obj,"city",city); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"state",state); |             field_from_json( Obj,"state",state); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"postal",postal); |             field_from_json( Obj,"postal",postal); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"country",country); |             field_from_json( Obj,"country",country); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"phones",phones); |             field_from_json( Obj,"phones",phones); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles); |             field_from_json( Obj,"mobiles",mobiles); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode); |             field_from_json( Obj,"geoCode",geoCode); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"inUse",inUse); |             field_from_json( Obj,"inUse",inUse); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             return true; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |  | ||||||
| @@ -248,43 +251,43 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void Contact::to_json(Poco::JSON::Object &Obj) const { |     void Contact::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"type", to_string(type)); |         field_to_json( Obj,"type", to_string(type)); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"title",title); |         field_to_json( Obj,"title",title); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"salutation",salutation); |         field_to_json( Obj,"salutation",salutation); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"firstname",firstname); |         field_to_json( Obj,"firstname",firstname); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"lastname",lastname); |         field_to_json( Obj,"lastname",lastname); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"initials",initials); |         field_to_json( Obj,"initials",initials); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"visual",visual); |         field_to_json( Obj,"visual",visual); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"mobiles",mobiles); |         field_to_json( Obj,"mobiles",mobiles); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"phones",phones); |         field_to_json( Obj,"phones",phones); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"primaryEmail",primaryEmail); |         field_to_json( Obj,"primaryEmail",primaryEmail); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"secondaryEmail",secondaryEmail); |         field_to_json( Obj,"secondaryEmail",secondaryEmail); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"accessPIN",accessPIN); |         field_to_json( Obj,"accessPIN",accessPIN); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"inUse",inUse); |         field_to_json( Obj,"inUse",inUse); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"entity",entity); |         field_to_json( Obj,"entity",entity); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool Contact::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             std::string tmp_type; |             std::string tmp_type; | ||||||
|             RESTAPI_utils::field_from_json( Obj,"type", tmp_type); |             field_from_json( Obj,"type", tmp_type); | ||||||
|             type = contact_from_string(tmp_type); |             type = contact_from_string(tmp_type); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"title",title); |             field_from_json( Obj,"title",title); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"salutation",salutation); |             field_from_json( Obj,"salutation",salutation); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"firstname",firstname); |             field_from_json( Obj,"firstname",firstname); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"lastname",lastname); |             field_from_json( Obj,"lastname",lastname); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"initials",initials); |             field_from_json( Obj,"initials",initials); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"visual",visual); |             field_from_json( Obj,"visual",visual); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"mobiles",mobiles); |             field_from_json( Obj,"mobiles",mobiles); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"phones",phones); |             field_from_json( Obj,"phones",phones); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"primaryEmail",primaryEmail); |             field_from_json( Obj,"primaryEmail",primaryEmail); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"secondaryEmail",secondaryEmail); |             field_from_json( Obj,"secondaryEmail",secondaryEmail); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"accessPIN",accessPIN); |             field_from_json( Obj,"accessPIN",accessPIN); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"inUse",inUse); |             field_from_json( Obj,"inUse",inUse); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             return true; |             return true; | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|  |  | ||||||
| @@ -294,35 +297,35 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void InventoryTag::to_json(Poco::JSON::Object &Obj) const { |     void InventoryTag::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "serialNumber", serialNumber); |         field_to_json(Obj, "serialNumber", serialNumber); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "venue", venue); |         field_to_json(Obj, "venue", venue); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "entity", entity); |         field_to_json(Obj, "entity", entity); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "subscriber", subscriber); |         field_to_json(Obj, "subscriber", subscriber); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "deviceType", deviceType); |         field_to_json(Obj, "deviceType", deviceType); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "qrCode", qrCode); |         field_to_json(Obj, "qrCode", qrCode); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "geoCode", geoCode); |         field_to_json(Obj, "geoCode", geoCode); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "location", location); |         field_to_json(Obj, "location", location); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "contact", contact); |         field_to_json(Obj, "contact", contact); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"deviceConfiguration",deviceConfiguration); |         field_to_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"rrm",rrm); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"serialNumber",serialNumber); |             field_from_json( Obj,"serialNumber",serialNumber); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"venue",venue); |             field_from_json( Obj,"venue",venue); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entity",entity); |             field_from_json( Obj,"entity",entity); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"subscriber",subscriber); |             field_from_json( Obj,"subscriber",subscriber); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"deviceType",deviceType); |             field_from_json( Obj,"deviceType",deviceType); | ||||||
|             RESTAPI_utils::field_from_json(Obj, "qrCode", qrCode); |             field_from_json(Obj, "qrCode", qrCode); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"geoCode",geoCode); |             field_from_json( Obj,"geoCode",geoCode); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"location",location); |             field_from_json( Obj,"location",location); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"contact",contact); |             field_from_json( Obj,"contact",contact); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"deviceConfiguration",deviceConfiguration); |             field_from_json( Obj,"deviceConfiguration",deviceConfiguration); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"rrm",rrm); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -331,18 +334,18 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { |     void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json( Obj,"name", name); |         field_to_json( Obj,"name", name); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"description", description); |         field_to_json( Obj,"description", description); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"weight", weight); |         field_to_json( Obj,"weight", weight); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"configuration", configuration); |         field_to_json( Obj,"configuration", configuration); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool DeviceConfigurationElement::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"name",name); |             field_from_json( Obj,"name",name); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"description",description); |             field_from_json( Obj,"description",description); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"weight",weight); |             field_from_json( Obj,"weight",weight); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"configuration",configuration); |             field_from_json( Obj,"configuration",configuration); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -352,27 +355,27 @@ namespace OpenWifi::ProvObjects { | |||||||
|  |  | ||||||
|     void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const { |     void DeviceConfiguration::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         info.to_json(Obj); |         info.to_json(Obj); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"managementPolicy",managementPolicy); |         field_to_json( Obj,"managementPolicy",managementPolicy); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"deviceTypes",deviceTypes); |         field_to_json( Obj,"deviceTypes",deviceTypes); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"configuration",configuration); |         field_to_json( Obj,"configuration",configuration); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"inUse",inUse); |         field_to_json( Obj,"inUse",inUse); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"variables",variables); |         field_to_json( Obj,"variables",variables); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"rrm",rrm); |         field_to_json( Obj,"rrm",rrm); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); |         field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); | ||||||
|         RESTAPI_utils::field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); |         field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             info.from_json(Obj); |             info.from_json(Obj); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"managementPolicy",managementPolicy); |             field_from_json( Obj,"managementPolicy",managementPolicy); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"deviceTypes",deviceTypes); |             field_from_json( Obj,"deviceTypes",deviceTypes); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"configuration",configuration); |             field_from_json( Obj,"configuration",configuration); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"inUse",inUse); |             field_from_json( Obj,"inUse",inUse); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"variables",variables); |             field_from_json( Obj,"variables",variables); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"rrm",rrm); |             field_from_json( Obj,"rrm",rrm); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); |             field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); |             field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -381,8 +384,8 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Report::to_json(Poco::JSON::Object &Obj) const { |     void Report::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj, "snapshot", snapShot); |         field_to_json(Obj, "snapshot", snapShot); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "devices", tenants); |         field_to_json(Obj, "devices", tenants); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     void Report::reset() { |     void Report::reset() { | ||||||
| @@ -390,16 +393,16 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const { |     void ExpandedUseEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj, "uuid", uuid); |         field_to_json(Obj, "uuid", uuid); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "name", name); |         field_to_json(Obj, "name", name); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "description", description); |         field_to_json(Obj, "description", description); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ExpandedUseEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"uuid",uuid); |             field_from_json( Obj,"uuid",uuid); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"name",name); |             field_from_json( Obj,"name",name); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"description",description); |             field_from_json( Obj,"description",description); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -408,14 +411,14 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const { |     void ExpandedUseEntryList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj, "type", type); |         field_to_json(Obj, "type", type); | ||||||
|         RESTAPI_utils::field_to_json(Obj, "entries", entries); |         field_to_json(Obj, "entries", entries); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ExpandedUseEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"type",type); |             field_from_json( Obj,"type",type); | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entries",entries); |             field_from_json( Obj,"entries",entries); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -424,12 +427,94 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const { |     void ExpandedUseEntryMapList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         RESTAPI_utils::field_to_json(Obj, "entries", entries); |         field_to_json(Obj, "entries", entries); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool ExpandedUseEntryMapList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             RESTAPI_utils::field_from_json( Obj,"entries",entries); |             field_from_json( Obj,"entries",entries); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void UserList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "list", list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool UserList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "list", list); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void ObjectACL::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "users", users); | ||||||
|  |         field_to_json(Obj, "access", access); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "users", users); | ||||||
|  |             field_from_json(Obj, "access", access); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     void ObjectACLList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "list", list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "list", list); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Map::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         info.to_json(Obj); | ||||||
|  |         field_to_json( Obj,"data",data); | ||||||
|  |         field_to_json( Obj,"entity",entity); | ||||||
|  |         field_to_json( Obj,"creator",creator); | ||||||
|  |         field_to_json( Obj,"visibility",visibility); | ||||||
|  |         field_to_json( Obj,"access",access); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             info.from_json(Obj); | ||||||
|  |             field_from_json( Obj,"data",data); | ||||||
|  |             field_from_json( Obj,"entity",entity); | ||||||
|  |             field_from_json( Obj,"creator",creator); | ||||||
|  |             field_from_json( Obj,"visibility",visibility); | ||||||
|  |             field_from_json( Obj,"access",access); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void MapList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json( Obj,"list",list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool MapList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json( Obj,"list",list); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
| @@ -438,13 +523,47 @@ namespace OpenWifi::ProvObjects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { |     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||||
|  |         uint64_t Now = std::time(nullptr); | ||||||
|         if(O->has("name")) |         if(O->has("name")) | ||||||
|             I.name = O->get("name").toString(); |             I.name = O->get("name").toString(); | ||||||
|         if(O->has("description")) |  | ||||||
|  |         if(I.name.empty()) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|  |        if(O->has("description")) | ||||||
|             I.description = O->get("description").toString(); |             I.description = O->get("description").toString(); | ||||||
|         SecurityObjects::MergeNotes(O,U,I.notes); |         SecurityObjects::MergeNotes(O,U,I.notes); | ||||||
|         I.modified = std::time(nullptr); |         SecurityObjects::NoteInfoVec N; | ||||||
|  |         for(auto &i:I.notes) { | ||||||
|  |             if(i.note.empty()) | ||||||
|  |                 continue; | ||||||
|  |             N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note}); | ||||||
|  |         } | ||||||
|  |         I.modified = Now; | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { | ||||||
|  |         uint64_t Now = std::time(nullptr); | ||||||
|  |         if(O->has("name")) | ||||||
|  |             I.name = O->get("name").toString(); | ||||||
|  |  | ||||||
|  |         if(I.name.empty()) | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|  |         if(O->has("description")) | ||||||
|  |             I.description = O->get("description").toString(); | ||||||
|  |  | ||||||
|  |         SecurityObjects::NoteInfoVec N; | ||||||
|  |         for(auto &i:I.notes) { | ||||||
|  |             if(i.note.empty()) | ||||||
|  |                 continue; | ||||||
|  |             N.push_back(SecurityObjects::NoteInfo{.created=Now,.createdBy=U.email,.note=i.note}); | ||||||
|  |         } | ||||||
|  |         I.notes = N; | ||||||
|  |         I.modified = I.created = Now; | ||||||
|  |         I.id = MicroService::CreateUUID(); | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -15,6 +15,13 @@ | |||||||
|  |  | ||||||
| namespace OpenWifi::ProvObjects { | namespace OpenWifi::ProvObjects { | ||||||
|  |  | ||||||
|  |     enum FIRMWARE_UPGRADE_RULES { | ||||||
|  |         dont_upgrade, | ||||||
|  |         upgrade_inherit, | ||||||
|  |         upgrade_release_only, | ||||||
|  |         upgrade_latest | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     struct ObjectInfo { |     struct ObjectInfo { | ||||||
|         Types::UUID_t   id; |         Types::UUID_t   id; | ||||||
|         std::string     name; |         std::string     name; | ||||||
| @@ -317,7 +324,50 @@ namespace OpenWifi::ProvObjects { | |||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     struct UserList { | ||||||
|  |         std::vector<std::string>    list; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct ObjectACL { | ||||||
|  |         UserList        users; | ||||||
|  |         std::string     access; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct ObjectACLList { | ||||||
|  |         std::vector<ObjectACL>  list; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct Map { | ||||||
|  |         ObjectInfo          info; | ||||||
|  |         std::string         data; | ||||||
|  |         std::string         entity; | ||||||
|  |         std::string         creator; | ||||||
|  |         std::string         visibility; | ||||||
|  |         ObjectACLList       access; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct MapList { | ||||||
|  |         std::vector<Map>    list; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); |     bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
|  |     bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -138,7 +138,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj,"primary", primary); | 	    field_to_json(Obj,"primary", primary); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 	    try { | 	    try { | ||||||
| 	        field_from_json(Obj,"number",number); | 	        field_from_json(Obj,"number",number); | ||||||
| 	        field_from_json(Obj,"verified",verified); | 	        field_from_json(Obj,"verified",verified); | ||||||
| @@ -155,7 +155,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj,"method", method); | 	    field_to_json(Obj,"method", method); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 	    try { | 	    try { | ||||||
| 	        field_from_json(Obj,"enabled",enabled); | 	        field_from_json(Obj,"enabled",enabled); | ||||||
| 	        field_from_json(Obj,"method",method); | 	        field_from_json(Obj,"method",method); | ||||||
| @@ -171,7 +171,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    field_to_json(Obj, "mfa", mfa); | 	    field_to_json(Obj, "mfa", mfa); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 	    try { | 	    try { | ||||||
| 	        field_from_json(Obj,"mobiles",mobiles); | 	        field_from_json(Obj,"mobiles",mobiles); | ||||||
| 	        field_from_json(Obj,"mfa",mfa); | 	        field_from_json(Obj,"mfa",mfa); | ||||||
| @@ -189,7 +189,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
|         field_to_json(Obj, "method", method); |         field_to_json(Obj, "method", method); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr Obj) { |     bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 	    try { | 	    try { | ||||||
| 	        field_from_json(Obj,"uuid",uuid); | 	        field_from_json(Obj,"uuid",uuid); | ||||||
| 	        field_from_json(Obj,"question",question); | 	        field_from_json(Obj,"question",question); | ||||||
| @@ -208,7 +208,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr Obj) { |     bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json(Obj,"uuid",uuid); |             field_from_json(Obj,"uuid",uuid); | ||||||
|             field_from_json(Obj,"answer",answer); |             field_from_json(Obj,"answer",answer); | ||||||
| @@ -387,11 +387,12 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj,"note", note); | 		field_to_json(Obj,"note", note); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool NoteInfo::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"created",created); | 			field_from_json(Obj,"created",created); | ||||||
| 			field_from_json(Obj,"createdBy",createdBy); | 			field_from_json(Obj,"createdBy",createdBy); | ||||||
| 			field_from_json(Obj,"note",note); | 			field_from_json(Obj,"note",note); | ||||||
|  | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| @@ -428,10 +429,11 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); | 		field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool ProfileAction::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"resource",resource); | 			field_from_json(Obj,"resource",resource); | ||||||
| 			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); | 			field_from_json<ResourceAccessType>(Obj,"access",access,ResourceAccessTypeFromString ); | ||||||
|  | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| @@ -447,7 +449,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj,"notes", notes); | 		field_to_json(Obj,"notes", notes); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"id",id); | 			field_from_json(Obj,"id",id); | ||||||
| 			field_from_json(Obj,"name",name); | 			field_from_json(Obj,"name",name); | ||||||
| @@ -455,6 +457,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 			field_from_json(Obj,"policy",policy); | 			field_from_json(Obj,"policy",policy); | ||||||
| 			field_from_json(Obj,"role",role); | 			field_from_json(Obj,"role",role); | ||||||
| 			field_from_json(Obj,"notes",notes); | 			field_from_json(Obj,"notes",notes); | ||||||
|  | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| @@ -465,13 +468,51 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		field_to_json(Obj, "profiles", profiles); | 		field_to_json(Obj, "profiles", profiles); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr Obj) { | 	bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"profiles",profiles); | 			field_from_json(Obj,"profiles",profiles); | ||||||
|  | 			return true; | ||||||
| 		} catch(...) { | 		} catch(...) { | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |     void ActionLink::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  | 	    field_to_json(Obj,"id",id); | ||||||
|  | 	    field_to_json(Obj,"action",action); | ||||||
|  | 	    field_to_json(Obj,"userId",userId); | ||||||
|  | 	    field_to_json(Obj,"actionTemplate",actionTemplate); | ||||||
|  | 	    field_to_json(Obj,"variables",variables); | ||||||
|  | 	    field_to_json(Obj,"locale",locale); | ||||||
|  | 	    field_to_json(Obj,"message",message); | ||||||
|  | 	    field_to_json(Obj,"sent",sent); | ||||||
|  | 	    field_to_json(Obj,"created",created); | ||||||
|  | 	    field_to_json(Obj,"expires",expires); | ||||||
|  | 	    field_to_json(Obj,"completed",completed); | ||||||
|  | 	    field_to_json(Obj,"canceled",canceled); | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |     bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) { | ||||||
|  | 	    try { | ||||||
|  | 	        field_from_json(Obj,"id",id); | ||||||
|  | 	        field_from_json(Obj,"action",action); | ||||||
|  | 	        field_from_json(Obj,"userId",userId); | ||||||
|  | 	        field_from_json(Obj,"actionTemplate",actionTemplate); | ||||||
|  | 	        field_from_json(Obj,"variables",variables); | ||||||
|  | 	        field_from_json(Obj,"locale",locale); | ||||||
|  | 	        field_from_json(Obj,"message",message); | ||||||
|  | 	        field_from_json(Obj,"sent",sent); | ||||||
|  | 	        field_from_json(Obj,"created",created); | ||||||
|  | 	        field_from_json(Obj,"expires",expires); | ||||||
|  | 	        field_from_json(Obj,"completed",completed); | ||||||
|  | 	        field_from_json(Obj,"canceled",canceled); | ||||||
|  | 	        return true; | ||||||
|  | 	    } catch(...) { | ||||||
|  |  | ||||||
|  | 	    } | ||||||
|  | 	    return false; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| #define UCENTRAL_RESTAPI_SECURITYOBJECTS_H | #define UCENTRAL_RESTAPI_SECURITYOBJECTS_H | ||||||
|  |  | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "../framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
|  |  | ||||||
| namespace OpenWifi::SecurityObjects { | namespace OpenWifi::SecurityObjects { | ||||||
|  |  | ||||||
| @@ -53,25 +53,25 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		std::string createdBy; | 		std::string createdBy; | ||||||
| 		std::string note; | 		std::string note; | ||||||
| 		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); | ||||||
| 	}; | 	}; | ||||||
| 	typedef std::vector<NoteInfo>	NoteInfoVec; | 	typedef std::vector<NoteInfo>	NoteInfoVec; | ||||||
|  |  | ||||||
| 	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; | ||||||
| 	    bool from_json(Poco::JSON::Object::Ptr Obj); | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct UserLoginLoginExtensions { | 	struct UserLoginLoginExtensions { | ||||||
| @@ -79,17 +79,17 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 	    struct MfaAuthInfo mfa; | 	    struct MfaAuthInfo mfa; | ||||||
|  |  | ||||||
| 	    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 MFAChallengeRequest { | 	struct MFAChallengeRequest { | ||||||
| 	    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); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|     struct MFAChallengeResponse { |     struct MFAChallengeResponse { | ||||||
| @@ -97,7 +97,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
|         std::string answer; |         std::string answer; | ||||||
|  |  | ||||||
|         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 UserInfo { | 	struct UserInfo { | ||||||
| @@ -200,7 +200,7 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		std::string resource; | 		std::string resource; | ||||||
| 		ResourceAccessType access; | 		ResourceAccessType access; | ||||||
| 		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); | ||||||
| 	}; | 	}; | ||||||
| 	typedef std::vector<ProfileAction>	ProfileActionVec; | 	typedef std::vector<ProfileAction>	ProfileActionVec; | ||||||
|  |  | ||||||
| @@ -212,14 +212,37 @@ namespace OpenWifi::SecurityObjects { | |||||||
| 		std::string role; | 		std::string role; | ||||||
| 		NoteInfoVec notes; | 		NoteInfoVec notes; | ||||||
| 		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); | ||||||
| 	}; | 	}; | ||||||
| 	typedef std::vector<SecurityProfile> SecurityProfileVec; | 	typedef std::vector<SecurityProfile> SecurityProfileVec; | ||||||
|  |  | ||||||
| 	struct SecurityProfileList { | 	struct SecurityProfileList { | ||||||
| 		SecurityProfileVec profiles; | 		SecurityProfileVec profiles; | ||||||
| 		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); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	enum LinkActions { | ||||||
|  | 	    FORGOT_PASSWORD=1, | ||||||
|  | 	    VERIFY_EMAIL | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	struct ActionLink { | ||||||
|  | 	    std::string         id; | ||||||
|  | 	    uint64_t            action; | ||||||
|  | 	    std::string         userId; | ||||||
|  | 	    std::string         actionTemplate; | ||||||
|  | 	    Types::StringPairVec variables; | ||||||
|  | 	    std::string         locale; | ||||||
|  | 	    std::string         message; | ||||||
|  | 	    uint64_t            sent=0; | ||||||
|  | 	    uint64_t            created=std::time(nullptr); | ||||||
|  | 	    uint64_t            expires=0; | ||||||
|  | 	    uint64_t            completed=0; | ||||||
|  | 	    uint64_t            canceled=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 	    bool from_json(Poco::JSON::Object::Ptr &Obj); | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,16 +14,18 @@ | |||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class SMSSender * SMSSender::instance_ = nullptr; |  | ||||||
|  |  | ||||||
|     int SMSSender::Start() { |     int SMSSender::Start() { | ||||||
|         Provider_ = MicroService::instance().ConfigGetString("sms.provider","aws"); |         Enabled_ = MicroService::instance().ConfigGetBool("smssender.enabled",false); | ||||||
|         if(Provider_=="aws") { |         if(Enabled_) { | ||||||
|             ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); |             Provider_ = MicroService::instance().ConfigGetString("smssender.provider","aws"); | ||||||
|         } else if(Provider_=="twilio") { |             if(Provider_=="aws") { | ||||||
|             ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); |                 ProviderImpl_ = std::make_unique<SMS_provider_aws>(Logger_); | ||||||
|  |             } else if(Provider_=="twilio") { | ||||||
|  |                 ProviderImpl_ = std::make_unique<SMS_provider_twilio>(Logger_); | ||||||
|  |             } | ||||||
|  |             Enabled_ = ProviderImpl_->Initialize(); | ||||||
|         } |         } | ||||||
|         Enabled_ = ProviderImpl_->Initialize(); |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,16 +18,14 @@ namespace OpenWifi { | |||||||
|         std::string Number; |         std::string Number; | ||||||
|         std::string Code; |         std::string Code; | ||||||
|         std::string UserName; |         std::string UserName; | ||||||
|         uint64_t    Created; |         uint64_t    Created = std::time(nullptr); | ||||||
|         bool        Validated=false; |         bool        Validated = false; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class SMSSender : public SubSystemServer { |     class SMSSender : public SubSystemServer { | ||||||
|         public: |         public: | ||||||
|             static SMSSender *instance() { |             static SMSSender *instance() { | ||||||
|                 if (instance_ == nullptr) { |                 static auto *instance_ = new SMSSender; | ||||||
|                     instance_ = new SMSSender; |  | ||||||
|                 } |  | ||||||
|                 return instance_; |                 return instance_; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -39,9 +37,8 @@ namespace OpenWifi { | |||||||
|             bool IsNumberValid(const std::string &Number, const std::string &UserName); |             bool IsNumberValid(const std::string &Number, const std::string &UserName); | ||||||
|             [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message); |             [[nodiscard]] bool Send(const std::string &PhoneNumber, const std::string &Message); | ||||||
|         private: |         private: | ||||||
|             static SMSSender * instance_; |             std::string                             Provider_; | ||||||
|             std::string         Provider_; |             bool                                    Enabled_=false; | ||||||
|             bool                Enabled_=false; |  | ||||||
|             std::vector<SMSValidationCacheEntry>    Cache_; |             std::vector<SMSValidationCacheEntry>    Cache_; | ||||||
|             std::unique_ptr<SMS_provider>           ProviderImpl_; |             std::unique_ptr<SMS_provider>           ProviderImpl_; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,18 +43,24 @@ namespace OpenWifi { | |||||||
|         if(!Running_) |         if(!Running_) | ||||||
|             return false; |             return false; | ||||||
|  |  | ||||||
|         Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_); |         try { | ||||||
|         Aws::SNS::Model::PublishRequest psms_req; |             Aws::SNS::SNSClient sns(AwsCreds_,AwsConfig_); | ||||||
|         psms_req.SetMessage(Message.c_str()); |             Aws::SNS::Model::PublishRequest psms_req; | ||||||
|         psms_req.SetPhoneNumber(PhoneNumber.c_str()); |             psms_req.SetMessage(Message.c_str()); | ||||||
|  |             psms_req.SetPhoneNumber(PhoneNumber.c_str()); | ||||||
|  |  | ||||||
|  |             auto psms_out = sns.Publish(psms_req); | ||||||
|  |             if (psms_out.IsSuccess()) { | ||||||
|  |                 Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber)); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             std::string ErrMsg{psms_out.GetError().GetMessage()}; | ||||||
|  |             Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); | ||||||
|  |             return false; | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|         auto psms_out = sns.Publish(psms_req); |  | ||||||
|         if (psms_out.IsSuccess()) { |  | ||||||
|             Logger_.debug(Poco::format("SMS sent to %s",PhoneNumber)); |  | ||||||
|             return true; |  | ||||||
|         } |         } | ||||||
|         std::string ErrMsg{psms_out.GetError().GetMessage()}; |         Logger_.debug(Poco::format("SMS NOT sent to %s: failure in SMS service",PhoneNumber)); | ||||||
|         Logger_.debug(Poco::format("SMS NOT sent to %s: %s",PhoneNumber, ErrMsg)); |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,29 +9,30 @@ | |||||||
| #include "Poco/Net/SMTPClientSession.h" | #include "Poco/Net/SMTPClientSession.h" | ||||||
| #include "Poco/Net/SecureSMTPClientSession.h" | #include "Poco/Net/SecureSMTPClientSession.h" | ||||||
| #include "Poco/Net/StringPartSource.h" | #include "Poco/Net/StringPartSource.h" | ||||||
| #include "Poco/Path.h" |  | ||||||
| #include "Poco/Exception.h" | #include "Poco/Exception.h" | ||||||
| #include "Poco/Net/SSLManager.h" | #include "Poco/Net/SSLManager.h" | ||||||
| #include "Poco/Net/Context.h" | #include "Poco/Net/Context.h" | ||||||
| #include "Poco/Net/InvalidCertificateHandler.h" |  | ||||||
| #include "Poco/Net/AcceptCertificateHandler.h" |  | ||||||
|  |  | ||||||
| #include "SMTPMailerService.h" | #include "SMTPMailerService.h" | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  | #include "AuthService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     class SMTPMailerService * SMTPMailerService::instance_ = nullptr; |  | ||||||
|  |  | ||||||
|     void SMTPMailerService::LoadMyConfig() { |     void SMTPMailerService::LoadMyConfig() { | ||||||
|         MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname"); |         Enabled_ = MicroService::instance().ConfigGetBool("mailer.enabled",false); | ||||||
|         SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username"); |         if(Enabled_) { | ||||||
|         SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); |             MailHost_ = MicroService::instance().ConfigGetString("mailer.hostname"); | ||||||
|         Sender_ = MicroService::instance().ConfigGetString("mailer.sender"); |             SenderLoginUserName_ = MicroService::instance().ConfigGetString("mailer.username"); | ||||||
|         LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); |             SenderLoginPassword_ = MicroService::instance().ConfigGetString("mailer.password"); | ||||||
|         MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); |             Sender_ = MicroService::instance().ConfigGetString("mailer.sender"); | ||||||
|         TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); |             LoginMethod_ = MicroService::instance().ConfigGetString("mailer.loginmethod"); | ||||||
|         Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); |             MailHostPort_ = (int) MicroService::instance().ConfigGetInt("mailer.port"); | ||||||
|  |             TemplateDir_ = MicroService::instance().ConfigPath("mailer.templates", MicroService::instance().DataDir()); | ||||||
|  |             MailRetry_ = (int) MicroService::instance().ConfigGetInt("mailer.retry",2*60); | ||||||
|  |             MailAbandon_ = (int) MicroService::instance().ConfigGetInt("mailer.abandon",2*60*60); | ||||||
|  |             Enabled_ = (!MailHost_.empty() && !SenderLoginPassword_.empty() && !SenderLoginUserName_.empty()); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     int SMTPMailerService::Start() { |     int SMTPMailerService::Start() { | ||||||
| @@ -54,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)));}); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -116,10 +106,12 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { |     bool SMTPMailerService::SendIt(const MessageEvent &Msg) { | ||||||
|  |         std::string             Recipient; | ||||||
|  |  | ||||||
|         try |         try | ||||||
|         { |         { | ||||||
|             Poco::Net::MailMessage  Message; |             Poco::Net::MailMessage  Message; | ||||||
|             std::string             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; |             Recipient = Msg.Attrs.find(RECIPIENT_EMAIL)->second; | ||||||
|  |  | ||||||
|             auto H1 = Msg.Attrs.find(SENDER); |             auto H1 = Msg.Attrs.find(SENDER); | ||||||
|             std::string TheSender; |             std::string TheSender; | ||||||
| @@ -130,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); | ||||||
|  |  | ||||||
| @@ -147,21 +138,26 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             auto Logo = Msg.Attrs.find(LOGO); |             auto Logo = Msg.Attrs.find(LOGO); | ||||||
|             if(Logo!=Msg.Attrs.end()) { |             if(Logo!=Msg.Attrs.end()) { | ||||||
|                 Poco::File  LogoFile(TemplateDir_ + "/" + Logo->second); |                 try { | ||||||
|                 std::ifstream   IF(LogoFile.path()); |                     Poco::File          LogoFile(AuthService::GetLogoAssetFileName()); | ||||||
|                 std::ostringstream   OS; |                     std::ifstream       IF(LogoFile.path()); | ||||||
|                 Poco::StreamCopier::copyStream(IF, OS); |                     std::ostringstream  OS; | ||||||
|                 Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/jpeg")); |                     Poco::StreamCopier::copyStream(IF, OS); | ||||||
|  |                     Message.addAttachment("logo", new Poco::Net::StringPartSource(OS.str(), "image/png")); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     Logger_.warning(Poco::format("Cannot add '%s' logo in email",AuthService::GetLogoAssetFileName())); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             Poco::SharedPtr<Poco::Net::AcceptCertificateHandler>  ptrHandler_ = new Poco::Net::AcceptCertificateHandler(false); | ||||||
|  |  | ||||||
|             Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_); |             Poco::Net::SecureSMTPClientSession session(MailHost_,MailHostPort_); | ||||||
|             Poco::Net::Context::Params P; |  | ||||||
|             auto ptrContext = Poco::AutoPtr<Poco::Net::Context> |             auto ptrContext = Poco::AutoPtr<Poco::Net::Context> | ||||||
|                     (new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", |                     (new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", | ||||||
|                                                             Poco::Net::Context::VERIFY_RELAXED, 9, true, |                                                             Poco::Net::Context::VERIFY_RELAXED, 9, true, | ||||||
|                                                             "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH")); |                                                             "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH")); | ||||||
|             Poco::Net::SSLManager::instance().initializeClient(nullptr, |             Poco::Net::SSLManager::instance().initializeClient(nullptr, | ||||||
|                                                                &ptrHandler_, |                                                                ptrHandler_, | ||||||
|                                                                ptrContext); |                                                                ptrContext); | ||||||
|             session.login(); |             session.login(); | ||||||
|             session.startTLS(ptrContext); |             session.startTLS(ptrContext); | ||||||
| @@ -178,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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -59,10 +59,8 @@ namespace OpenWifi { | |||||||
|     class SMTPMailerService : public SubSystemServer, Poco::Runnable { |     class SMTPMailerService : public SubSystemServer, Poco::Runnable { | ||||||
|         public: |         public: | ||||||
|            static SMTPMailerService *instance() { |            static SMTPMailerService *instance() { | ||||||
|                 if (instance_ == nullptr) { |                static auto * instance_ = new SMTPMailerService; | ||||||
|                     instance_ = new SMTPMailerService; |                return instance_; | ||||||
|                 } |  | ||||||
|                 return instance_; |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             struct MessageEvent { |             struct MessageEvent { | ||||||
| @@ -73,42 +71,35 @@ namespace OpenWifi { | |||||||
|                MessageAttributes    Attrs; |                MessageAttributes    Attrs; | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             struct MessageCacheEntry { |  | ||||||
|                uint64_t         LastRequest=0; |  | ||||||
|                uint64_t         HowManyRequests=0; |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             void run() override; |             void run() override; | ||||||
|  |  | ||||||
|             int Start() override; |             int Start() override; | ||||||
|             void Stop() override; |             void Stop() override; | ||||||
|  |  | ||||||
|             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); |             bool SendMessage(const std::string &Recipient, const std::string &Name, const MessageAttributes &Attrs); | ||||||
|             bool SendIt(const MessageEvent &Msg); |             bool SendIt(const MessageEvent &Msg); | ||||||
|             void LoadMyConfig(); |             void LoadMyConfig(); | ||||||
|             void reinitialize(Poco::Util::Application &self) override; |             void reinitialize(Poco::Util::Application &self) override; | ||||||
|             bool Enabled() const { return Enabled_; } |             bool Enabled() const { return Enabled_; } | ||||||
|  |  | ||||||
|         private: |         private: | ||||||
|             static SMTPMailerService * instance_; |  | ||||||
|             std::string             MailHost_; |             std::string             MailHost_; | ||||||
|             std::string             Sender_; |             std::string             Sender_; | ||||||
|             int                     MailHostPort_=25; |             int                     MailHostPort_=25; | ||||||
|  |             int                     MailRetry_=2*60; | ||||||
|  |             int                     MailAbandon_=2*60*20; | ||||||
|             std::string             SenderLoginUserName_; |             std::string             SenderLoginUserName_; | ||||||
|             std::string             SenderLoginPassword_; |             std::string             SenderLoginPassword_; | ||||||
|             std::string             LoginMethod_ = "login"; |             std::string             LoginMethod_ = "login"; | ||||||
|             std::string             LogoFileName_; |  | ||||||
|             std::string             TemplateDir_; |             std::string             TemplateDir_; | ||||||
|             std::list<MessageEvent> Messages_; |             std::list<MessageEvent> Messages_; | ||||||
|             std::map<std::string,MessageCacheEntry> Cache_; |             std::list<MessageEvent> PendingMessages_; | ||||||
|             Poco::Thread            SenderThr_; |             Poco::Thread            SenderThr_; | ||||||
|             std::atomic_bool        Running_=false; |             std::atomic_bool        Running_=false; | ||||||
|             bool                    Enabled_=false; |             bool                    Enabled_=false; | ||||||
|             Poco::Net::AcceptCertificateHandler  ptrHandler_; |  | ||||||
|  |  | ||||||
|             SMTPMailerService() noexcept: |             SMTPMailerService() noexcept: | ||||||
|                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer"), |                 SubSystemServer("SMTPMailer", "MAILER-SVR", "smtpmailer") | ||||||
|                 ptrHandler_(false) |  | ||||||
|             { |             { | ||||||
|                 std::string E{"SHA512"}; |  | ||||||
|             } |             } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,19 +10,34 @@ | |||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     class Storage *Storage::instance_ = nullptr; |  | ||||||
|  |  | ||||||
|     int Storage::Start() { |     int Storage::Start() { | ||||||
| 		std::lock_guard		Guard(Mutex_); | 		std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
| 		StorageClass::Start(); | 		StorageClass::Start(); | ||||||
| 		Create_Tables(); | 		Create_Tables(); | ||||||
|  | 		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 | ||||||
| @@ -13,36 +13,10 @@ | |||||||
| #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 AllActionLinksFieldsForSelect { |  | ||||||
|             "Id, " |  | ||||||
|             "Action," |  | ||||||
|             "UserId," |  | ||||||
|             "template," |  | ||||||
|             "locale," |  | ||||||
|             "message," |  | ||||||
|             "sent," |  | ||||||
|             "created," |  | ||||||
|             "expires," |  | ||||||
|             "completed," |  | ||||||
|             "canceled" |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     static const std::string AllActionLinksFieldsForUpdate { |  | ||||||
|             "Id=?, " |  | ||||||
|             "Action=?," |  | ||||||
|             "UserId=?," |  | ||||||
|             "template=?," |  | ||||||
|             "locale=?," |  | ||||||
|             "message=?," |  | ||||||
|             "sent=?," |  | ||||||
|             "created=?," |  | ||||||
|             "expires=?," |  | ||||||
|             "completed=?," |  | ||||||
|             "canceled=?" |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     static const std::string AllEmailTemplatesFieldsForCreation { |     static const std::string AllEmailTemplatesFieldsForCreation { | ||||||
|  |  | ||||||
|     }; |     }; | ||||||
| @@ -55,6 +29,12 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     class Archiver { | ||||||
|  |     public: | ||||||
|  |         void onTimer(Poco::Timer & timer); | ||||||
|  |     private: | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     class Storage : public StorageClass { |     class Storage : public StorageClass { | ||||||
|     public: |     public: | ||||||
|  |  | ||||||
| @@ -90,7 +70,7 @@ namespace OpenWifi { | |||||||
|             return UNKNOWN; |             return UNKNOWN; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         static const std::string from_userType(USER_TYPE U) { |         static std::string from_userType(USER_TYPE U) { | ||||||
|             switch(U) { |             switch(U) { | ||||||
|                 case ROOT: return "root"; |                 case ROOT: return "root"; | ||||||
|                 case ADMIN: return "admin"; |                 case ADMIN: return "admin"; | ||||||
| @@ -104,9 +84,7 @@ namespace OpenWifi { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         static Storage *instance() { |         static Storage *instance() { | ||||||
|             if (instance_ == nullptr) { |             static auto * instance_ = new Storage; | ||||||
|                 instance_ = new Storage; |  | ||||||
|             } |  | ||||||
|             return instance_; |             return instance_; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -116,7 +94,8 @@ namespace OpenWifi { | |||||||
|         /* |         /* | ||||||
|          *  All user management functions |          *  All user management functions | ||||||
|          */ |          */ | ||||||
|         bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser); |         bool InitializeDefaultUser(); | ||||||
|  |         bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false); | ||||||
|         bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); |         bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User); | ||||||
|         bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); |         bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User); | ||||||
|         bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); |         bool DeleteUser(const std::string & Admin, USER_ID_TYPE & Id); | ||||||
| @@ -133,28 +112,38 @@ 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 | ||||||
|          */ |          */ | ||||||
|         bool CreateAction(std::string &ActionId, std::string &Action, USER_ID_TYPE & Id, Types::StringPairVec & Elements ); |         bool CreateAction( SecurityObjects::ActionLink & A); | ||||||
|         bool DeleteAction(std::string &ActionId); |         bool DeleteAction(std::string &ActionId); | ||||||
|         bool CompleteAction(std::string &ActionId); |         bool CompleteAction(std::string &ActionId); | ||||||
|         bool CancelAction(std::string &ActionId); |         bool CancelAction(std::string &ActionId); | ||||||
|  |         bool SentAction(std::string &ActionId); | ||||||
|  |         bool GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A); | ||||||
|  |         bool GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max=200); | ||||||
|  |         void CleanOldActionLinks(); | ||||||
|  |  | ||||||
| 	  private: | 	  private: | ||||||
| 		static Storage      							*instance_; |  | ||||||
|  |  | ||||||
|         int Create_Tables(); |         int Create_Tables(); | ||||||
|         int Create_UserTable(); |         int Create_UserTable(); | ||||||
|         int Create_AvatarTable(); |         int Create_AvatarTable(); | ||||||
|         int Create_TokensTable(); |         int Create_TokensTable(); | ||||||
|  |         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(); }; | ||||||
|   | |||||||
							
								
								
									
										2479
									
								
								src/framework/ConfigurationValidator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2479
									
								
								src/framework/ConfigurationValidator.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										46
									
								
								src/framework/ConfigurationValidator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/framework/ConfigurationValidator.h
									
									
									
									
									
										Normal 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 | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -47,13 +47,19 @@ namespace OpenWifi::RESTAPI::Errors { | |||||||
|     static const std::string IdMustBe0{"To create a user, you must set the ID to 0"}; |     static const std::string IdMustBe0{"To create a user, you must set the ID to 0"}; | ||||||
|     static const std::string InvalidUserRole{"Invalid userRole."}; |     static const std::string InvalidUserRole{"Invalid userRole."}; | ||||||
|     static const std::string InvalidEmailAddress{"Invalid email address."}; |     static const std::string InvalidEmailAddress{"Invalid email address."}; | ||||||
|     static const std::string InvalidPassword{"Invalid password."}; |  | ||||||
|     static const std::string PasswordRejected{"Password was rejected. This maybe an old password."}; |     static const std::string PasswordRejected{"Password was rejected. This maybe an old password."}; | ||||||
|     static const std::string InvalidIPRanges{"Invalid IP range specifications."}; |     static const std::string InvalidIPRanges{"Invalid IP range specifications."}; | ||||||
|     static const std::string InvalidLOrderBy{"Invalid orderBy specification."}; |     static const std::string InvalidLOrderBy{"Invalid orderBy specification."}; | ||||||
|     static const std::string NeedMobileNumber{"You must provide at least one validated phone number."}; |     static const std::string NeedMobileNumber{"You must provide at least one validated phone number."}; | ||||||
|     static const std::string BadMFAMethod{"MFA only supports sms or email."}; |     static const std::string BadMFAMethod{"MFA only supports sms or email."}; | ||||||
|  |     static const std::string InvalidCredentials{"Invalid credentials (username/password)."}; | ||||||
|  |     static const std::string InvalidPassword{"Password does not conform to basic password rules."}; | ||||||
|  |     static const std::string UserPendingVerification{"User access denied pending email verification."}; | ||||||
|  |     static const std::string PasswordMustBeChanged{"Password must be changed."}; | ||||||
|  |     static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."}; | ||||||
|  |     static const std::string MissingAuthenticationInformation{"Missing authentication information."}; | ||||||
|  |     static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."}; | ||||||
|  |     static const std::string ExpiredToken{"Token has expired, user must login."}; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif //OWPROV_RESTAPI_ERRORS_H | #endif //OWPROV_RESTAPI_ERRORS_H | ||||||
|   | |||||||
| @@ -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,15 +88,13 @@ namespace OpenWifi { | |||||||
|         inline int Setup_PostgreSQL(); |         inline int Setup_PostgreSQL(); | ||||||
|  |  | ||||||
|     protected: |     protected: | ||||||
|         std::unique_ptr<Poco::Data::SessionPool>        	Pool_; |     	Poco::SharedPtr<Poco::Data::SessionPool>    Pool_; | ||||||
|         std::unique_ptr<Poco::Data::SQLite::Connector>  	SQLiteConn_; |         Poco::Data::SQLite::Connector  	            SQLiteConn_; | ||||||
|         std::unique_ptr<Poco::Data::PostgreSQL::Connector>  PostgresConn_; |         Poco::Data::PostgreSQL::Connector           PostgresConn_; | ||||||
|         std::unique_ptr<Poco::Data::MySQL::Connector>       MySQLConn_; |         Poco::Data::MySQL::Connector                MySQLConn_; | ||||||
|         DBType                                              dbType_ = sqlite; |         DBType                                      dbType_ = sqlite; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| //    inline StorageClass * Storage() { return StorageClass::instance(); } |  | ||||||
|  |  | ||||||
| #ifdef	SMALL_BUILD | #ifdef	SMALL_BUILD | ||||||
|     int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } |     int Service::Setup_MySQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } | ||||||
|     int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } |     int Service::Setup_PostgreSQL() { Daemon()->exit(Poco::Util::Application::EXIT_CONFIG); return 0; } | ||||||
| @@ -116,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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -141,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; | ||||||
|     } |     } | ||||||
| @@ -168,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
									
								
							
							
						
						
									
										13
									
								
								src/ow_version.h.in
									
									
									
									
									
										Normal 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@"}; | ||||||
|  | } | ||||||
							
								
								
									
										201
									
								
								src/storage/storage_actionLinks.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								src/storage/storage_actionLinks.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-08. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "storage_actionLinks.h" | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | #include "StorageService.h" | ||||||
|  | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     bool Convert(const ActionLinkRecord &T, SecurityObjects::ActionLink &U) { | ||||||
|  |         U.id = T.get<0>(); | ||||||
|  |         U.action = T.get<1>(); | ||||||
|  |         U.userId = T.get<2>(); | ||||||
|  |         U.actionTemplate = T.get<3>(); | ||||||
|  |         U.variables = RESTAPI_utils::to_stringpair_array(T.get<4>()); | ||||||
|  |         U.locale = T.get<5>(); | ||||||
|  |         U.message = T.get<6>(); | ||||||
|  |         U.sent = T.get<7>(); | ||||||
|  |         U.created = T.get<8>(); | ||||||
|  |         U.expires = T.get<9>(); | ||||||
|  |         U.completed = T.get<10>(); | ||||||
|  |         U.canceled = T.get<11>(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Convert(const SecurityObjects::ActionLink &U, ActionLinkRecord &T) { | ||||||
|  |         T.set<0>(U.id); | ||||||
|  |         T.set<1>(U.action); | ||||||
|  |         T.set<2>(U.userId); | ||||||
|  |         T.set<3>(U.actionTemplate); | ||||||
|  |         T.set<4>(RESTAPI_utils::to_string(U.variables)); | ||||||
|  |         T.set<5>(U.locale); | ||||||
|  |         T.set<6>(U.message); | ||||||
|  |         T.set<7>(U.sent); | ||||||
|  |         T.set<8>(U.created); | ||||||
|  |         T.set<9>(U.expires); | ||||||
|  |         T.set<10>(U.completed); | ||||||
|  |         T.set<11>(U.canceled); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::CreateAction( SecurityObjects::ActionLink & A) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Insert(Sess); | ||||||
|  |             std::string St2{ | ||||||
|  |                 "INSERT INTO ActionLinks (" + AllActionLinksFieldsForSelect + ") VALUES(" + AllActionLinksValuesForSelect + ")"}; | ||||||
|  |             ActionLinkRecord AR; | ||||||
|  |             Convert(A, AR); | ||||||
|  |             Insert << ConvertParams(St2), | ||||||
|  |                 Poco::Data::Keywords::use(AR); | ||||||
|  |             Insert.execute(); | ||||||
|  |             return true; | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::GetActions(std::vector<SecurityObjects::ActionLink> &Links, uint64_t Max) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Select(Sess); | ||||||
|  |  | ||||||
|  |             ActionLinkRecordList ARL; | ||||||
|  |  | ||||||
|  |             std::string S{ | ||||||
|  |                 "SELECT " + AllActionLinksFieldsForSelect + " From ActionLinks where sent=0 and canceled=0 and completed=0"}; | ||||||
|  |             Select << ConvertParams(S), | ||||||
|  |                 Poco::Data::Keywords::into(ARL); | ||||||
|  |             Select.execute(); | ||||||
|  |  | ||||||
|  |             for(const auto &i:ARL) { | ||||||
|  |                 SecurityObjects::ActionLink L; | ||||||
|  |                 Convert(i,L); | ||||||
|  |                 Links.emplace_back(L); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |  | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::GetActionLink(std::string &ActionId, SecurityObjects::ActionLink &A) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Select(Sess); | ||||||
|  |  | ||||||
|  |             ActionLinkRecord AR; | ||||||
|  |  | ||||||
|  |             std::string St2{ | ||||||
|  |                 "SELECT " + AllActionLinksFieldsForSelect + " From ActionLinks where id=?"}; | ||||||
|  |             Select << ConvertParams(St2), | ||||||
|  |             Poco::Data::Keywords::into(AR), | ||||||
|  |             Poco::Data::Keywords::use(ActionId); | ||||||
|  |             Select.execute(); | ||||||
|  |  | ||||||
|  |             if(Select.rowsExtracted()==1) { | ||||||
|  |                 Convert(AR, A); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::SentAction(std::string &ActionId) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Update(Sess); | ||||||
|  |  | ||||||
|  |             uint64_t Sent = std::time(nullptr); | ||||||
|  |             std::string St{"UPDATE ActionLinks set Sent=? where id=?"}; | ||||||
|  |             Update << ConvertParams(St), | ||||||
|  |                 Poco::Data::Keywords::use(Sent), | ||||||
|  |                 Poco::Data::Keywords::use(ActionId); | ||||||
|  |             Update.execute(); | ||||||
|  |             return true; | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::DeleteAction(std::string &ActionId) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Delete(Sess); | ||||||
|  |  | ||||||
|  |             uint64_t Sent = std::time(nullptr); | ||||||
|  |             std::string St{"DELETE FROM ActionLinks where id=?"}; | ||||||
|  |             Delete << ConvertParams(St), | ||||||
|  |                 Poco::Data::Keywords::use(ActionId); | ||||||
|  |             Delete.execute(); | ||||||
|  |             return true; | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::CompleteAction(std::string &ActionId) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Update(Sess); | ||||||
|  |  | ||||||
|  |             uint64_t completed = std::time(nullptr); | ||||||
|  |             std::string St{"UPDATE ActionLinks set completed=? where id=?"}; | ||||||
|  |             Update << ConvertParams(St), | ||||||
|  |                 Poco::Data::Keywords::use(completed), | ||||||
|  |                 Poco::Data::Keywords::use(ActionId); | ||||||
|  |             Update.execute(); | ||||||
|  |             return true; | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::CancelAction(std::string &ActionId) { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |             Poco::Data::Statement Update(Sess); | ||||||
|  |  | ||||||
|  |             uint64_t canceled = std::time(nullptr); | ||||||
|  |             std::string St{"UPDATE ActionLinks set canceled=? where id=?"}; | ||||||
|  |             Update << ConvertParams(St), | ||||||
|  |                 Poco::Data::Keywords::use(canceled), | ||||||
|  |                 Poco::Data::Keywords::use(ActionId); | ||||||
|  |             Update.execute(); | ||||||
|  |             return true; | ||||||
|  |         } catch (const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         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); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										79
									
								
								src/storage/storage_actionLinks.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/storage/storage_actionLinks.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-08. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef OWSEC_STORAGE_ACTIONLINKS_H | ||||||
|  | #define OWSEC_STORAGE_ACTIONLINKS_H | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include "Poco/Tuple.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |     static const std::string AllActionLinksFieldsForCreation{ | ||||||
|  |         "Id             varchar(36)," | ||||||
|  |         "Action         bigint," | ||||||
|  |         "UserId         text," | ||||||
|  |         "template       text," | ||||||
|  |         "variables      text," | ||||||
|  |         "locale         varchar," | ||||||
|  |         "message        text," | ||||||
|  |         "sent           bigint," | ||||||
|  |         "created        bigint," | ||||||
|  |         "expires        bigint," | ||||||
|  |         "completed      bigint," | ||||||
|  |         "canceled       bigint" | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllActionLinksFieldsForSelect { | ||||||
|  |         "Id, " | ||||||
|  |         "Action," | ||||||
|  |         "UserId," | ||||||
|  |         "template," | ||||||
|  |         "variables," | ||||||
|  |         "locale," | ||||||
|  |         "message," | ||||||
|  |         "sent," | ||||||
|  |         "created," | ||||||
|  |         "expires," | ||||||
|  |         "completed," | ||||||
|  |         "canceled" | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllActionLinksValuesForSelect{ "?,?,?,?,?,?,?,?,?,?,?,?" }; | ||||||
|  |  | ||||||
|  |     static const std::string AllActionLinksFieldsForUpdate { | ||||||
|  |         "Id=?, " | ||||||
|  |         "Action=?," | ||||||
|  |         "UserId=?," | ||||||
|  |         "template=?," | ||||||
|  |         "variables=?," | ||||||
|  |         "locale=?," | ||||||
|  |         "message=?," | ||||||
|  |         "sent=?," | ||||||
|  |         "created=?," | ||||||
|  |         "expires=?," | ||||||
|  |         "completed=?," | ||||||
|  |         "canceled=?" | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     typedef Poco::Tuple < | ||||||
|  |                 std::string,    // id | ||||||
|  |                 uint64_t,       // action | ||||||
|  |                 std::string,    // userId | ||||||
|  |                 std::string,    // actionTemplate | ||||||
|  |                 std::string,    // variables | ||||||
|  |                 std::string,    // locale | ||||||
|  |                 std::string,    // message | ||||||
|  |                 uint64_t,       // sent | ||||||
|  |                 uint64_t,       // created | ||||||
|  |                 uint64_t,       // expires | ||||||
|  |                 uint64_t,       // completed | ||||||
|  |                 uint64_t        // canceled | ||||||
|  |             > ActionLinkRecord; | ||||||
|  |     typedef std::vector <ActionLinkRecord> ActionLinkRecordList; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif //OWSEC_STORAGE_ACTIONLINKS_H | ||||||
| @@ -35,8 +35,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|             uint64_t Now = std::time(nullptr); |             uint64_t Now = std::time(nullptr); | ||||||
|  |  | ||||||
|             std::string St2{ |             std::string St2{"INSERT INTO Avatars (" + AllAvatarFieldsForSelect + ") VALUES( " + AllAvatarValuesForSelect + " )"}; | ||||||
|                     "INSERT INTO Avatars (Id,Type,Created,Name,Avatar) VALUES(?,?,?,?,?)"}; |  | ||||||
|  |  | ||||||
|             Insert << ConvertParams(St2), |             Insert << ConvertParams(St2), | ||||||
|                     Poco::Data::Keywords::use(Id), |                     Poco::Data::Keywords::use(Id), | ||||||
| @@ -58,13 +57,19 @@ namespace OpenWifi { | |||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|             Poco::Data::Statement Select(Sess); |             Poco::Data::Statement Select(Sess); | ||||||
|  |  | ||||||
|             std::string St2{"SELECT Avatar, Type, Name FROM Avatars WHERE Id=?"}; |             std::string St2{"SELECT " + AllAvatarFieldsForSelect + " FROM Avatars WHERE Id=?"}; | ||||||
|  |  | ||||||
|             Poco::Data::Statement Select2(Sess); |             Poco::Data::Statement Select2(Sess); | ||||||
|  |  | ||||||
|  |             std::string TId; | ||||||
|  |             uint64_t    Created; | ||||||
|  |  | ||||||
|             Select2 << ConvertParams(St2), |             Select2 << ConvertParams(St2), | ||||||
|                     Poco::Data::Keywords::into(L), |                     Poco::Data::Keywords::into(TId), | ||||||
|                     Poco::Data::Keywords::into(Type), |                     Poco::Data::Keywords::into(Type), | ||||||
|  |                     Poco::Data::Keywords::into(Created), | ||||||
|                     Poco::Data::Keywords::into(Name), |                     Poco::Data::Keywords::into(Name), | ||||||
|  |                     Poco::Data::Keywords::into(L), | ||||||
|                     Poco::Data::Keywords::use(Id); |                     Poco::Data::Keywords::use(Id); | ||||||
|             Select2.execute(); |             Select2.execute(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,33 @@ | |||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     static const std::string AllAvatarFieldsForCreation_sqlite{ | ||||||
|  |         "Id			    VARCHAR(36) PRIMARY KEY, " | ||||||
|  |         "Type			VARCHAR, " | ||||||
|  |         "Created 		BIGINT, " | ||||||
|  |         "Name           VARCHAR, " | ||||||
|  |         "Avatar     	BLOB" | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllAvatarFieldsForCreation_mysql{ | ||||||
|  |         "Id			    VARCHAR(36) PRIMARY KEY, " | ||||||
|  |         "Type			VARCHAR, " | ||||||
|  |         "Created 		BIGINT, " | ||||||
|  |         "Name           VARCHAR, " | ||||||
|  |         "Avatar     	LONGBLOB" | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllAvatarFieldsForCreation_pgsql{ | ||||||
|  |         "Id			    VARCHAR(36) PRIMARY KEY, " | ||||||
|  |         "Type			VARCHAR, " | ||||||
|  |         "Created 		BIGINT, " | ||||||
|  |         "Name           VARCHAR, " | ||||||
|  |         "Avatar     	BYTEA" | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     static const std::string AllAvatarFieldsForSelect{ " Id,Type,Created,Name,Avatar " }; | ||||||
|  |     static const std::string AllAvatarValuesForSelect{ "?,?,?,?,?" }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ | |||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "storage_users.h" | #include "storage_users.h" | ||||||
| #include "storage_avatar.h" | #include "storage_avatar.h" | ||||||
|  | #include "storage_actionLinks.h" | ||||||
|  | #include "storage_tokens.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -12,6 +14,7 @@ namespace OpenWifi { | |||||||
|         Create_UserTable(); |         Create_UserTable(); | ||||||
|         Create_AvatarTable(); |         Create_AvatarTable(); | ||||||
|         Create_TokensTable(); |         Create_TokensTable(); | ||||||
|  |         Create_ActionLinkTable(); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -40,83 +43,51 @@ namespace OpenWifi { | |||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     int Storage::Create_ActionLinkTable() { | ||||||
|  |         try { | ||||||
|  |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |  | ||||||
|  |             Sess << "CREATE TABLE IF NOT EXISTS ActionLinks ( " | ||||||
|  |                     + AllActionLinksFieldsForCreation + " ) ", | ||||||
|  |             Poco::Data::Keywords::now; | ||||||
|  |             return 0; | ||||||
|  |         } catch(const Poco::Exception &E) { | ||||||
|  |             Logger_.log(E); | ||||||
|  |         } | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     int Storage::Create_AvatarTable() { |     int Storage::Create_AvatarTable() { | ||||||
|             try { |             try { | ||||||
|                 Poco::Data::Session Sess = Pool_->get(); |                 Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |  | ||||||
|                 if(dbType_==sqlite) { |                 if(dbType_==sqlite) { | ||||||
|                     Sess << "CREATE TABLE IF NOT EXISTS Avatars (" |                     Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_sqlite + | ||||||
|                             "Id			    VARCHAR(36) PRIMARY KEY, " |  | ||||||
|                             "Type			VARCHAR, " |  | ||||||
|                             "Created 		BIGINT, " |  | ||||||
|                             "Name           VARCHAR, " |  | ||||||
|                             "Avatar     	BLOB" |  | ||||||
|                             ") ", Poco::Data::Keywords::now; |                             ") ", Poco::Data::Keywords::now; | ||||||
|                 } else if(dbType_==mysql) { |                 } else if(dbType_==mysql) { | ||||||
|                     Sess << "CREATE TABLE IF NOT EXISTS Avatars (" |                     Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_mysql + | ||||||
|                             "Id			    VARCHAR(36) PRIMARY KEY, " |  | ||||||
|                             "Type			VARCHAR, " |  | ||||||
|                             "Created 		BIGINT, " |  | ||||||
|                             "Name           VARCHAR, " |  | ||||||
|                             "Avatar     	LONGBLOB" |  | ||||||
|                             ") ", Poco::Data::Keywords::now; |                             ") ", Poco::Data::Keywords::now; | ||||||
|                 } else if(dbType_==pgsql) { |                 } else if(dbType_==pgsql) { | ||||||
|                     Sess << "CREATE TABLE IF NOT EXISTS Avatars (" |                     Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_pgsql + | ||||||
|                             "Id			    VARCHAR(36) PRIMARY KEY, " |  | ||||||
|                             "Type			VARCHAR, " |  | ||||||
|                             "Created 		BIGINT, " |  | ||||||
|                             "Name           VARCHAR, " |  | ||||||
|                             "Avatar     	BYTEA" |  | ||||||
|                             ") ", Poco::Data::Keywords::now; |                             ") ", Poco::Data::Keywords::now; | ||||||
|                 } |                 } | ||||||
|                 return 0; |                 return 0; | ||||||
|             } catch(const Poco::Exception &E) { |             } catch(const Poco::Exception &E) { | ||||||
|                 Logger_.log(E); |                 Logger_.log(E); | ||||||
|             } |             } | ||||||
|             return 0; |             return 1; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int Storage::Create_TokensTable() { |         int Storage::Create_TokensTable() { | ||||||
|         try { |         try { | ||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|             if(dbType_==sqlite) { |                 Sess << "CREATE TABLE IF NOT EXISTS Tokens (" + | ||||||
|                 Sess << "CREATE TABLE IF NOT EXISTS Tokens (" |                             AllTokensFieldsForCreation + | ||||||
|                         "Token			    TEXT PRIMARY KEY, " |  | ||||||
|                         "RefreshToken       TEXT, " |  | ||||||
|                         "TokenType          TEXT, " |  | ||||||
|                         "UserName           TEXT, " |  | ||||||
|                         "Created 		    BIGINT, " |  | ||||||
|                         "Expires 		    BIGINT, " |  | ||||||
|                         "IdleTimeOut        BIGINT, " |  | ||||||
|                         "RevocationDate 	BIGINT " |  | ||||||
|                         ") ", Poco::Data::Keywords::now; |                         ") ", Poco::Data::Keywords::now; | ||||||
|             } else if(dbType_==mysql) { |  | ||||||
|                 Sess << "CREATE TABLE IF NOT EXISTS Tokens (" |  | ||||||
|                         "Token			    TEXT PRIMARY KEY, " |  | ||||||
|                         "RefreshToken       TEXT, " |  | ||||||
|                         "TokenType          TEXT, " |  | ||||||
|                         "UserName           TEXT, " |  | ||||||
|                         "Created 		    BIGINT, " |  | ||||||
|                         "Expires 		    BIGINT, " |  | ||||||
|                         "IdleTimeOut        BIGINT, " |  | ||||||
|                         "RevocationDate 	BIGINT " |  | ||||||
|                         ") ", Poco::Data::Keywords::now; |  | ||||||
|             } else if(dbType_==pgsql) { |  | ||||||
|                 Sess << "CREATE TABLE IF NOT EXISTS Tokens (" |  | ||||||
|                         "Token			    TEXT PRIMARY KEY, " |  | ||||||
|                         "RefreshToken       TEXT, " |  | ||||||
|                         "TokenType          TEXT, " |  | ||||||
|                         "UserName           TEXT, " |  | ||||||
|                         "Created 		    BIGINT, " |  | ||||||
|                         "Expires 		    BIGINT, " |  | ||||||
|                         "IdleTimeOut        BIGINT, " |  | ||||||
|                         "RevocationDate 	BIGINT " |  | ||||||
|                         ") ", Poco::Data::Keywords::now; |  | ||||||
|             } |  | ||||||
|             return 0; |             return 0; | ||||||
|         } catch(const Poco::Exception &E) { |         } catch(const Poco::Exception &E) { | ||||||
|             Logger_.log(E); |             Logger_.log(E); | ||||||
|         } |         } | ||||||
|         return 0; |         return 1; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
|  |  | ||||||
| #include "../StorageService.h" | #include "StorageService.h" | ||||||
|  | #include "storage/storage_tokens.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -14,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); | ||||||
| @@ -22,13 +23,13 @@ namespace OpenWifi { | |||||||
|             uint64_t Z = 0; |             uint64_t Z = 0; | ||||||
|  |  | ||||||
|             std::string St2{ |             std::string St2{ | ||||||
|                 "INSERT INTO Tokens (Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate) VALUES(?,?,?,?,?,?,?,?)"}; |                 "INSERT INTO Tokens (" + AllTokensFieldsForSelect + ") VALUES(" + AllTokensValuesForSelect + ")"}; | ||||||
|  |  | ||||||
|             Insert << ConvertParams(St2), |             Insert << ConvertParams(St2), | ||||||
|                 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), | ||||||
| @@ -41,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 Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate 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); | ||||||
| @@ -115,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) { | ||||||
| @@ -132,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) { | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								src/storage/storage_tokens.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/storage/storage_tokens.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-11-08. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef OWSEC_STORAGE_TOKENS_H | ||||||
|  | #define OWSEC_STORAGE_TOKENS_H | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include "Poco/Tuple.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  |     static std::string AllTokensFieldsForCreation{                        "Token			    TEXT PRIMARY KEY, " | ||||||
|  |                                                                           "RefreshToken       TEXT, " | ||||||
|  |                                                                           "TokenType          TEXT, " | ||||||
|  |                                                                           "UserName           TEXT, " | ||||||
|  |                                                                           "Created 		    BIGINT, " | ||||||
|  |                                                                           "Expires 		    BIGINT, " | ||||||
|  |                                                                           "IdleTimeOut        BIGINT, " | ||||||
|  |                                                                           "RevocationDate 	BIGINT " | ||||||
|  |     }; | ||||||
|  |     static std::string AllTokensFieldsForSelect {"Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate"}; | ||||||
|  |     static std::string AllTokensValuesForSelect{"?,?,?,?,?,?,?,?"}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif //OWSEC_STORAGE_TOKENS_H | ||||||
| @@ -80,7 +80,52 @@ namespace OpenWifi { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser) { |     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 | ||||||
|  |     //  property file. We must set its flag to "must change password", this user has root privilege. | ||||||
|  |     //  if the "DEFAULT-USER-UUID", we keep the UUID of that user. We want to hide the UUID of the default root user | ||||||
|  |     bool Storage::InitializeDefaultUser() { | ||||||
|  |         SecurityObjects::UserInfo   U; | ||||||
|  |         bool DefaultUserCreated = false; | ||||||
|  |  | ||||||
|  |         ReplaceOldDefaultUUID(); | ||||||
|  |         AppServiceRegistry().Get("defaultusercreated",DefaultUserCreated); | ||||||
|  |         if(!GetUserById(NewDefaultUseridStockUUID,U) && !DefaultUserCreated) { | ||||||
|  |             U.currentPassword = MicroService::instance().ConfigGetString("authentication.default.password",""); | ||||||
|  |             U.lastPasswords.push_back(U.currentPassword); | ||||||
|  |             U.email = MicroService::instance().ConfigGetString("authentication.default.username",""); | ||||||
|  |             U.Id = NewDefaultUseridStockUUID; | ||||||
|  |             U.userRole = SecurityObjects::ROOT; | ||||||
|  |             U.creationDate = std::time(nullptr); | ||||||
|  |             U.validated = true; | ||||||
|  |             U.name = "Default User"; | ||||||
|  |             U.description = "Default user should be deleted."; | ||||||
|  |             U.changePassword = true; | ||||||
|  |             CreateUser("SYSTEM",U, true); | ||||||
|  |             AppServiceRegistry().Set("defaultusercreated",true); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Storage::CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready ) { | ||||||
|         try { |         try { | ||||||
|             Poco::Data::Session Sess = Pool_->get(); |             Poco::Data::Session Sess = Pool_->get(); | ||||||
|  |  | ||||||
| @@ -103,19 +148,23 @@ namespace OpenWifi { | |||||||
|             if(!Records.empty()) |             if(!Records.empty()) | ||||||
|                 return false; |                 return false; | ||||||
|  |  | ||||||
|             NewUser.Id = MicroService::instance().CreateUUID(); |             if(!PasswordHashedAlready) { | ||||||
|             NewUser.creationDate = std::time(nullptr); |                 NewUser.Id = MicroService::CreateUUID(); | ||||||
|  |                 NewUser.creationDate = std::time(nullptr); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             //  if there is a password, we assume that we do not want email verification, |             //  if there is a password, we assume that we do not want email verification, | ||||||
|             //  if there is no password, we will do email verification |             //  if there is no password, we will do email verification | ||||||
|             if(NewUser.currentPassword.empty()) { |             if(NewUser.currentPassword.empty()) { | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 NewUser.currentPassword = AuthService()->ComputePasswordHash(NewUser.email,NewUser.currentPassword); |                 if(!PasswordHashedAlready) { | ||||||
|                 NewUser.lastPasswords.clear(); |                     NewUser.currentPassword = AuthService()->ComputeNewPasswordHash(NewUser.email,NewUser.currentPassword); | ||||||
|                 NewUser.lastPasswords.push_back(NewUser.currentPassword); |                     NewUser.lastPasswords.clear(); | ||||||
|                 NewUser.lastPasswordChange = std::time(nullptr); |                     NewUser.lastPasswords.push_back(NewUser.currentPassword); | ||||||
|                 NewUser.validated = true; |                     NewUser.lastPasswordChange = std::time(nullptr); | ||||||
|  |                     NewUser.validated = true; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             auto Notes = RESTAPI_utils::to_string(NewUser.notes); |             auto Notes = RESTAPI_utils::to_string(NewUser.notes); | ||||||
|   | |||||||
| @@ -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," | ||||||
| @@ -105,43 +105,29 @@ namespace OpenWifi { | |||||||
|             "oauthType=?, " |             "oauthType=?, " | ||||||
|             "oauthUserInfo=? "}; |             "oauthUserInfo=? "}; | ||||||
|  |  | ||||||
|     static const std::string AllActionLinksFieldsForCreation{ |  | ||||||
|             "Id          varchar(36)," |  | ||||||
|             "Action         varchar," |  | ||||||
|             "UserId         varchar," |  | ||||||
|             "template       varchar," |  | ||||||
|             "locale         varchar," |  | ||||||
|             "message        text," |  | ||||||
|             "sent           bigint," |  | ||||||
|             "created        bigint," |  | ||||||
|             "expires        bigint," |  | ||||||
|             "completed      bigint," |  | ||||||
|             "canceled       bigint" |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     typedef Poco::Tuple < |     typedef Poco::Tuple < | ||||||
|         std::string,    // Id = 0; |         std::string,    // Id = 0; | ||||||
|         std::string,    // name; |         std::string,    // name; | ||||||
|         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; | ||||||
|   | |||||||
| @@ -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) | ||||||
| @@ -58,8 +58,8 @@ testlogin() { | |||||||
|     curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ |     curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ | ||||||
|         -H "Content-Type: application/json" \ |         -H "Content-Type: application/json" \ | ||||||
|         -d "$payload" > ${result_file} |         -d "$payload" > ${result_file} | ||||||
|     userMustChangePassword=$(cat ${result_file} | jq -r '.userMustChangePassword') |     userMustChangePassword=$(cat ${result_file} | jq -r '.ErrorCode') | ||||||
|     if [[ ${userMustChangePassword} == "true" ]] |     if [[ ${userMustChangePassword} == "1" ]] | ||||||
|     then |     then | ||||||
|         echo "User must change password to login..." |         echo "User must change password to login..." | ||||||
|         if [[ "$3" == "" ]] |         if [[ "$3" == "" ]] | ||||||
| @@ -78,7 +78,10 @@ testlogin() { | |||||||
|         curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ |         curl ${FLAGS} -X POST "https://${OWSEC}/api/v1/oauth2" \ | ||||||
|                 -H "Content-Type: application/json" \ |                 -H "Content-Type: application/json" \ | ||||||
|                 -d "$payload" > ${result_file} |                 -d "$payload" > ${result_file} | ||||||
|         jq < ${result_file} |         token=$(cat ${result_file} | jq -r '.access_token') | ||||||
|  |     else | ||||||
|  |         payload="{ \"userId\" : \"$1\" , \"password\" : \"$2\" }" | ||||||
|  |         token=$(curl ${FLAGS} -X POST -H "Content-Type: application/json" -d "$payload" "https://${OWSEC}/api/v1/oauth2" | jq -r '.access_token') | ||||||
|     fi |     fi | ||||||
|     jq < ${result_file} |     jq < ${result_file} | ||||||
| } | } | ||||||
| @@ -372,6 +375,7 @@ case "$1" in | |||||||
|     "getsubsystemnames") login; getsubsystemnames; logout ;; |     "getsubsystemnames") login; getsubsystemnames; logout ;; | ||||||
|     "reloadsubsystem") login; reloadsubsystem "$2"; logout ;; |     "reloadsubsystem") login; reloadsubsystem "$2"; logout ;; | ||||||
|     "systeminfo") login; systeminfo ; logout;; |     "systeminfo") login; systeminfo ; logout;; | ||||||
|  |     "testburst") login; login; login; login; login; login; login; login; login; login; login; login; login; login; login; login;; | ||||||
|     "help") login; help  ; logout ;; |     "help") login; help  ; logout ;; | ||||||
|     *) help ;; |     *) help ;; | ||||||
| esac | esac | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								wait-for-postgres.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								wait-for-postgres.sh
									
									
									
									
									
										Executable 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 "$@" | ||||||
| @@ -29,9 +29,38 @@ | |||||||
|             opacity: 0.8; |             opacity: 0.8; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .imgcontainer { |         .img-container { | ||||||
|  |             width: 100%; | ||||||
|  |             margin-top: 5%; | ||||||
|             text-align: center; |             text-align: center; | ||||||
|             margin: 24px 0 12px 0; |             display: block; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-card { | ||||||
|  |             padding: 30px; | ||||||
|  |             box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | ||||||
|  |             display: block; | ||||||
|  |             width: 50%; | ||||||
|  |             border: 1em; | ||||||
|  |             background-color: white; | ||||||
|  |             width: 40%; | ||||||
|  |             height: auto; | ||||||
|  |             margin-left: auto; | ||||||
|  |             margin-right: auto; | ||||||
|  |             margin-bottom: auto; | ||||||
|  |             margin-top: 50px; | ||||||
|  |             position: relative; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         .info-list { | ||||||
|  |             width: 80%; | ||||||
|  |             margin: auto; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-title { | ||||||
|  |             padding-bottom: 20px; | ||||||
|  |             width: 80%; | ||||||
|  |             margin: auto; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         img.avatar { |         img.avatar { | ||||||
| @@ -48,6 +77,10 @@ | |||||||
|             padding-top: 16px; |             padding-top: 16px; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         body { | ||||||
|  |             background-color: #ebedef; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         /* Change styles for span and cancel button on extra small screens */ |         /* Change styles for span and cancel button on extra small screens */ | ||||||
|         @media screen and (max-width: 300px) { |         @media screen and (max-width: 300px) { | ||||||
|             span.password1 { |             span.password1 { | ||||||
| @@ -62,13 +95,13 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|  |  | ||||||
| <div class="imgcontainer"> | <div class="img-container"> | ||||||
|     <img src="open-wifi.svg" alt="OpenWifi"> |     <img src="/wwwassets/the_logo.png" alt="OpenWifi"> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <div> | <div class="info-card"> | ||||||
|     <p>Site access rules:</p> |     <h2 class="info-title">Site Access rules</h2> | ||||||
|     <ul> |     <ul class="info-list"> | ||||||
|         <li>Must be a TIP Member.</li> |         <li>Must be a TIP Member.</li> | ||||||
|     </ul> |     </ul> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -30,8 +30,10 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .imgcontainer { |         .imgcontainer { | ||||||
|  |             width: 100%; | ||||||
|  |             margin-top: 5%; | ||||||
|             text-align: center; |             text-align: center; | ||||||
|             margin: 24px 0 12px 0; |             display: block; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         img.avatar { |         img.avatar { | ||||||
| @@ -43,6 +45,37 @@ | |||||||
|             padding: 16px; |             padding: 16px; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         .info-card { | ||||||
|  |             padding: 30px; | ||||||
|  |             box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | ||||||
|  |             display: block; | ||||||
|  |             width: 50%; | ||||||
|  |             border: 1em; | ||||||
|  |             background-color: white; | ||||||
|  |             width: 40%; | ||||||
|  |             height: auto; | ||||||
|  |             margin-left: auto; | ||||||
|  |             margin-right: auto; | ||||||
|  |             margin-bottom: auto; | ||||||
|  |             margin-top: 50px; | ||||||
|  |             position: relative; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-list { | ||||||
|  |             width: 80%; | ||||||
|  |             margin: auto; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-title { | ||||||
|  |             padding-bottom: 20px; | ||||||
|  |             width: 80%; | ||||||
|  |             margin: auto; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         .body { | ||||||
|  |             background-color: #ebedef; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         span.password1 { |         span.password1 { | ||||||
|             float: right; |             float: right; | ||||||
|             padding-top: 16px; |             padding-top: 16px; | ||||||
| @@ -60,16 +93,17 @@ | |||||||
|         } |         } | ||||||
|     </style> |     </style> | ||||||
| </head> | </head> | ||||||
| <body> | <body class="body"> | ||||||
|  |  | ||||||
| <div class="imgcontainer"> | <div class="imgcontainer"> | ||||||
|     <img src="open-wifi.svg" alt="OpenWifi"> |     <img src="/wwwassets/the_logo.png" alt="OpenWifi"> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <div> |  | ||||||
|     <p>Password rules:</p> | <div class="info-card"> | ||||||
|     <ul> |     <h2 class="info-title">Password rules</h2> | ||||||
|         <li>Must be at least 8 characters long.</li> |     <ul class="info-list"> | ||||||
|  |         <li>Must be at least 8 characters long</li> | ||||||
|         <li>Must contain 1 uppercase letter</li> |         <li>Must contain 1 uppercase letter</li> | ||||||
|         <li>Must contain 1 lowercase letter</li> |         <li>Must contain 1 lowercase letter</li> | ||||||
|         <li>Must contain 1 digit</li> |         <li>Must contain 1 digit</li> | ||||||
| @@ -78,5 +112,6 @@ | |||||||
| </div> | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
| @@ -3,8 +3,15 @@ | |||||||
| <head> | <head> | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     <style> |     <style> | ||||||
|         body {font-family: Arial, Helvetica, sans-serif;} |         body { | ||||||
|         form {border: 3px solid #f1f1f1;} |             font-family: Arial,  | ||||||
|  |             Helvetica, sans-serif; | ||||||
|  |             background-color: #ebedef; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .body { | ||||||
|  |             background-color: #ebedef; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         input[type=text], input[type=password] { |         input[type=text], input[type=password] { | ||||||
|             width: 90%; |             width: 90%; | ||||||
| @@ -31,15 +38,10 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .imgcontainer { |         .imgcontainer { | ||||||
|  |             width: 100%; | ||||||
|  |             margin-top: 5%; | ||||||
|             text-align: center; |             text-align: center; | ||||||
|             margin: 5px 0 5px 0; |             display: block; | ||||||
|             grid-column-start: 2; |  | ||||||
|             grid-column-end: 2; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .passwordlabel { |  | ||||||
|             grid-column-start: 2; |  | ||||||
|             grid-column-end: 2; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         img.avatar { |         img.avatar { | ||||||
| @@ -50,16 +52,22 @@ | |||||||
|         .grid-container  { |         .grid-container  { | ||||||
|             display: grid; |             display: grid; | ||||||
|             grid-template-columns: 15% 70% 15%; |             grid-template-columns: 15% 70% 15%; | ||||||
|             background-color: #f3db21; |  | ||||||
|             grid-column-gap: 5px; |             grid-column-gap: 5px; | ||||||
|             padding: 10px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .grid-container > div { |  | ||||||
|             background-color: rgba(255, 255, 255, 0.8); |             background-color: rgba(255, 255, 255, 0.8); | ||||||
|             text-align: center; |             text-align: center; | ||||||
|             padding: 20px 0; |             padding: 30px; | ||||||
|             font-size: 30px; |             box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | ||||||
|  |             display: block; | ||||||
|  |             width: 50%; | ||||||
|  |             border: 1em; | ||||||
|  |             background-color: white; | ||||||
|  |             width: 40%; | ||||||
|  |             height: auto; | ||||||
|  |             margin-left: auto; | ||||||
|  |             margin-right: auto; | ||||||
|  |             margin-bottom: auto; | ||||||
|  |             margin-top: 50px; | ||||||
|  |             position: relative; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .passwordtext { |         .passwordtext { | ||||||
| @@ -67,7 +75,13 @@ | |||||||
|             margin-left: 5%; |             margin-left: 5%; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         .password-input { | ||||||
|  |             margin-top: 0px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         .rulestext { |         .rulestext { | ||||||
|  |             width: 95%; | ||||||
|  |             margin: auto; | ||||||
|             display: inline-block; |             display: inline-block; | ||||||
|             text-align: left; |             text-align: left; | ||||||
|             text-justify: none; |             text-justify: none; | ||||||
| @@ -101,17 +115,18 @@ | |||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
|  |  | ||||||
|  | <div class="imgcontainer"> | ||||||
|  |     <img src="/wwwassets/the_logo.png" alt="OpenWifi"> | ||||||
|  | </div> | ||||||
|  |  | ||||||
| <form action="/api/v1/actionLink?action=password_reset" method="post" onsubmit="return validatePassword()"> | <form action="/api/v1/actionLink?action=password_reset" method="post" onsubmit="return validatePassword()"> | ||||||
| <input type="hidden" id="custId" name="id" value="${UUID}"> | <input type="hidden" id="custId" name="id" value="${UUID}"> | ||||||
| <div class="grid-container"> | <div class="grid-container"> | ||||||
|  |     <h2>Reset Password</h2> | ||||||
|         <div class="imgcontainer"> |  | ||||||
|             <img src="/wwwassets/open-wifi.svg" alt="Logo" class="logo"> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|     <div class="passwordlabel"> |     <div class="passwordlabel"> | ||||||
|         <label class="passwordtext" for="password1" ><b>New Password</b></label> |         <label class="passwordtext" for="password1" ><b>New Password</b></label> | ||||||
|         <input id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required> |         <input className="password-input" id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required> | ||||||
|     </div> |     </div> | ||||||
|     <div class="passwordlabel"> |     <div class="passwordlabel"> | ||||||
|         <label class="passwordtext" for="password2"><b>Retype Password</b></label> |         <label class="passwordtext" for="password2"><b>Retype Password</b></label> | ||||||
|   | |||||||
| @@ -1,11 +1,107 @@ | |||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="en"> | <html lang="en"> | ||||||
| <head> | <head> | ||||||
|     <meta charset="UTF-8"> |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     <title>Reset Password Failed</title> |     <style> | ||||||
|  |         body {font-family: Arial, Helvetica, sans-serif;} | ||||||
|  |         form {border: 3px solid #f1f1f1;} | ||||||
|  |  | ||||||
|  |         input[type=text], input[type=password] { | ||||||
|  |             width: 100%; | ||||||
|  |             padding: 12px 20px; | ||||||
|  |             margin: 8px 0; | ||||||
|  |             display: inline-block; | ||||||
|  |             border: 1px solid #ccc; | ||||||
|  |             box-sizing: border-box; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         button { | ||||||
|  |             background-color: #04AA6D; | ||||||
|  |             color: white; | ||||||
|  |             padding: 14px 20px; | ||||||
|  |             margin: 8px 0; | ||||||
|  |             border: none; | ||||||
|  |             cursor: pointer; | ||||||
|  |             width: 100%; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         button:hover { | ||||||
|  |             opacity: 0.8; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .imgcontainer { | ||||||
|  |             width: 100%; | ||||||
|  |             margin-top: 5%; | ||||||
|  |             text-align: center; | ||||||
|  |             display: block; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         img.avatar { | ||||||
|  |             width: 40%; | ||||||
|  |             border-radius: 50%; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .container { | ||||||
|  |             padding: 16px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-card { | ||||||
|  |             padding: 30px; | ||||||
|  |             box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | ||||||
|  |             display: block; | ||||||
|  |             width: 50%; | ||||||
|  |             border: 1em; | ||||||
|  |             background-color: white; | ||||||
|  |             width: 40%; | ||||||
|  |             height: auto; | ||||||
|  |             margin-left: auto; | ||||||
|  |             margin-right: auto; | ||||||
|  |             margin-bottom: auto; | ||||||
|  |             margin-top: 50px; | ||||||
|  |             position: relative; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-list { | ||||||
|  |             width: 80%; | ||||||
|  |             margin: auto; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .info-title { | ||||||
|  |             padding-bottom: 20px; | ||||||
|  |             width: 80%; | ||||||
|  |             margin: auto; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .body { | ||||||
|  |             background-color: #ebedef; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span.password1 { | ||||||
|  |             float: right; | ||||||
|  |             padding-top: 16px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /* Change styles for span and cancel button on extra small screens */ | ||||||
|  |         @media screen and (max-width: 300px) { | ||||||
|  |             span.password1 { | ||||||
|  |                 display: block; | ||||||
|  |                 float: none; | ||||||
|  |             } | ||||||
|  |             .cancelbtn { | ||||||
|  |                 width: 100%; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     </style> | ||||||
| </head> | </head> | ||||||
| <body> | <body class="body"> | ||||||
|     <h1>Password reset failed...</h1> |  | ||||||
|  | <div class="imgcontainer"> | ||||||
|  |     <img src="/wwwassets/the_logo.png" alt="OpenWifi"> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <div class="info-card"> | ||||||
|  |     <h1 class="info-title">Reset Password Failed</h1> | ||||||
|     <div> |     <div> | ||||||
|         <h3>ID</h3> |         <h3>ID</h3> | ||||||
|         <b>${UUID}</b> |         <b>${UUID}</b> | ||||||
| @@ -14,5 +110,7 @@ | |||||||
|         <h3>Error</h3> |         <h3>Error</h3> | ||||||
|         <b>${ERROR_TEXT}</b> |         <b>${ERROR_TEXT}</b> | ||||||
|     </div> |     </div> | ||||||
|  | </div> | ||||||
|  |  | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
| @@ -62,8 +62,9 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|     <div class="imgcontainer"> |     <div class="imgcontainer"> | ||||||
|       <img src="/wwwassets/avatar.jpg" alt="Avatar" class="avatar"> |       <img src="/wwwassets/the_logo.png" alt="Avatar" class="avatar"> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <h1>Password was successfully reset</h1> |     <h1>Password was successfully reset</h1> | ||||||
|     <div> |     <div> | ||||||
|         <h3>Thank you ${USERNAME} for resetting your password.</h3> |         <h3>Thank you ${USERNAME} for resetting your password.</h3> | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								wwwassets/the_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wwwassets/the_logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.8 KiB | 
		Reference in New Issue
	
	Block a user