]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add OpenResty to CI test servers
authorNick Porter <nick@portercomputing.co.uk>
Fri, 10 Feb 2023 12:08:17 +0000 (12:08 +0000)
committerNick Porter <nick@portercomputing.co.uk>
Mon, 13 Feb 2023 15:00:45 +0000 (15:00 +0000)
.github/workflows/ci.yml
scripts/ci/openresty-setup.sh [new file with mode: 0755]
scripts/ci/openresty/.htpasswd [new file with mode: 0644]
scripts/ci/openresty/auth-api.lua [new file with mode: 0644]
scripts/ci/openresty/json-api.lua [new file with mode: 0644]
scripts/ci/openresty/post-api.lua [new file with mode: 0644]
scripts/ci/openresty/test.txt [new file with mode: 0644]

index 00e37ee1de39fc6de425fcea3ce5ff953821d767..3cd8fff002b65abf9b36d33fd1835d01990c1206 100644 (file)
@@ -274,6 +274,19 @@ jobs:
         path: build/plist/**/*.html
       if: ${{ matrix.env.CC == 'clang' && failure() }}
 
+    - name: Add OpenResty repository
+      shell: bash
+      run: |
+        wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
+        echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list
+
+        sudo apt-get update
+
+    - name: Setup git (containers)
+      if: ${{ env.USE_DOCKER == 1 }}
+      shell: bash
+      run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
+
     - name: Install test requisites
       run: |
         # Temporarily replace ucf (for config merge) with cp since it's
@@ -286,6 +299,7 @@ jobs:
         sudo apt-get install ${APT_OPTS} \
           apparmor-utils \
           ldap-utils \
+          openresty \
           slapd
 
         sudo mv -f /usr/bin/ucf.disabled /usr/bin/ucf
@@ -313,11 +327,17 @@ jobs:
 
         slapd
 
+    - name: Build certificates for REST tests
+      run: |
+        cp -r raddb/certs raddb/restcerts
+        cd ./raddb/restcerts && make ca && make server
+
     - name: Setup test databases
       run: |
         for i in \
             postgresql-setup.sh \
             mysql-setup.sh \
+            openresty-setup.sh \
             ldap-setup.sh \
             ldap2-setup.sh; do
 
diff --git a/scripts/ci/openresty-setup.sh b/scripts/ci/openresty-setup.sh
new file mode 100755 (executable)
index 0000000..af1b31d
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/sh -e
+#
+# ### This is a script to setup an openresty web server for testing rlm_smtp
+#
+
+#
+# Declare the important path variables
+#
+
+# Base Directories
+BASEDIR=$(git rev-parse --show-toplevel)
+BUILDDIR="${BASEDIR}/build/ci/openresty"
+CIDIR="${BASEDIR}/scripts/ci"
+
+# Directories for openresty processes
+ROOTDIR="${BUILDDIR}/html"
+APIDIR="${BUILDDIR}/api"
+LOGDIR="${BUILDDIR}/logs"
+CERTDIR="${BUILDDIR}/certs"
+CERTSRCDIR="${BASEDIR}/raddb/restcerts"
+PASSWORD="whatever"
+
+# Important files for running openresty
+CONF="${BUILDDIR}/nginx.conf"
+
+#
+# Prepare the directories and files needed for running openresty
+#
+
+# Stop any currently running openresty instance
+echo "Checking for a running openresty instance"
+if [ -e "${LOGDIR}/nginx.pid" ]
+then
+       echo "Stopping the current openresty instance"
+       kill "$(cat ${LOGDIR}/nginx.pid)"
+       rm -r "${BUILDDIR}"
+fi
+
+# Create the directories
+mkdir -p "${BUILDDIR}" "${ROOTDIR}" "${APIDIR}" "${LOGDIR}" "${CERTDIR}"
+
+# Create the certificate
+echo "Generating the certificates"
+openssl pkcs8 -in ${CERTSRCDIR}/server.key -passin pass:${PASSWORD} -out ${CERTDIR}/server.key
+cat ${CERTSRCDIR}/server.pem ${CERTSRCDIR}/ca.pem > ${CERTDIR}/server.pem
+
+# Create nginx.conf file
+echo "Generating the openresty configuration file"
+touch "${CONF}"
+
+# Build nginx.conf
+echo "
+#
+worker_processes  1;
+error_log  ${LOGDIR}/error.log;
+pid        ${LOGDIR}/nginx.pid;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       /usr/local/openresty/nginx/conf/mime.types;
+    default_type  text/plain;
+
+    sendfile      on;
+
+    server {
+        listen       8080;
+       server_name  localhost;
+
+       location / {
+           root   ${ROOTDIR};
+           index  index.html;
+       }
+
+       location ~ ^/user(.*)$ {
+           default_type 'application/json';
+           add_header   'Content-Type' 'application/json';
+           content_by_lua_file  ${APIDIR}/json-api.lua;
+       }
+
+       location ~ ^/post(.*)$ {
+           content_by_lua_file  ${APIDIR}/post-api.lua;
+       }
+    }
+
+    server {
+        listen       8443 ssl;
+       server_name  localhost;
+
+       ssl_certificate      ${CERTDIR}/server.pem;
+       ssl_certificate_key  ${CERTDIR}/server.key;
+
+       ssl_session_cache    shared:SSL:1m;
+       ssl_session_timeout  5m;
+
+       ssl_ciphers  HIGH:!aNULL:!MD5;
+       ssl_prefer_server_ciphers  on;
+
+       location / {
+           root   ${ROOTDIR};
+           index  index.html;
+       }
+
+        location ~ ^/user(.*)$ {
+           default_type 'application/json';
+           add_header   'Content-Type' 'application/json';
+           content_by_lua_file  ${APIDIR}/json-api.lua;
+       }
+
+       location ~ ^/post(.*)$ {
+           content_by_lua_file  ${APIDIR}/post-api.lua;
+       }
+
+       location ~ ^/auth(.*)$ {
+           content_by_lua_file   ${APIDIR}/auth-api.lua;
+           auth_basic            'Auth Area';
+           auth_basic_user_file  ${BUILDDIR}/.htpasswd;
+       }
+    }
+}
+
+" >"${CONF}"
+
+echo "Copy lua scripts into place"
+cp ${CIDIR}/openresty/*.lua "${APIDIR}"
+
+echo "Copy sample data into place"
+cp "${CIDIR}/openresty/test.txt" "${ROOTDIR}"
+
+echo "Copy htpasswd into place"
+cp "${CIDIR}/openresty/.htpasswd" "${BUILDDIR}"
+
+#
+# Run the openresty instance
+#
+echo "Starting openresty"
+openresty -c ${CONF} -p ${BUILDDIR}
+echo "Running openresty on port 8080 and 8443, accepting all local connections"
diff --git a/scripts/ci/openresty/.htpasswd b/scripts/ci/openresty/.htpasswd
new file mode 100644 (file)
index 0000000..028536a
--- /dev/null
@@ -0,0 +1 @@
+Bob:$apr1$4AtMvgrH$pWCOxq7gq1N2AyeE7GT3R/
diff --git a/scripts/ci/openresty/auth-api.lua b/scripts/ci/openresty/auth-api.lua
new file mode 100644 (file)
index 0000000..8ea336c
--- /dev/null
@@ -0,0 +1,19 @@
+-- Simple API for checking POST data
+
+-- Get the request path
+local reqPath = ngx.var.uri
+-- Get the request method (POST, GET etc..)
+local reqMethod = ngx.var.request_method
+-- Get any URI arguments
+local uriArgs = ngx.req.get_uri_args()
+-- Get any POST arguments
+ngx.req.read_body()
+local postArgs = ngx.req.get_post_args()
+
+-- We only reply to POST requests
+if reqMethod ~= "POST"
+then
+    return false
+end
+
+ngx.say("Section: ", uriArgs.section, ", User: ", postArgs.user, ", Authenticated: true")
diff --git a/scripts/ci/openresty/json-api.lua b/scripts/ci/openresty/json-api.lua
new file mode 100644 (file)
index 0000000..4a574f7
--- /dev/null
@@ -0,0 +1,145 @@
+-- Based on https://github.com/bambattajb/openresty-api-example
+
+-- Helper functions
+function strSplit(delim,str)
+    local t = {}
+
+    for substr in string.gmatch(str, "[^".. delim.. "]*") do
+        if substr ~= nil and string.len(substr) > 0 then
+            table.insert(t,substr)
+        end
+    end
+
+    return t
+end
+
+-- Read body being passed
+-- Required for ngx.req.get_body_data()
+ngx.req.read_body()
+-- Parser for sending JSON back to the client
+local cjson = require("cjson")
+-- Get the request path
+local reqPath = ngx.var.uri
+-- Get the request method (POST, GET etc..)
+local reqMethod = ngx.var.request_method
+-- Get any URI arguments
+local uriArgs = ngx.req.get_uri_args()
+-- Parse the body data as JSON
+local body = ngx.req.get_body_data() ==
+        -- This is like a ternary statement for Lua
+        -- It is saying if doesn't exist at least
+        -- define as empty object
+        nil and {} or cjson.decode(ngx.req.get_body_data());
+
+Api = {}
+Api.__index = Api
+-- Declare API not yet responded
+Api.responded = false;
+-- Function for checking input from client
+function Api.endpoint(method, path, callback)
+
+    -- return false if method doesn't match
+    if reqMethod ~= method
+    then
+        return false
+    end
+
+    -- If API already responded
+    if Api.responded then
+        return false
+    end
+
+    -- KeyData = params passed in path
+    local keyData = {}
+    -- Unaltered version of path
+    local origPath = reqPath
+    -- If this endpoint has params
+    if string.find(path, "<(.-)>")
+    then
+        -- Split origin and passed path sections
+        local splitPath = strSplit("/", path)
+        local splitReqPath = strSplit("/", reqPath)
+        -- Iterate over splitPath
+        for i, k in pairs(splitPath) do
+            -- If chunk contains <something>
+            if string.find(k, "<(.-)>")
+            then
+                if not splitReqPath[i] then
+                    reqPath = origPath
+                    return false
+                end
+                -- Add to keyData
+                keyData[string.match(k, "%<(%a+)%>")] = splitReqPath[i]
+                -- Replace matches with default for validation
+                reqPath = string.gsub(reqPath, splitReqPath[i], k)
+            end
+        end
+    end
+
+    -- return false if path doesn't match anything
+    if reqPath ~= path
+    then
+        reqPath = origPath
+        return false;
+    end
+
+    -- Make sure we don't run this again
+    Api.responded = true;
+
+    return callback(body, keyData);
+end
+
+-- Used in the accounting test
+Api.endpoint('POST', '/user/<username>/mac/<client>',
+    function(body, keyData)
+        local returnData = {}
+        returnData["control:Tmp-String-0"] = uriArgs.section
+        returnData["control:Tmp-String-1"] = {
+            reqMethod,
+            reqPath
+        }
+        returnData["control:User-Name"] = {
+            op = ":=",
+            value = keyData.username
+        }
+        returnData["control:NAS-IP-Address"] = {
+            op = "+=",
+            value = body.NAS or body['NAS-IP-Address'].value
+        }
+        returnData["control:Tmp-String-2"] = {
+            op = "^=",
+            value = keyData.username
+        }
+        return ngx.say(cjson.encode(returnData))
+    end
+)
+
+-- Used in the authorize test
+Api.endpoint('GET', '/user/<username>/mac/<client>',
+    function(body, keyData)
+        local returnData = {}
+        returnData["control:Tmp-String-0"] = uriArgs.section
+        returnData["control:Tmp-String-1"] = {
+            reqMethod,
+            reqPath
+        }
+        returnData["control:User-Name"] = {
+            op = ":=",
+            value = keyData.username
+        }
+        returnData["control:Tmp-String-2"] = {
+            op = "^=",
+            value = keyData.username
+        }
+        return ngx.say(cjson.encode(returnData))
+    end
+)
+
+-- Simple reflection of a URI argument
+Api.endpoint('GET', '/user/<username>/reflect/',
+    function(body, keyData)
+        local returnData = {}
+        returnData["station"] = uriArgs.station
+        return ngx.say(cjson.encode(returnData))
+    end
+)
diff --git a/scripts/ci/openresty/post-api.lua b/scripts/ci/openresty/post-api.lua
new file mode 100644 (file)
index 0000000..3f22960
--- /dev/null
@@ -0,0 +1,19 @@
+-- Simple API for checking POST data
+
+-- Get the request path
+local reqPath = ngx.var.uri
+-- Get the request method (POST, GET etc..)
+local reqMethod = ngx.var.request_method
+-- Get any URI arguments
+local uriArgs = ngx.req.get_uri_args()
+-- Get any POST arguments
+ngx.req.read_body()
+local postArgs = ngx.req.get_post_args()
+
+-- We only reply to POST requests
+if reqMethod ~= "POST"
+then
+    return false
+end
+
+ngx.say("Section: ", uriArgs.section, ", User: ", postArgs.user)
diff --git a/scripts/ci/openresty/test.txt b/scripts/ci/openresty/test.txt
new file mode 100644 (file)
index 0000000..eceb6ed
--- /dev/null
@@ -0,0 +1 @@
+Sample text response