Compare commits

..

23 Commits

Author SHA1 Message Date
Ivan Chvets
ea90cf4975 Merge branch 'master' into v3.1.0 2024-07-12 09:53:35 -04:00
TIP Automation User
1d2e943071 Chg: update image tag in helm values to v3.1.0 2024-06-29 16:50:23 +00:00
i-chvets
5d89107827 Merge pull request #362 from Telecominfraproject/WIFI-13597-fix-kafka-producer-using-poll
WIFI-13857: fix: modified code to use flush() when internal queue is not loaded
2024-06-19 16:52:01 -04:00
Ivan Chvets
3c15c6dc4f fix: modified code to use flush() when internal queue is not loaded
https://telecominfraproject.atlassian.net/browse/WIFI-13597

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-06-19 16:29:24 -04:00
i-chvets
7b33a692b2 Merge pull request #361 from Telecominfraproject/WIFI-13597-fix-kafka-producer-using-poll
fix: added flush() for proper shutdown
2024-06-18 12:04:02 -04:00
Ivan Chvets
b118dcbcec fix: added flush() for proper shutdown
https://telecominfraproject.atlassian.net/browse/WIFI-13597

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-06-14 16:30:23 -04:00
Stephane Bourque
02a0eef44a Merge pull request #360 from Telecominfraproject/WIFI-13597-fix-kafka-producer-using-poll
WIFI-13597: fix: modified kafka manager to use poll in producer
2024-06-12 12:17:08 -07:00
Ivan Chvets
c7ed7fb264 fix: modified kafka manager to use poll in producer
https://telecominfraproject.atlassian.net/browse/WIFI-13597

Summary of changes:
- Modified code in KafkaManager to use poll instead of flush for every
  messages sent. flush is used only on empty internal notification queue
in idle times.

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-06-11 11:15:42 -04:00
TIP Automation User
5d259a5f68 Chg: update image tag in helm values to v3.1.0-RC1 2024-06-09 17:01:41 +00:00
Gopi Raga
1d88bb50d9 Merge pull request #359 from Telecominfraproject/WIFI-431-fix-update-internal-schema-validation
fix: modified code to use final as default for fingerprint mode
2024-06-06 11:10:46 +05:30
Ivan Chvets
3b613ea159 fix: modified code to use final as default for fingerprint mode
https://telecominfraproject.atlassian.net/browse/WIFI-431

Summary of changes:
- Modified code to use `final` as default value for fingerprint mode.

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-06-05 11:49:49 -04:00
Stephane Bourque
d00d409fca Merge pull request #358 from Telecominfraproject/OLS-84
https://telecominfraproject.atlassian.net/browse/OLS-84
2024-06-04 20:49:16 -07:00
stephb9959
8382818e2d https://telecominfraproject.atlassian.net/browse/OLS-84
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2024-06-04 20:48:14 -07:00
Stephane Bourque
ed4670d239 Merge pull request #357 from Telecominfraproject/OLS-84
https://telecominfraproject.atlassian.net/browse/OLS-84
2024-06-04 13:32:32 -07:00
stephb9959
cca3619e91 https://telecominfraproject.atlassian.net/browse/OLS-84
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2024-06-04 12:55:54 -07:00
Stephane Bourque
9a834c29a2 Merge pull request #355 from Telecominfraproject/WIFI-431-fix-update-internal-schema-validation
fix: modified code to use proper fingerprint defintion
2024-06-04 09:41:34 -07:00
Ivan Chvets
2b06a0bcf6 fix: modified code to use proper fingerprint defintion
https://telecominfraproject.atlassian.net/browse/WIFI-431

Summary of changes:
- Modified code to use proper definition of fingerprint service.

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-06-04 12:16:19 -04:00
Stephane Bourque
03dabed878 Merge pull request #352 from Telecominfraproject/WIFI-13535
https://telecominfraproject.atlassian.net/browse/WIFI-13535
2024-06-03 13:25:46 -07:00
i-chvets
e133a9c3ab Merge pull request #354 from Telecominfraproject/OLS-56-cherry-pick-fix-ols-switch-schema-parsing
OLS-56: fix: replaced incorrect case conversion for device type
2024-05-31 11:37:43 -04:00
Ivan Chvets
23b33fab20 fix: replaced incorrect case conversion for device type
https://telecominfraproject.atlassian.net/browse/OLS-56

Summary of changes:
- Replaced incorrect case conversion for device type.

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-05-30 09:09:48 -04:00
stephb9959
909b4c889e https://telecominfraproject.atlassian.net/browse/WIFI-13535
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2024-05-29 09:12:58 -07:00
Stephane Bourque
a04c5336d2 Merge pull request #350 from Telecominfraproject/WIFI-12748-feat-schema-update-afc-support
ucentral schema update: added afc support
2024-05-27 13:38:27 -07:00
Ivan Chvets
4df1bf985d ucentral schema update: added afc support
https://telecominfraproject.atlassian.net/browse/WIFI-12748

Update to internal schema in the gateway code is required to ensure code is in-sync with schema version on Github.

- Added section to enabled AFC configuration
- Additional updates listed below.

The following updates to schema are also included in this PR:

fix bss color handling
da090931f0

drop ports.duplex support
35da0a1cd0

add support for device fingerprinting
cb1c18db70

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2024-05-27 15:01:17 -04:00
35 changed files with 487 additions and 625 deletions

View File

@@ -1,19 +1,19 @@
name: Build Docker image
name: CI
on:
push:
paths-ignore:
- 'openapi/**'
- '**.md'
- 'version'
- 'package*.json'
- 'helm/*.yaml'
- 'CMakeLists.txt'
branches:
- kinara
- master
- 'release/*'
tags:
- 'v*'
pull_request:
branches:
- kinara
- master
- 'release/*'
defaults:
run:
@@ -21,102 +21,81 @@ defaults:
jobs:
docker:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
env:
ECR_REGISTRY: 471112855615.dkr.ecr.us-east-1.amazonaws.com
ECR_REPOSITORY: owgw
AWS_REGION: us-east-1
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
DOCKER_REGISTRY_USERNAME: ucentral
steps:
- name: Checkout source
uses: actions/checkout@v4
with:
path: build
token: ${{ secrets.GIT_PUSH_PAT }}
persist-credentials: true
- name: Checkout actions repo
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github
- name: Checkout dot github repo
uses: actions/checkout@v4
with:
repository: kinarasystems/.github
ref: main
path: tools
token: ${{ secrets.GIT_PUSH_PAT }}
- name: Build and push Docker image
uses: ./github/composite-actions/docker-image-build
with:
image_name: owgw
registry: tip-tip-wlan-cloud-ucentral.jfrog.io
registry_user: ucentral
registry_password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
- name: Bump version and checkin
if: github.ref == 'refs/heads/kinara'
id: bump-version
run: |
cd build
../tools/utils/setup-git-credentials "${{ secrets.GIT_PUSH_PAT}}"
../tools/utils/ver-bump -b -a -p -V kv -y helm/Chart.yaml -Y helm/values.yaml -M CMakeLists.txt
- name: Notify on failure via Slack
if: failure() && github.ref == 'refs/heads/master'
uses: rtCamp/action-slack-notify@v2
env:
SLACK_USERNAME: GitHub Actions failure notifier
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_COLOR: "${{ job.status }}"
SLACK_ICON: https://raw.githubusercontent.com/quintessence/slack-icons/master/images/github-logo-slack-icon.png
SLACK_TITLE: Docker build failed for OWGW service
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
GITHUB_REF: ${{ github.ref }}
run: |
cd build
version=$(cat version)
../tools/utils/docker_build \
-m kinara \
-b "$GITHUB_REF" \
-t "$IMAGE_TAG" \
-r "$ECR_REGISTRY/$ECR_REPOSITORY" \
-v "kv${version}"
- name: Notify via Teams
#if: failure() && github.ref == 'refs/heads/kinara'
if: always()
uses: skitionek/notify-microsoft-teams@master
with:
webhook_url: ${{ secrets.MS_TEAMS_WEBHOOK }}
needs: ${{ toJson(needs) }}
job: ${{ toJson(job) }}
steps: ${{ toJson(steps) }}
dry_run: False
deploy-to-dev:
trigger-testing:
if: startsWith(github.ref, 'refs/pull/')
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/kinara'
env:
DEPLOY_NAME: owgw
AWS_DEFAULT_REGION: us-east-1
AWS_NAMESPACE: kic-dev1
AWS_EKS_NAME: kinara-dev
KUBECTL_VERSION: "v1.27.14"
needs: docker
steps:
- name: Get base branch name and set as output
id: get_base_branch
run: |
echo "branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/master/main/g')" >> $GITHUB_OUTPUT
- name: Checkout actions repo
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github
- name: Trigger testing of OpenWifi Docker Compose deployment and wait for result
uses: ./github/composite-actions/trigger-workflow-and-wait
env:
BASE_BRANCH: ${{ steps.get_base_branch.outputs.branch }}
with:
owner: Telecominfraproject
repo: wlan-testing
workflow: ow_docker-compose.yml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"deployment_version": "${{ env.BASE_BRANCH }}", "owgw_version": "${{ github.sha }}", "owsec_version": "${{ env.BASE_BRANCH }}", "owfms_version": "${{ env.BASE_BRANCH }}", "owprov_version": "${{ env.BASE_BRANCH }}", "owanalytics_version": "${{ env.BASE_BRANCH }}", "owsub_version": "${{ env.BASE_BRANCH }}", "microservice": "owgw"}'
trigger-deploy-to-dev:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
needs:
- docker
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
- name: Checkout actions repo
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github
- name: Fetch kubeconfig
run: |
aws eks update-kubeconfig --name ${{ env.AWS_EKS_NAME }} --region ${{ env.AWS_DEFAULT_REGION }}
- name: Install kubectl
run: |
curl -s -LO "https://dl.k8s.io/release/${{ env.KUBECTL_VERSION }}/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
- name: Rolling update of deployment
run: |
kubectl rollout restart deployment/${{ env.DEPLOY_NAME }} -n ${{ env.AWS_NAMESPACE }}
- name: Trigger deployment of the latest version to dev instance and wait for result
uses: ./github/composite-actions/trigger-workflow-and-wait
with:
owner: Telecominfraproject
repo: wlan-testing
workflow: ucentralgw-dev-deployment.yaml
token: ${{ secrets.WLAN_TESTING_PAT }}
ref: master
inputs: '{"force_latest": "true"}'

26
.github/workflows/cleanup.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Clean up PR Docker images
on:
pull_request:
branches:
- master
types: [ closed ]
defaults:
run:
shell: bash
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Cleanup Docker image with PR branch tag
run: |
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
else
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
fi

View File

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

41
.github/workflows/openapi-pages.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Update OpenAPI docs on GitHub Pages
on:
push:
paths:
- 'openapi/**'
branches:
- master
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
docsgen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate static HTML page with docs from OpenAPI definition
run: |
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralgw/master/openapi/owgw.yaml -g html2 --skip-validate-spec -o /local/
- name: Update OpenAPI docs
run: |
mkdir tmp-docs
mv index.html tmp-docs/index.html
mkdir -p ~/.ssh
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
git config --global credential.helper store
git config --global user.email "tip-automation@telecominfraproject.com"
git config --global user.name "TIP Automation User"
git pull
git checkout gh-pages || git checkout -b gh-pages
rm -rf docs
mv tmp-docs docs
git add docs
git commit -m'Update OpenAPI docs for GitHub pages'
git push --set-upstream origin gh-pages

46
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
name: Release chart package
on:
push:
tags:
- 'v*'
defaults:
run:
shell: bash
jobs:
helm-package:
runs-on: ubuntu-20.04
env:
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
HELM_REPO_USERNAME: ucentral
steps:
- name: Checkout uCentral assembly chart repo
uses: actions/checkout@v3
with:
path: wlan-cloud-ucentralgw
- name: Build package
working-directory: wlan-cloud-ucentralgw/helm
run: |
helm plugin install https://github.com/aslafy-z/helm-git --version 0.10.0
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm dependency update
mkdir dist
helm package . -d dist
- name: Generate GitHub release body
working-directory: wlan-cloud-ucentralgw/helm
run: |
pip3 install yq -q
echo "Docker image - tip-tip-wlan-cloud-ucentral.jfrog.io/owgw:$GITHUB_REF_NAME" > release.txt
echo "Helm charted may be attached to this release" >> release.txt
echo "Deployment artifacts may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/$GITHUB_REF_NAME" >> release.txt
- name: Create GitHub release
uses: softprops/action-gh-release@v1
with:
body_path: wlan-cloud-ucentralgw/helm/release.txt
files: wlan-cloud-ucentralgw/helm/dist/*

1
.gitignore vendored
View File

@@ -29,3 +29,4 @@ helm/charts/*
!helm/charts/.gitkeep
/portal-test/
/src/ow_version.h

View File

@@ -1,8 +0,0 @@
## 3.0.4 (July 17, 2024)
- chore: updated package.json, updated helm/Chart.yaml, updated helm/values.yaml, updated CMakeLists.txt, updated version, updated CHANGELOG.md, bumped 3.0.3 -> 3.0.4
- Merge pull request #7 from kinarasystems/fix_uptime_update_after_reboot
## 3.0.3 (June 19, 2024)
- chore: updated package.json, updated helm/Chart.yaml, updated helm/values.yaml, updated CMakeLists.txt, updated version, created CHANGELOG.md, bumped 3.0.2 -> 3.0.3
- Merge pull request #6 from kinarasystems/devices

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 3.0.4)
project(owgw VERSION 3.1.0)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

2
build
View File

@@ -1 +1 @@
95
3

View File

@@ -1,21 +0,0 @@
#!/bin/bash
set -e
[ -z "$AWS_PROFILE" ] && echo "Please set AWS_PROFILE" && exit 1
registry="471112855615.dkr.ecr.us-east-1.amazonaws.com"
repo="owgw"
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin "$registry"
img="$registry/$repo"
if [ -n "$1" ] ; then
version="$1"
else
version="latest"
fi
#date > about.txt
#id=$(git rev-parse HEAD)
#br=$(git branch --show-current)
#echo "$br" >> about.txt
#echo "$id" >> about.txt
#echo "Built manually via $0" >> about.txt
#docker build --no-cache -t $img:$version .
docker build -t $img:$version .
docker push $img:$version

20
buildit
View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -e
repo="owgw"
[ -z "$REMOTE_DOCKER_HOST" ] && echo "Please set DOCKER_HOST" && exit 1
[ -z "$REMOTE_DOCKER_PASSWORD" ] && echo "Please set DOCKER_PASSWORD" && exit 1
img="$REMOTE_DOCKER_HOST/kinara/$repo"
if [ -n "$1" ] ; then
version="$1"
else
version="latest"
fi
#date > about.txt
#id=$(git rev-parse HEAD)
#br=$(git branch --show-current)
#echo "$br" >> about.txt
#echo "$id" >> about.txt
#echo "Built manually via $0" >> about.txt
#docker build --no-cache -t $img:$version .
docker build -t $img:$version .
docker push $img:$version

View File

@@ -1,18 +1,18 @@
apiVersion: v2
appVersion: "3.0.4"
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: owgw
version: 0.1.0
dependencies:
- name: postgresql
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
version: 10.9.2
condition: postgresql.enabled
- name: mysql
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
version: 8.8.3
condition: mysql.enabled
- name: mariadb
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
version: 9.4.2
condition: mariadb.enabled
- name: postgresql
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
version: 10.9.2
condition: postgresql.enabled
- name: mysql
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
version: 8.8.3
condition: mysql.enabled
- name: mariadb
repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
version: 9.4.2
condition: mariadb.enabled

View File

@@ -2,21 +2,24 @@
replicaCount: 1
strategyType: Recreate
revisionHistoryLimit: 2
nameOverride: ""
fullnameOverride: ""
images:
owgw:
repository: 471112855615.dkr.ecr.us-east-1.amazonaws.com/owgw
tag: kv3.0.4
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
tag: v3.1.0
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
# username: username
# password: password
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
# username: username
# password: password
dockerize:
repository: 471112855615.dkr.ecr.us-east-1.amazonaws.com/wait-ready
tag: latest
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/dockerize
tag: 0.16.0
pullPolicy: IfNotPresent
services:
owgw:
type: ClusterIP
@@ -59,6 +62,7 @@ services:
servicePort: 3799
targetPort: 3799
protocol: UDP
checks:
owgw:
liveness:
@@ -69,31 +73,33 @@ checks:
exec:
command:
- /readiness_check
ingresses:
restapi:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- restapi.chart-example.local
- restapi.chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
serviceName: owgw
servicePort: restapi
- path: /
pathType: ImplementationSpecific
serviceName: owgw
servicePort: restapi
fileuploader:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- fileuploader.chart-example.local
- fileuploader.chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
serviceName: owgw
servicePort: fileuploader
- path: /
pathType: ImplementationSpecific
serviceName: owgw
servicePort: fileuploader
volumes:
owgw:
- name: config
@@ -119,17 +125,18 @@ volumes:
volumeDefinition: |
persistentVolumeClaim:
claimName: {{ template "owgw.fullname" . }}-pvc
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# requests:
# cpu: 100m
# memory: 128Mi
# limits:
# cpu: 100m
# memory: 128Mi
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# requests:
# cpu: 100m
# memory: 128Mi
# limits:
# cpu: 100m
# memory: 128Mi
securityContext:
fsGroup: 1000
@@ -144,12 +151,18 @@ securityContext:
# value: "2"
#- name: net.ipv4.tcp_keepalive_time
# value: "45"
nodeSelector: {}
tolerations: []
affinity: {}
podAnnotations: {}
podSecurityPolicy:
enabled: false
persistence:
enabled: true
# storageClassName: "-"
@@ -157,6 +170,7 @@ persistence:
- ReadWriteOnce
size: 10Gi
annotations: {}
# Application
public_env_variables:
OWGW_ROOT: /owgw-data
@@ -166,10 +180,12 @@ public_env_variables:
# NOTE in order for readiness check to use system info you need to set READINESS_METHOD to "systeminfo" and set OWSEC to the OWSEC's REST API endpoint
#READINESS_METHOD: systeminfo
#OWSEC: gw-qa01.cicd.lab.wlan.tip.build:16001
secret_env_variables:
# NOTE in order for readiness check to use system info method you need to override these values to the real OWSEC credentials
OWSEC_USERNAME: tip@ucentral.com
OWSEC_PASSWORD: openwifi
configProperties:
# -> Public part
# Websocket
@@ -294,6 +310,7 @@ configProperties:
archiver.db.2.keep: 7
archiver.db.3.name: commandlist
archiver.db.3.keep: 7
# -> Secret part
# Websocket
ucentral.websocket.host.0.key.password: mypassword
@@ -315,8 +332,10 @@ configProperties:
## MySQL
storage.type.mysql.username: stephb
storage.type.mysql.password: snoopy99
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
existingCertsSecret: ""
certs:
clientcas.pem: ""
issuer.pem: ""
@@ -326,53 +345,66 @@ certs:
root.pem: ""
websocket-cert.pem: ""
websocket-key.pem: ""
certsCAs:
issuer.pem: ""
root.pem: ""
# PostgreSQL (https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
postgresql:
enabled: false
image:
registry: docker.io
repository: bitnami/postgresql
tag: 11.13.0-debian-10-r0
postgresqlPostgresPassword: "rootPassword"
postgresqlUsername: stephb
postgresqlPassword: snoopy99
postgresqlDatabase: owgw
persistence:
enabled: true
storageClass: ""
size: 8Gi
# MySQL (https://github.com/bitnami/charts/tree/master/bitnami/mysql)
mysql:
enabled: false
image:
registry: docker.io
repository: bitnami/mysql
tag: 8.0.26-debian-10-r10
auth:
rootPassword: rootPassword
database: owgw
username: stephb
password: snoopy99
primary:
persistence:
enabled: true
storageClass: ""
size: 8Gi
# MariaDB (https://github.com/bitnami/charts/tree/master/bitnami/mariadb)
mariadb:
enabled: false
image:
registry: docker.io
repository: bitnami/mariadb
tag: 10.5.12-debian-10-r0
auth:
rootPassword: rootPassword
database: owgw
username: stephb
password: snoopy99
primary:
persistence:
enabled: true

View File

@@ -1,15 +0,0 @@
{
"name": "owgw",
"version": "3.0.4",
"description": "This is the Kinara version of OpenWifi OWGW",
"author": "Kinara Systems",
"homepage": "https://kinarasystems.com",
"repository": {
"type": "git",
"url": "https://github.com/kinarasystems/wlan-cloud-ucentralgw"
},
"keywords": [
"owgw",
"gateway"
]
}

View File

@@ -83,7 +83,7 @@ namespace OpenWifi {
State_.Address = Utils::FormatIPv6(WS_->peerAddress().toString());
CId_ = SerialNumber_ + "@" + CId_;
auto &Platform = Caps.Platform();
auto Platform = Poco::toLower(Caps.Platform());
if(ParamsObj->has("reason")) {
State_.connectReason = ParamsObj->get("reason").toString();

View File

@@ -207,6 +207,28 @@ namespace OpenWifi {
return 0;
}
bool AP_WS_Server::Disconnect(uint64_t SerialNumber) {
std::shared_ptr<AP_WS_Connection> Connection;
{
auto hashIndex = MACHash::Hash(SerialNumber);
std::lock_guard DeviceLock(SerialNumbersMutex_[hashIndex]);
auto DeviceHint = SerialNumbers_[hashIndex].find(SerialNumber);
if (DeviceHint == SerialNumbers_[hashIndex].end() || DeviceHint->second == nullptr) {
return false;
}
Connection = DeviceHint->second;
SerialNumbers_[hashIndex].erase(DeviceHint);
}
{
auto H = SessionHash::Hash(Connection->State_.sessionId);
std::lock_guard SessionLock(SessionMutex_[H]);
Sessions_[H].erase(Connection->State_.sessionId);
}
return true;
}
void AP_WS_Server::CleanupSessions() {
while(Running_) {

View File

@@ -141,6 +141,7 @@ namespace OpenWifi {
bool Connected(uint64_t SerialNumber, GWObjects::DeviceRestrictions &Restrictions) const;
bool Connected(uint64_t SerialNumber) const;
bool Disconnect(uint64_t SerialNumber);
bool SendFrame(uint64_t SerialNumber, const std::string &Payload) const;
bool SendRadiusAuthenticationData(const std::string &SerialNumber,
const unsigned char *buffer, std::size_t size);

View File

@@ -265,7 +265,11 @@ namespace OpenWifi::Config {
Model_ = Caps->get("model").toString();
if (Caps->has("platform"))
Platform_ = Caps->get("platform").toString();
Platform_ = Poco::toLower(Caps->get("platform").toString());
if(Compatible_.empty()) {
Compatible_ = Model_;
}
std::ostringstream OS;
Caps->stringify(OS);

View File

@@ -17,6 +17,8 @@
#include "RESTAPI_device_helper.h"
#include "AP_WS_Server.h"
namespace OpenWifi {
void RESTAPI_device_handler::DoGet() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
@@ -80,6 +82,9 @@ namespace OpenWifi {
return OK();
} else if (StorageService()->DeleteDevice(SerialNumber)) {
if(AP_WS_Server()->Connected(Utils::SerialNumberToInt(SerialNumber))) {
AP_WS_Server()->Disconnect(Utils::SerialNumberToInt(SerialNumber));
}
return OK();
}

View File

@@ -127,7 +127,7 @@ namespace OpenWifi {
} else if (QB_.CountOnly) {
uint64_t Count = 0;
if (StorageService()->GetDeviceCount(Count, platform, includeProvisioned)) {
if (StorageService()->GetDeviceCount(Count, platform)) {
return ReturnCountOnly(Count);
}
} else if (serialOnly) {

View File

@@ -23,8 +23,8 @@ namespace OpenWifi {
void RESTAPI_script_handler::DoDelete() {
std::string UUID = GetBinding("uuid", "");
if (!UserInfo_.userinfo.userPermissions[SecurityObjects::PM_SCRIPTS_GW][SecurityObjects::PT_DELETE]) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
return BadRequest(RESTAPI::Errors::ACCESS_DENIED);
}
if (UUID.empty()) {
@@ -40,8 +40,8 @@ namespace OpenWifi {
void RESTAPI_script_handler::DoPost() {
std::string UUID = GetBinding("uuid", "");
if (!UserInfo_.userinfo.userPermissions[SecurityObjects::PM_SCRIPTS_GW][SecurityObjects::PT_CREATE]) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
return BadRequest(RESTAPI::Errors::ACCESS_DENIED);
}
if (UUID.empty()) {
@@ -86,8 +86,8 @@ namespace OpenWifi {
void RESTAPI_script_handler::DoPut() {
std::string UUID = GetBinding("uuid", "");
if (!UserInfo_.userinfo.userPermissions[SecurityObjects::PM_SCRIPTS_GW][SecurityObjects::PT_UPDATE]) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT) {
return BadRequest(RESTAPI::Errors::ACCESS_DENIED);
}
if (UUID.empty()) {

View File

@@ -30,7 +30,7 @@ namespace OpenWifi::GWObjects {
void Device::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "serialNumber", SerialNumber);
#ifdef TIP_GATEWAY_SERVICE
field_to_json(Obj, "deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible));
field_to_json(Obj, "deviceType", StorageService()->GetPlatform(SerialNumber));
field_to_json(Obj, "blackListed", StorageService()->IsBlackListed(Utils::MACToInt(SerialNumber)));
#endif
field_to_json(Obj, "macAddress", MACAddress);
@@ -295,7 +295,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "started", started);
field_to_json(Obj, "sessionId", sessionId);
field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj, "totalConnectionTime", started ? Utils::Now() - started : 0);
field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "connectReason", connectReason);
field_to_json(Obj, "uptime", uptime);

View File

@@ -12,8 +12,6 @@
#include "RESTAPI_SecurityObjects.h"
#include "framework/RESTAPI_utils.h"
#include <stdlib.h>
using OpenWifi::RESTAPI_utils::field_from_json;
using OpenWifi::RESTAPI_utils::field_to_json;
@@ -284,7 +282,6 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj, "oauthUserInfo", oauthUserInfo);
field_to_json(Obj, "modified", modified);
field_to_json(Obj, "signingUp", signingUp);
Obj.set("userPermissions", permissions_to_json(userPermissions));
};
bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -321,7 +318,6 @@ namespace OpenWifi::SecurityObjects {
field_from_json(Obj, "oauthUserInfo", oauthUserInfo);
field_from_json(Obj, "modified", modified);
field_from_json(Obj, "signingUp", signingUp);
userPermissions = permissions_from_json(Obj->getObject("userPermissions"));
return true;
} catch (const Poco::Exception &E) {
std::cout << "Cannot parse: UserInfo" << std::endl;
@@ -741,218 +737,4 @@ namespace OpenWifi::SecurityObjects {
return false;
}
PERMISSION_TYPE PermTypeFromString(const std::string &U) {
if (!Poco::icompare(U, "create"))
return PT_CREATE;
else if (!Poco::icompare(U, "update"))
return PT_UPDATE;
else if (!Poco::icompare(U, "delete"))
return PT_DELETE;
else if (!Poco::icompare(U, "readonly"))
return PT_READ_ONLY;
return PT_UNKNOWN;
}
std::string PermTypeToString(PERMISSION_TYPE U) {
switch (U) {
case PT_CREATE:
return "create";
case PT_UPDATE:
return "update";
case PT_DELETE:
return "delete";
case PT_READ_ONLY:
return "readonly";
case PT_UNKNOWN:
default:
return "unknown";
}
}
PERMISSION_MODEL PermModelFromString(const std::string &U) {
if (!Poco::icompare(U, "permissions"))
return PM_PERMISSIONS;
else if (!Poco::icompare(U, "venues"))
return PM_VENUES_PROV;
else if (!Poco::icompare(U, "venues_list"))
return PM_VENUES_LIST_PROV;
else if (!Poco::icompare(U, "entities"))
return PM_ENTITIES_PROV;
else if (!Poco::icompare(U, "entities_list"))
return PM_ENTITIES_LIST_PROV;
else if (!Poco::icompare(U, "inventory"))
return PM_INVENTORY_PROV;
else if (!Poco::icompare(U, "inventory_list"))
return PM_INVENTORY_LIST_PROV;
else if (!Poco::icompare(U, "managementpolicy"))
return PM_MANAGEMENTPOLICY_PROV;
else if (!Poco::icompare(U, "managementpolicy_list"))
return PM_MANAGEMENTPOLICY_LIST_PROV;
else if (!Poco::icompare(U, "managementrole"))
return PM_MANAGEMENTROLE_PROV;
else if (!Poco::icompare(U, "managementrole_list"))
return PM_MANAGEMENTROLE_LIST_PROV;
//GW
else if (!Poco::icompare(U, "scripts"))
return PM_SCRIPTS_GW;
else if (!Poco::icompare(U, "configure"))
return PM_DEVICE_CONFIGURE_GW;
else if (!Poco::icompare(U, "upgrade"))
return PM_DEVICE_UPGRADE_GW;
else if (!Poco::icompare(U, "factoryreset"))
return PM_DEVICE_FACTORY_GW;
else if (!Poco::icompare(U, "leds"))
return PM_DEVICE_LEDS_GW;
else if (!Poco::icompare(U, "trace"))
return PM_DEVICE_TRACE_GW;
else if (!Poco::icompare(U, "request"))
return PM_DEVICE_REQUEST_GW;
else if (!Poco::icompare(U, "wifiscan"))
return PM_DEVICE_WIFISCAN_GW;
else if (!Poco::icompare(U, "eventqueue"))
return PM_DEVICE_EVENTQUEUE_GW;
else if (!Poco::icompare(U, "telemetry"))
return PM_DEVICE_TELEMETRY_GW;
else if (!Poco::icompare(U, "ping"))
return PM_DEVICE_PING_GW;
else if (!Poco::icompare(U, "ap_script"))
return PM_DEVICE_SCRIPT_GW;
else if (!Poco::icompare(U, "rrm"))
return PM_DEVICE_RRM_GW;
else if (!Poco::icompare(U, "transfer"))
return PM_DEVICE_TRANSFER_GW;
else if (!Poco::icompare(U, "certupdate"))
return PM_DEVICE_CERTUPDATE_GW;
else if (!Poco::icompare(U, "powercycle"))
return PM_DEVICE_POWERCYCLE_GW;
else if (!Poco::icompare(U, "ap_logs"))
return PM_DEVICE_LOGS_GW;
else if (!Poco::icompare(U, "healthchecks"))
return PM_DEVICE_HEALTHCHECKS_GW;
else if (!Poco::icompare(U, "ap_capabilities"))
return PM_DEVICE_CAPABILITIES_GW;
else if (!Poco::icompare(U, "ap_statistics"))
return PM_DEVICE_STATISTICS_GW;
else if (!Poco::icompare(U, "ap_status"))
return PM_DEVICE_STATUS_GW;
else if (!Poco::icompare(U, "ap_rtty"))
return PM_DEVICE_RTTY_GW;
return PM_UNKNOWN;
}
std::string PermModelToString(PERMISSION_MODEL U) {
switch (U) {
case PM_PERMISSIONS:
return "permissions";
case PM_VENUES_PROV:
return "venues";
case PM_VENUES_LIST_PROV:
return "venues_list";
case PM_ENTITIES_PROV:
return "entities";
case PM_ENTITIES_LIST_PROV:
return "entities_list";
case PM_INVENTORY_PROV:
return "inventory";
case PM_INVENTORY_LIST_PROV:
return "inventory_list";
case PM_MANAGEMENTPOLICY_PROV:
return "managementpolicy";
case PM_MANAGEMENTPOLICY_LIST_PROV:
return "managementpolicy_list";
case PM_MANAGEMENTROLE_PROV:
return "managementrole";
case PM_MANAGEMENTROLE_LIST_PROV:
return "managementrole_list";
//Gateway
case PM_SCRIPTS_GW:
return "scripts";
case PM_DEVICE_CONFIGURE_GW:
return "configure";
case PM_DEVICE_UPGRADE_GW:
return "upgrade";
case PM_DEVICE_FACTORY_GW:
return "factoryreset";
case PM_DEVICE_LEDS_GW:
return "leds";
case PM_DEVICE_TRACE_GW:
return "trace";
case PM_DEVICE_REQUEST_GW:
return "request";
case PM_DEVICE_WIFISCAN_GW:
return "wifiscan";
case PM_DEVICE_EVENTQUEUE_GW:
return "eventqueue";
case PM_DEVICE_TELEMETRY_GW:
return "telemetry";
case PM_DEVICE_PING_GW:
return "ping";
case PM_DEVICE_SCRIPT_GW:
return "ap_script";
case PM_DEVICE_RRM_GW:
return "rrm";
case PM_DEVICE_TRANSFER_GW:
return "transfer";
case PM_DEVICE_CERTUPDATE_GW:
return "certupdate";
case PM_DEVICE_POWERCYCLE_GW:
return "powercycle";
case PM_DEVICE_LOGS_GW:
return "ap_logs";
case PM_DEVICE_HEALTHCHECKS_GW:
return "healthchecks";
case PM_DEVICE_CAPABILITIES_GW:
return "ap_capabilities";
case PM_DEVICE_STATISTICS_GW:
return "ap_statistics";
case PM_DEVICE_STATUS_GW:
return "ap_status";
case PM_DEVICE_RTTY_GW:
return "ap_rtty";
case PM_UNKNOWN:
default:
return "unknown";
}
}
/**
* Convert PermissionMap into a JSON object and return it
*/
Poco::JSON::Object permissions_to_json(const PermissionMap &Map) {
Poco::JSON::Object MapObj;
for (auto &[Model, Permissions] : Map) {
Poco::JSON::Object ModelObject;
for (auto &[Permission, Allowed] : Permissions) {
ModelObject.set(PermTypeToString(Permission), Allowed);
}
MapObj.set(PermModelToString(Model), ModelObject);
}
return MapObj;
}
/**
* Convert JSON object into a PermissionMap and return it
*/
PermissionMap permissions_from_json(const Poco::JSON::Object::Ptr &Obj) {
PermissionMap permissions;
if (Obj == nullptr) {
return permissions;
}
Poco::JSON::Object::ConstIterator it1;
for(it1 = Obj->begin(); it1 != Obj->end(); it1++) {
std::string model = it1->first;
Poco::JSON::Object::Ptr modelObj = it1->second.extract<Poco::JSON::Object::Ptr>();
Poco::JSON::Object::ConstIterator it2;
for(it2 = modelObj->begin(); it2 != modelObj->end(); it2++) {
std::string permission = it2->first;
bool allowed = it2->second;
permissions[PermModelFromString(model)]
[PermTypeFromString(permission)] = allowed;
}
}
return permissions;
}
} // namespace OpenWifi::SecurityObjects

View File

@@ -11,15 +11,10 @@
#include "Poco/Data/LOB.h"
#include "Poco/Data/LOBStream.h"
#include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPRequest.h"
#include "framework/OpenWifiTypes.h"
#include "framework/utils.h"
#include <string>
#include <type_traits>
#include <iostream>
#include <fstream>
#include <map>
#include <set>
namespace OpenWifi {
uint64_t Now();
@@ -60,10 +55,6 @@ namespace OpenWifi {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
// example entry {"/api/v1/device", {Poco::Net::HTTPRequest::HTTP_POST, Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE}}
const std::map<std::string, std::set<std::string>> API_WHITELIST = {
};
enum USER_ROLE {
UNKNOWN,
ROOT,
@@ -134,72 +125,6 @@ namespace OpenWifi {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
// Represents particular permissions, i.e. what are you doing do the model
enum PERMISSION_TYPE {
PT_CREATE,
PT_DELETE,
PT_UPDATE,
PT_READ_ONLY,
PT_UNKNOWN
};
PERMISSION_TYPE PermTypeFromString(const std::string &U);
std::string PermTypeToString(PERMISSION_TYPE U);
// Represents a model that can be operated on
enum PERMISSION_MODEL {
//Security
PM_PERMISSIONS,
//Provisioning
PM_VENUES_PROV,
PM_VENUES_LIST_PROV,
PM_ENTITIES_PROV,
PM_ENTITIES_LIST_PROV,
PM_INVENTORY_PROV,
PM_INVENTORY_LIST_PROV,
PM_MANAGEMENTPOLICY_PROV,
PM_MANAGEMENTPOLICY_LIST_PROV,
PM_MANAGEMENTROLE_PROV,
PM_MANAGEMENTROLE_LIST_PROV,
//Gateway
PM_DEVICE_CONFIGURE_GW,
PM_DEVICE_UPGRADE_GW,
PM_DEVICE_REBOOT_GW,
PM_DEVICE_FACTORY_GW,
PM_DEVICE_LEDS_GW,
PM_DEVICE_TRACE_GW,
PM_DEVICE_REQUEST_GW,
PM_DEVICE_WIFISCAN_GW,
PM_DEVICE_EVENTQUEUE_GW,
PM_DEVICE_TELEMETRY_GW,
PM_DEVICE_PING_GW,
PM_DEVICE_SCRIPT_GW,
PM_DEVICE_RRM_GW,
PM_DEVICE_TRANSFER_GW,
PM_DEVICE_CERTUPDATE_GW,
PM_DEVICE_POWERCYCLE_GW,
PM_DEVICE_LOGS_GW,
PM_DEVICE_HEALTHCHECKS_GW,
PM_DEVICE_CAPABILITIES_GW,
PM_DEVICE_STATISTICS_GW,
PM_DEVICE_STATUS_GW,
PM_DEVICE_RTTY_GW,
PM_SCRIPTS_GW,
PM_UNKNOWN
};
PERMISSION_MODEL PermModelFromString(const std::string &U);
std::string PermModelToString(PERMISSION_MODEL U);
// Map a permission (e.g. create, delete) to true/false
typedef std::map<PERMISSION_TYPE, bool> ModelPermissionMap;
// Map a model (e.g. venues, devices) to permissions
typedef std::map<PERMISSION_MODEL, ModelPermissionMap> PermissionMap;
Poco::JSON::Object permissions_to_json(const SecurityObjects::PermissionMap &Map);
PermissionMap permissions_from_json(const Poco::JSON::Object::Ptr &Obj);
struct UserInfo {
std::string id;
std::string name;
@@ -224,7 +149,6 @@ namespace OpenWifi {
bool suspended = false;
bool blackListed = false;
USER_ROLE userRole;
PermissionMap userPermissions;
UserLoginLoginExtensions userTypeProprietaryInfo;
std::string securityPolicy;
uint64_t securityPolicyChange = 0;

View File

@@ -155,13 +155,14 @@ namespace OpenWifi {
bool DeleteDevice(std::string &SerialNumber);
bool DeleteDevices(std::string &SerialPattern, bool SimulatedOnly);
bool DeleteDevices(std::uint64_t OlderContact, bool SimulatedOnly);
std::string GetPlatform(const std::string &SerialNumber);
bool UpdateDevice(GWObjects::Device &);
bool UpdateDevice(LockedDbSession &Session, GWObjects::Device &);
bool UpdateDevice(Poco::Data::Session &Sess, GWObjects::Device &NewDeviceDetails);
bool DeviceExists(std::string &SerialNumber);
bool SetConnectInfo(std::string &SerialNumber, std::string &Firmware);
bool GetDeviceCount(uint64_t &Count, const std::string &platform = "", bool includeProvisioned = true);
bool GetDeviceCount(uint64_t &Count, const std::string &platform = "");
bool GetDeviceSerialNumbers(uint64_t From, uint64_t HowMany,
std::vector<std::string> &SerialNumbers,
const std::string &orderBy = "",

View File

@@ -129,26 +129,4 @@ namespace OpenWifi {
return RetrieveApiKeyInformation(SessionToken, UInfo, TID, Expired, Contacted, Suspended);
}
/**
* Given a role, remove the cached user info for any user with that role
*/
void AuthClient::EmptyCacheForRole(const std::string &role) {
SecurityObjects::USER_ROLE roleEnum = SecurityObjects::UserTypeFromString(role);
Poco::JSON::Object::ConstIterator it;
std::set<std::string> tokens = Cache_.getAllKeys();
for(const std::string &token : tokens) {
auto UInfo = Cache_.get(token);
if (UInfo->userinfo.userRole == roleEnum) {
Cache_.remove(token);
}
}
tokens = ApiKeyCache_.getAllKeys();
for(const std::string &token : tokens) {
auto UInfo = ApiKeyCache_.get(token);
if (UInfo->UserInfo.userinfo.userRole == roleEnum) {
ApiKeyCache_.remove(token);
}
}
}
} // namespace OpenWifi

View File

@@ -61,8 +61,6 @@ namespace OpenWifi {
SecurityObjects::UserInfoAndPolicy &UInfo, std::uint64_t TID,
bool &Expired, bool &Contacted, bool &Suspended);
void EmptyCacheForRole(const std::string &role);
private:
Poco::ExpireLRUCache<std::string, OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{
512, 1200000};

View File

@@ -28,7 +28,6 @@ static const std::vector<std::string> GitJSONSchemaURLs = {
};
static std::string DefaultAPSchema = R"foo(
{
"$id": "https://openwrt.org/ucentral.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
@@ -354,14 +353,6 @@ static std::string DefaultAPSchema = R"foo(
10000
]
},
"duplex": {
"description": "The duplex mode that shall be forced.",
"type": "string",
"enum": [
"half",
"full"
]
},
"enabled": {
"description": "This allows forcing the port to down state by default.",
"type": "boolean",
@@ -490,7 +481,59 @@ static std::string DefaultAPSchema = R"foo(
"bss-color": {
"description": "This enables BSS Coloring on the PHY. setting it to 0 disables the feature 1-63 sets the color and 64 will make hostapd pick a random color.",
"type": "integer",
"default": 64
"minimum": 0,
"maximum": 64,
"default": 0
}
}
},
"radio.he-6ghz": {
"type": "object",
"properties": {
"power-type": {
"description": "This config is to set the 6 GHz Access Point type",
"type": "string",
"enum": [
"indoor-power-indoor",
"standard-power",
"very-low-power"
],
"default": "very-low-power"
},
"controller": {
"description": "The URL of the AFC controller that the AP shall connect to.",
"type": "string"
},
"ca-certificate": {
"description": "The CA of the server. This enables mTLS.",
"type": "string",
"format": "uc-base64"
},
"serial-number": {
"description": "The serial number that the AP shall send to the AFC controller.",
"type": "string"
},
"certificate-ids": {
"description": "The certificate IDs that the AP shall send to the AFC controller.",
"type": "string"
},
"minimum-power": {
"description": "The minimum power that the AP shall request from to the AFC controller.",
"type": "number"
},
"frequency-ranges": {
"description": "The list of frequency ranges that the AP shall request from to the AFC controller.",
"type": "array",
"items": {
"type": "string"
}
},
"operating-classes": {
"description": "The list of frequency ranges that the AP shall request from to the AFC controller.",
"type": "array",
"items": {
"type": "number"
}
}
}
},
@@ -635,6 +678,9 @@ static std::string DefaultAPSchema = R"foo(
"he-settings": {
"$ref": "#/$defs/radio.he"
},
"he-6ghz-settings": {
"$ref": "#/$defs/radio.he-6ghz"
},
"hostapd-iface-raw": {
"description": "This array allows passing raw hostapd.conf lines.",
"type": "array",
@@ -784,8 +830,19 @@ static std::string DefaultAPSchema = R"foo(
},
"use-dns": {
"description": "The DNS server sent to clients as DHCP option 6.",
"type": "string",
"format": "uc-ip"
"anyOf": [
{
"type": "string",
"format": "ipv4"
},
{
"type": "array",
"items": {
"type": "string",
"format": "ipv4"
}
}
]
}
}
},
@@ -1313,8 +1370,7 @@ static std::string DefaultAPSchema = R"foo(
"domain-identifier": {
"description": "Mobility Domain identifier (dot11FTMobilityDomainID, MDID).",
"type": "string",
"maxLength": 4,
"minLength": 4,
"format": "uc-mobility",
"examples": [
"abcd"
]
@@ -3701,6 +3757,42 @@ static std::string DefaultAPSchema = R"foo(
}
}
},
"service.fingerprint": {
"description": "This section can be used to configure device fingerprinting.",
"type": "object",
"properties": {
"mode": {
"description": "Enable this option if you would like to enable the MDNS server on the unit.",
"type": "string",
"enum": [
"polled",
"final",
"raw-data"
],
"default": "final"
},
"minimum-age": {
"description": "The minimum age a fingerprint must have before it is reported.",
"type": "number",
"default": 60
},
"maximum-age": {
"description": "The age at which fingerprints get flushed from the local state.",
"type": "number",
"default": 60
},
"periodicity": {
"description": "This value defines the period at which entries get reported.",
"type": "number",
"default": 600
},
"allow-wan": {
"description": "Allow fingerprinting devices found on the WAN port.",
"type": "boolean",
"default": false
}
}
},
"service": {
"description": "This section describes all of the services that may be present on the AP. Each service is then referenced via its name inside an interface, ssid, ...",
"type": "object",
@@ -3770,6 +3862,9 @@ static std::string DefaultAPSchema = R"foo(
},
"rrm": {
"$ref": "#/$defs/service.rrm"
},
"fingerprint": {
"$ref": "#/$defs/service.fingerprint"
}
}
},

View File

@@ -31,7 +31,7 @@ namespace OpenWifi {
void reinitialize(Poco::Util::Application &self) override;
inline static ConfigurationType GetType(const std::string &type) {
std::string Type = Poco::toUpper(type);
std::string Type = Poco::toLower(type);
if (Type == Platforms::AP)
return ConfigurationType::AP;
if (Type == Platforms::SWITCH)

View File

@@ -107,7 +107,16 @@ namespace OpenWifi {
NewMessage.partition(0);
NewMessage.payload(Msg->Payload());
Producer.produce(NewMessage);
Producer.flush();
if (Queue_.size() < 100) {
// use flush when internal queue is lightly loaded, i.e. flush after each
// message
Producer.flush();
}
else {
// use poll when internal queue is loaded to allow messages to be sent in
// batches
Producer.poll((std::chrono::milliseconds) 0);
}
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,
@@ -117,8 +126,13 @@ namespace OpenWifi {
} catch (...) {
poco_error(Logger_, "std::exception");
}
if (Queue_.size() == 0) {
// message queue is empty, flush all previously sent messages
Producer.flush();
}
Note = Queue_.waitDequeueNotification();
}
Producer.flush();
poco_information(Logger_, "Stopped...");
}
@@ -324,4 +338,4 @@ namespace OpenWifi {
partitions.front().get_partition()));
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -27,7 +27,6 @@ namespace OpenWifi::KafkaTopics {
inline const char * EVENT_LEAVE = "leave";
inline const char * EVENT_KEEP_ALIVE = "keep-alive";
inline const char * EVENT_REMOVE_TOKEN = "remove-token";
inline const char * EVENT_PERMISSIONS_UPDATE = "permissions-update";
namespace Fields {
inline const char * EVENT = "event";
@@ -38,7 +37,6 @@ namespace OpenWifi::KafkaTopics {
inline const char * KEY = "key";
inline const char * VRSN = "version";
inline const char * TOKEN = "token";
inline const char * ROLE = "role";
} // namespace Fields
} // namespace ServiceEvents
} // namespace OpenWifi::KafkaTopics

View File

@@ -155,16 +155,6 @@ namespace OpenWifi {
BusLogger,
fmt::format("KAFKA-MSG: invalid event '{}', missing token", Event));
}
} else if (Event == KafkaTopics::ServiceEvents::EVENT_PERMISSIONS_UPDATE) {
if (Object->has(KafkaTopics::ServiceEvents::Fields::ROLE)) {
// Permissions of this role have updated, cached user info is now invalid
AuthClient()->EmptyCacheForRole(
Object->get(KafkaTopics::ServiceEvents::Fields::ROLE).toString());
} else {
poco_information(
logger(),
fmt::format("KAFKA-MSG: invalid event '{}', missing role", Event));
}
} else {
poco_information(BusLogger,
fmt::format("Unknown Event: {} Source: {}", Event, ID));

View File

@@ -60,52 +60,9 @@ namespace OpenWifi {
AlwaysAuthorize_(AlwaysAuthorize), Server_(Server), MyRates_(Profile),
TransactionId_(TransactionId) {}
inline int nthOccurrence(const std::string& str, const std::string& findMe, int nth) {
/*
Helper function to get the index of the nth occurence of string findMe in string str.
if there are not n occurrences of findMe in str, returns -1.
*/
size_t pos = 0;
int count = 0;
while(count != nth)
{
pos+=1;
pos = str.find(findMe, pos);
if (pos == std::string::npos)
return -1;
count++;
}
return pos;
}
inline bool RoleIsAuthorized([[maybe_unused]] const std::string &Path,
[[maybe_unused]] const std::string &Method,
[[maybe_unused]] std::string &Reason) {
// If user role is admin or root, authorized is true
if (UserInfo_.userinfo.userRole == SecurityObjects::USER_ROLE::ADMIN || UserInfo_.userinfo.userRole == SecurityObjects::USER_ROLE::ROOT) {
return true;
}
// We just want the /api/v1/x part of the path so we need to account for
// extra path variables as well as query variables.
std::string pathstubtmp = Path.substr(0, nthOccurrence(Path, "/", 3));
std::string pathstub = pathstubtmp.substr(0, nthOccurrence(pathstubtmp, "?", 1));
// Next check the pathstub against the whitelist
if (SecurityObjects::API_WHITELIST.find(pathstub) != SecurityObjects::API_WHITELIST.end()) {
std::set<std::string> allowed_methods = SecurityObjects::API_WHITELIST.at(pathstub);
// The API stub is in the whitelist, but we also need to check that this method is whitelisted for this stub.
if (allowed_methods.find(Method) != allowed_methods.end()) {
return true;
}
}
// At this point, the user is not root/admin and the API + method is not whitelisted, so we disallow any method that is not a GET.
if (Method != Poco::Net::HTTPRequest::HTTP_GET) {
return false;
}
return true;
}

View File

@@ -172,27 +172,18 @@ namespace OpenWifi {
R.set<30>(D.connectReason);
}
bool Storage::GetDeviceCount(uint64_t &Count, const std::string &platform, bool includeProvisioned) {
bool Storage::GetDeviceCount(uint64_t &Count, const std::string &platform) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
std::string st;
std::string whereClause = "";
if(!platform.empty()) {
if (includeProvisioned == false) {
whereClause = fmt::format("WHERE entity='' and venue='' and DeviceType='" + platform + "'");
} else {
whereClause = fmt::format("WHERE DeviceType='" + platform + "'");
}
std::string st{"SELECT COUNT(*) FROM Devices WHERE DeviceType='" + platform + "'"};
Select << st, Poco::Data::Keywords::into(Count);
} else {
if (includeProvisioned == false) {
whereClause = fmt::format("WHERE entity='' and venue=''");
}
std::string st{"SELECT COUNT(*) FROM Devices"};
Select << st, Poco::Data::Keywords::into(Count);
}
st = fmt::format("SELECT COUNT(*) FROM Devices {}", whereClause);
Select << st, Poco::Data::Keywords::into(Count);
Select.execute();
return true;
} catch (const Poco::Exception &E) {
@@ -624,7 +615,9 @@ namespace OpenWifi {
D.locale = InsertRadiosCountyRegulation(D.Configuration, IPAddress);
D.SerialNumber = Poco::toLower(SerialNumber);
D.Compatible = Caps.Compatible();
D.DeviceType = Caps.Platform();
if(D.Compatible.empty())
D.Compatible = Caps.Model();
D.DeviceType = Poco::toLower(Caps.Platform());
D.MACAddress = Utils::SerialToMAC(SerialNumber);
D.Manufacturer = Caps.Model();
D.Firmware = Firmware;
@@ -673,6 +666,22 @@ namespace OpenWifi {
return false;
}
std::string Storage::GetPlatform(const std::string &SerialNumber) {
try {
Poco::Data::Session Sess = Pool_->get();
Poco::Data::Statement Select(Sess);
std::string St = fmt::format("SELECT DeviceType FROM Devices WHERE SerialNumber='{}'", SerialNumber);
std::string Platform;
Select << ConvertParams(St), Poco::Data::Keywords::into(Platform);
Select.execute();
return Platform;
} catch (const Poco::Exception &E) {
Logger().log(E);
}
return "";
}
bool Storage::DeleteDevice(std::string &SerialNumber) {
try {
std::vector<std::string> TableNames{"Devices", "Statistics", "CommandList",

View File

@@ -1 +0,0 @@
3.0.4