]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add tests for clients loaded from SQL 'nas' table
authorJorge Pereira <jpereiran@gmail.com>
Thu, 27 May 2021 04:48:12 +0000 (01:48 -0300)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 27 May 2021 13:36:07 +0000 (09:36 -0400)
Makefile
src/tests/all.mk
src/tests/radiusd.mk [new file with mode: 0644]
src/tests/sql_nas_table/all.mk [new file with mode: 0644]
src/tests/sql_nas_table/auth.txt [new file with mode: 0644]
src/tests/sql_nas_table/clients.sql [new file with mode: 0644]
src/tests/sql_nas_table/config/radiusd.conf [new file with mode: 0644]

index f4be9e184668122b838047a467d0ec942189081a..5ec0ab4fde9910cc5783505c598cfa9d678362df 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ $(BUILD_DIR)/tests/radiusd-c: raddb/test.conf ${BUILD_DIR}/bin/radiusd | build.r
        @echo "ok"
        @touch $@
 
-test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.xlat tests.keywords tests.auth $(BUILD_DIR)/tests/radiusd-c | build.raddb
+test: ${BUILD_DIR}/bin/radiusd ${BUILD_DIR}/bin/radclient tests.unit tests.xlat tests.keywords tests.auth test.sql_nas_table $(BUILD_DIR)/tests/radiusd-c | build.raddb
        @$(MAKE) -C src/tests tests
 
 #
index d87a22e08201e8f0d69a25ab765efa72da972822..142772b35cd05feedde2a1961fdd8709e6ddc471 100644 (file)
@@ -1,4 +1,7 @@
-SUBMAKEFILES := rbmonkey.mk unit/all.mk map/all.mk xlat/all.mk keywords/all.mk auth/all.mk modules/all.mk
+SUBMAKEFILES := rbmonkey.mk unit/all.mk map/all.mk xlat/all.mk keywords/all.mk auth/all.mk modules/all.mk sql_nas_table/all.mk
+PORT := 12340
+SECRET := testing123
+DICT_PATH := $(top_srcdir)/share
 
 #
 #  Include all of the autoconf definitions into the Make variable space
@@ -10,3 +13,66 @@ SUBMAKEFILES := rbmonkey.mk unit/all.mk map/all.mk xlat/all.mk keywords/all.mk a
 #
 $(BUILD_DIR)/tests/keywords/autoconf.h.mk: src/include/autoconf.h
        @grep '^#define' $^ | sed 's/#define /AC_/;s/ / := /' > $@
+
+######################################################################
+#
+#  Generic rules to set up the tests
+#
+#  Use $(eval $(call TEST_BOOTSTRAP))
+#
+######################################################################
+define TEST_BOOTSTRAP
+
+#
+#  The test files are files without extensions.
+#
+OUTPUT.$(TEST) := $(patsubst %/,%,$(subst $(top_srcdir)/src,$(BUILD_DIR),$(abspath $(DIR))))
+OUTPUT := $$(OUTPUT.$(TEST))
+
+#
+#  Create the output directory
+#
+$$(OUTPUT.$(TEST)):
+       $${Q}mkdir -p $$@
+
+#
+#  All of the output files depend on the input files
+#
+FILES.$(TEST) := $(addprefix $$(OUTPUT.$(TEST))/,$(sort $(FILES)))
+
+#
+#  The output files also depend on the directory
+#  and on the previous test.
+#
+$$(FILES.$(TEST)): | $$(OUTPUT.$(TEST))
+
+#
+#  Make sure that the output files depend on the input.
+#  This way if the input file doesn't exist, we get a
+#  build error.  Without this rule, the test target
+#  would just get re-built every time, no matter what.
+#
+$(foreach x, $(FILES), $(eval $$(OUTPUT.$(TEST))/$x: $(DIR)/$x))
+
+#
+#  We have a real file that's created if all of the tests pass.
+#
+$(BUILD_DIR)/tests/$(TEST): $$(FILES.$(TEST))
+       $${Q}touch $$@
+
+#
+#  For simplicity, we create a phony target so that the poor developer
+#  doesn't need to remember path names
+#
+$(TEST): $(BUILD_DIR)/tests/$(TEST)
+
+#
+#  Clean the output directory and files.
+#
+.PHONY: clean.$(TEST)
+clean.$(TEST):
+       $${Q}rm -rf $$(OUTPUT.$(TEST))
+       $${Q}rm -f $$(BUILD_DIR)/tests/$(TEST)
+
+clean.test: clean.$(TEST)
+endef
diff --git a/src/tests/radiusd.mk b/src/tests/radiusd.mk
new file mode 100644 (file)
index 0000000..85eb4eb
--- /dev/null
@@ -0,0 +1,115 @@
+#
+#      The "RADIUSD_SERVICE" macro is charged to start/stop the radiusd instances
+# from the mostly test targets. It expects the below variables.
+#
+#  - Already defined by scripts/boiler.mk
+#
+#  DIR       = src/tests/$target
+#  BUILD_DIR = build/
+#
+#  - Defined by the target
+#
+#  PORT      := Run the service
+#  TEST      := test.$target
+#
+#  - Parameter
+#
+#  ${1}                config-name found in $(DIR)/config, e.g: src/tests/$target/config/${config-name}.conf
+#  ${2}                output directory
+#
+#  - How to use
+#
+#  1. $(eval $(call RADIUSD_SERVICE,myconfig,directory/path/))
+#
+#  2. It will defined the targets.
+#
+#    $(TEST).radiusd_kill and $(TEST).radiusd_start
+#
+#  3. The target 'radiusd_start' define the variable $(RADIUSD_RUN) with the
+#  exactly command used to start the service.
+#
+#  4. You could use the 'RADIUSD_BIN' to set such path to the "radiusd" binary
+#  that you want to against the tests.
+#
+#  e.g:
+#
+#   make RADIUSD_BIN=/path/to/my/radiusd test
+#
+include Make.inc
+
+define RADIUSD_SERVICE
+$$(eval RADIUSD_BIN := $(JLIBTOOL) --silent --mode=execute $$(TESTBIN)/radiusd)
+
+#
+#  Kill it.  We don't care if it failed or not.  However, we do care
+#  if we can't kill it.
+#
+.PHONY: $(TEST).radiusd_kill
+$(TEST).radiusd_kill: | ${2}
+       ${Q}if [ -f ${2}/radiusd.pid ]; then \
+               if ! ps `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+                   rm -f ${2}/radiusd.pid; \
+                   echo "FreeRADIUS terminated during test called by $(TEST).radiusd_kill"; \
+                   echo "GDB output was:"; \
+                   cat "${2}/gdb.log" 2> /dev/null; \
+                   echo "--------------------------------------------------"; \
+                   echo "Last entries in server log (${2}/radiusd.log):"; \
+                   tail -n 100 "${2}/radiusd.log" 2> /dev/null; \
+                   exit 0; \
+               fi; \
+               if ! kill -9 `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+                       exit 1; \
+               fi; \
+               rm -f ${2}/radiusd.pid; \
+               exit 0; \
+       fi
+
+#
+#  Stop it politely.
+#
+.PHONY: $(TEST).radiusd_stop
+$(TEST).radiusd_stop: | ${2}
+       ${Q}if [ -f ${2}/radiusd.pid ]; then \
+               if ! ps `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+                   rm -f ${2}/radiusd.pid; \
+                   echo "FreeRADIUS terminated during test called by $(TEST).radiusd_kill"; \
+                   echo "GDB output was:"; \
+                   cat "${2}/gdb.log" 2> /dev/null; \
+                   echo "--------------------------------------------------"; \
+                   echo "Last entries in server log (${2}/radiusd.log):"; \
+                   tail -n 100 "${2}/radiusd.log" 2> /dev/null; \
+                   exit 1; \
+               fi; \
+               if ! kill -TERM `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+                       exit 1; \
+               fi; \
+               rm -f ${2}/radiusd.pid; \
+               exit 0; \
+       fi
+
+#
+#      Start radiusd instance
+#
+${2}/radiusd.pid: ${2}
+       $$(eval RADIUSD_RUN := TOP_SRCDIR=$(top_srcdir) TESTDIR=$(DIR) OUTPUT=$(OUTPUT) TEST_PORT=$(PORT) $$(RADIUSD_BIN) -Pxxx -d $(DIR)/config -n ${1} -D $(DICT_PATH) -l ${2}/radiusd.log)
+       ${Q}rm -f ${2}/radiusd.log
+       ${Q}if ! $$(RADIUSD_RUN); then \
+               echo "FAILED STARTING RADIUSD"; \
+               grep 'Error :' "${2}/radiusd.log"; \
+               echo "Last entries in server log (${2}/radiusd.log):"; \
+               tail -n 100 "${2}/radiusd.log" 2> /dev/null; \
+               echo "RADIUSD_RUN: $$(RADIUSD_RUN)"; \
+       fi
+
+.PHONY: $(TEST).radiusd_start
+$(TEST).radiusd_start: ${2}/radiusd.pid
+
+#
+#  If this test framework needs radiusd to be started / stopped, then ensure that
+#  the output files depend on the radiusd binary.
+#
+ifneq "$(FILES.$(TEST))" ""
+$(foreach x, $(FILES.$(TEST)), $(eval $x: $(TESTBINDIR)/radiusd $(TESTBINDIR)/$(CLIENT) $(top_srcdir)/src/tests/$(subst test.,,$(TEST))/config/${1}.conf))
+endif
+
+endef
diff --git a/src/tests/sql_nas_table/all.mk b/src/tests/sql_nas_table/all.mk
new file mode 100644 (file)
index 0000000..98b290c
--- /dev/null
@@ -0,0 +1,57 @@
+#
+#      Unit tests validating the SQL 'nas' table clients
+#
+
+#
+#      Test name
+#
+TEST  := test.sql_nas_table
+FILES := $(subst $(DIR)/,,$(wildcard $(DIR)/*.txt))
+
+$(eval $(call TEST_BOOTSTRAP))
+
+#
+#      Config settings
+#
+SQL_NASTABLE_BUILD_DIR  := $(BUILD_DIR)/tests/sql_nas_table
+SQL_NASTABLE_RADIUS_LOG := $(SQL_NASTABLE_BUILD_DIR)/radiusd.log
+SQL_NASTABLE_GDB_LOG    := $(SQL_NASTABLE_BUILD_DIR)/gdb.log
+SQL_NASTABLE_DB         := $(SQL_NASTABLE_BUILD_DIR)/sql_nas_table.db
+
+# Used by src/tests/sql_nas_table/config/radiusd.conf
+export SQL_NASTABLE_DB
+
+#
+#  Generic rules to start / stop the radius service.
+#
+include src/tests/radiusd.mk
+$(eval $(call RADIUSD_SERVICE,radiusd,$(OUTPUT)))
+
+.PHONY: sql_nas_table_bootstrap
+sql_nas_table_bootstrap:
+       $(Q)rm -f $(SQL_NASTABLE_DB)
+       $(Q)mkdir -p $(SQL_NASTABLE_BUILD_DIR)
+       $(Q)sqlite3 $(SQL_NASTABLE_DB) < ./raddb/mods-config/sql/main/sqlite/schema.sql
+       $(Q)sqlite3 $(SQL_NASTABLE_DB) < ./src/tests/sql_nas_table/clients.sql
+
+#
+#      Run the radclient commands against the radiusd.
+#
+$(OUTPUT)/%: $(DIR)/% | $(TEST).radiusd_kill sql_nas_table_bootstrap $(TEST).radiusd_start
+       $(Q)echo "SQL_NASTABLE-TEST"
+       $(Q)mkdir -p $(dir $@)
+       $(Q)[ -f $(dir $@)/radiusd.pid ] || exit 1
+       $(Q)if ! $(TESTBIN)/radclient $(ARGV) -f src/tests/sql_nas_table/auth.txt -D share/ 127.0.0.1:$(PORT) auth $(SECRET) 1> /dev/null 2>&1; then \
+               echo "FAILED";                                              \
+               rm -f $(BUILD_DIR)/tests/test.sql_nas_table;                \
+               $(MAKE) --no-print-directory test.sql_nas_table.radiusd_kill;   \
+               echo "RADIUSD:   $(RADIUSD_RUN)";                           \
+               echo "SQL_NASTABLE: $(TESTBIN)/radclient $(ARGV) -f $< -xF -d src/tests/sql_nas_table/config -D share/ 127.0.0.1:$(PORT) auth $(SECRET)"; \
+               exit 1;                                                     \
+       fi
+
+       $(Q)touch $@
+
+$(TEST):
+       $(Q)$(MAKE) --no-print-directory $@.radiusd_stop
+       @touch $(BUILD_DIR)/tests/$@
diff --git a/src/tests/sql_nas_table/auth.txt b/src/tests/sql_nas_table/auth.txt
new file mode 100644 (file)
index 0000000..c1b0a1d
--- /dev/null
@@ -0,0 +1,2 @@
+User-Name = bob
+Cleartext-Password = hello
diff --git a/src/tests/sql_nas_table/clients.sql b/src/tests/sql_nas_table/clients.sql
new file mode 100644 (file)
index 0000000..d631b7f
--- /dev/null
@@ -0,0 +1 @@
+INSERT INTO nas (nasname,shortname,type,ports,secret,server,community,description) VALUES ('127.0.0.1', 'test', 'test', '123', 'testing123', 'extra', '', 'RADIUS Client');
diff --git a/src/tests/sql_nas_table/config/radiusd.conf b/src/tests/sql_nas_table/config/radiusd.conf
new file mode 100644 (file)
index 0000000..16513bb
--- /dev/null
@@ -0,0 +1,143 @@
+#  -*- text -*-
+#
+#  test configuration file.  Do not install.
+#
+#  $Id$
+#
+
+#
+#  Minimal radiusd.conf for testing
+#
+top_srcdir   = $ENV{TOP_SRCDIR}
+testdir      = $ENV{TESTDIR}
+output       = ${top_srcdir}/$ENV{OUTPUT}
+run_dir      = ${output}
+raddb        = raddb
+pidfile      = ${run_dir}/radiusd.pid
+panic_action = "gdb -batch -x src/tests/panic.gdb %e %p > ${run_dir}/gdb.log 2>&1; cat ${run_dir}/gdb.log"
+
+maindir      = ${raddb}
+radacctdir   = ${run_dir}/radacct
+modconfdir   = ${maindir}/mods-config
+certdir      = ${maindir}/certs
+cadir        = ${maindir}/certs
+test_port    = $ENV{TEST_PORT}
+
+client docnet {
+       ipaddr = 192.0.2.1
+       secret = testing123123
+}
+
+#  Only for testing!
+#  Setting this on a production system is a BAD IDEA.
+security {
+       allow_vulnerable_openssl = yes
+}
+
+policy {
+       files.authorize {
+               if (&User-Name == "bob") {
+                       update control {
+                               &Password.Cleartext := "hello"
+                       }
+               }
+       }
+       $INCLUDE ${maindir}/policy.d/
+}
+
+modules {
+       expr {
+
+       }
+
+       sql {
+               driver = "rlm_sql_sqlite"
+               dialect = "sqlite"
+               sqlite {
+                       # Path to the sqlite database
+                       filename = "$ENV{SQL_NASTABLE_DB}"
+
+                       # How long to wait for write locks on the database to be
+                       # released (in ms) before giving up.
+                       busy_timeout = 200
+
+                       # The bootstrap is handled by src/tests/sql_nas_table/all.mk
+               }
+
+               radius_db = "radius"
+
+               acct_table1 = "radacct"
+               acct_table2 = "radacct"
+               postauth_table = "radpostauth"
+               authcheck_table = "radcheck"
+               groupcheck_table = "radgroupcheck"
+               authreply_table = "radreply"
+               groupreply_table = "radgroupreply"
+               usergroup_table = "radusergroup"
+               read_groups = yes
+               read_profiles = yes
+
+               # Set to 'yes' to read radius clients from the database ('nas' table)
+               # Clients will ONLY be read on server startup.
+               read_clients = yes
+
+               # Table to keep radius client info
+               client_table = "nas"
+
+               # The group attribute specific to this instance of rlm_sql
+               group_attribute = "SQL-Group"
+
+               # Read database-specific queries
+               $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
+       }
+
+       always reject {
+               rcode = reject
+       }
+       always fail {
+               rcode = fail
+       }
+       always ok {
+               rcode = ok
+       }
+       always handled {
+               rcode = handled
+       }
+       always invalid {
+               rcode = invalid
+       }
+       always notfound {
+               rcode = notfound
+       }
+       always noop {
+               rcode = noop
+       }
+       always updated {
+               rcode = updated
+       }
+}
+
+#
+#  This virtual server is chosen for processing requests when using:
+#
+#      radiusd -Xd src/tests/ -i 127.0.0.1 -p 12340 -n test
+#
+server extra {
+       listen {
+               ipaddr = 127.0.0.1
+               port = ${test_port}
+               type = auth
+       }
+
+       authorize {
+               if (&User-Name == "bob") {
+                       accept
+               } else {
+                       reject
+               }
+       }
+
+       authenticate {
+
+       }
+}