summaryrefslogtreecommitdiffstats
path: root/src/tests/radsec
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/radsec')
-rw-r--r--src/tests/radsec/.gitignore6
-rw-r--r--src/tests/radsec/1.basic-auth.reply2
-rw-r--r--src/tests/radsec/1.basic-auth.request3
-rw-r--r--src/tests/radsec/2.ipaddrudp-coa.reply4
-rw-r--r--src/tests/radsec/2.ipaddrudp-coa.request3
-rw-r--r--src/tests/radsec/3.homepooludp-coa.reply4
-rw-r--r--src/tests/radsec/3.homepooludp-coa.request2
-rw-r--r--src/tests/radsec/4.homepooltls-coa.reply4
-rw-r--r--src/tests/radsec/4.homepooltls-coa.request2
-rw-r--r--src/tests/radsec/5.singletunnel_proxy-coa.reply6
-rw-r--r--src/tests/radsec/5.singletunnel_proxy-coa.request2
-rw-r--r--src/tests/radsec/6.singletunnel_originate-coa.reply4
-rw-r--r--src/tests/radsec/6.singletunnel_originate-coa.request2
-rw-r--r--src/tests/radsec/7.coareply-auth.reply4
-rw-r--r--src/tests/radsec/7.coareply-auth.request2
-rw-r--r--src/tests/radsec/Makefile10
-rw-r--r--src/tests/radsec/README.rst103
-rw-r--r--src/tests/radsec/all.mk150
-rw-r--r--src/tests/radsec/config-coa/main.conf.template37
-rw-r--r--src/tests/radsec/config-home/main.conf322
-rw-r--r--src/tests/radsec/config-proxy/main.conf.template207
-rwxr-xr-xsrc/tests/radsec/runtest.sh83
22 files changed, 962 insertions, 0 deletions
diff --git a/src/tests/radsec/.gitignore b/src/tests/radsec/.gitignore
new file mode 100644
index 0000000..9daa835
--- /dev/null
+++ b/src/tests/radsec/.gitignore
@@ -0,0 +1,6 @@
+dictionary
+radiusd.conf
+sites-enabled
+mods-enabled
+radrelay.conf
+test.conf
diff --git a/src/tests/radsec/1.basic-auth.reply b/src/tests/radsec/1.basic-auth.reply
new file mode 100644
index 0000000..77aa6b1
--- /dev/null
+++ b/src/tests/radsec/1.basic-auth.reply
@@ -0,0 +1,2 @@
+Received Access-Accept
+
diff --git a/src/tests/radsec/1.basic-auth.request b/src/tests/radsec/1.basic-auth.request
new file mode 100644
index 0000000..a6ddb8e
--- /dev/null
+++ b/src/tests/radsec/1.basic-auth.request
@@ -0,0 +1,3 @@
+User-Name = "bob",
+NAS-IP-Address = "1.2.3.4",
+Called-Station-Id = "key0"
diff --git a/src/tests/radsec/2.ipaddrudp-coa.reply b/src/tests/radsec/2.ipaddrudp-coa.reply
new file mode 100644
index 0000000..8ea0bfd
--- /dev/null
+++ b/src/tests/radsec/2.ipaddrudp-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "coa-buffered-reader:pre-proxy" "proxy-tls-default:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "proxy-tls-default:send-coa" "coa-buffered-reader:post-proxy"$
+
diff --git a/src/tests/radsec/2.ipaddrudp-coa.request b/src/tests/radsec/2.ipaddrudp-coa.request
new file mode 100644
index 0000000..9d3f5eb
--- /dev/null
+++ b/src/tests/radsec/2.ipaddrudp-coa.request
@@ -0,0 +1,3 @@
+User-Name = "IpAddress",
+NAS-IP-Address = "127.0.0.1",
+Called-Station-Id = "12341",
diff --git a/src/tests/radsec/3.homepooludp-coa.reply b/src/tests/radsec/3.homepooludp-coa.reply
new file mode 100644
index 0000000..ab9f0a1
--- /dev/null
+++ b/src/tests/radsec/3.homepooludp-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "home-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "home-originate-coa-relay:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/3.homepooludp-coa.request b/src/tests/radsec/3.homepooludp-coa.request
new file mode 100644
index 0000000..e3bff09
--- /dev/null
+++ b/src/tests/radsec/3.homepooludp-coa.request
@@ -0,0 +1,2 @@
+User-Name = "HomePoolCoA",
+Called-Station-Id = "coa-nas"
diff --git a/src/tests/radsec/4.homepooltls-coa.reply b/src/tests/radsec/4.homepooltls-coa.reply
new file mode 100644
index 0000000..4666894
--- /dev/null
+++ b/src/tests/radsec/4.homepooltls-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "home-originate-coa-relay:pre-proxy" "proxy-tls-default:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "proxy-tls-default:send-coa" "home-originate-coa-relay:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/4.homepooltls-coa.request b/src/tests/radsec/4.homepooltls-coa.request
new file mode 100644
index 0000000..7038e25
--- /dev/null
+++ b/src/tests/radsec/4.homepooltls-coa.request
@@ -0,0 +1,2 @@
+User-Name = "HomePoolCoA",
+Called-Station-Id = "coa-nas-tls"
diff --git a/src/tests/radsec/5.singletunnel_proxy-coa.reply b/src/tests/radsec/5.singletunnel_proxy-coa.reply
new file mode 100644
index 0000000..81a4173
--- /dev/null
+++ b/src/tests/radsec/5.singletunnel_proxy-coa.reply
@@ -0,0 +1,6 @@
+# We don't need delay since proxy flow will be finished
+# just after final CoA home server will return response.
+#delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "default:pre-proxy" "coa_tls:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "coa_tls:send-coa" "default:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/5.singletunnel_proxy-coa.request b/src/tests/radsec/5.singletunnel_proxy-coa.request
new file mode 100644
index 0000000..72ace4d
--- /dev/null
+++ b/src/tests/radsec/5.singletunnel_proxy-coa.request
@@ -0,0 +1,2 @@
+User-Name = "TcpSessionKey-Proxy",
+Called-Station-Id = "key0"
diff --git a/src/tests/radsec/6.singletunnel_originate-coa.reply b/src/tests/radsec/6.singletunnel_originate-coa.reply
new file mode 100644
index 0000000..6a242b0
--- /dev/null
+++ b/src/tests/radsec/6.singletunnel_originate-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "default:pre-proxy" "coa_tls:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "coa_tls:send-coa" "default:post-proxy-coa-ack"
+
diff --git a/src/tests/radsec/6.singletunnel_originate-coa.request b/src/tests/radsec/6.singletunnel_originate-coa.request
new file mode 100644
index 0000000..a838730
--- /dev/null
+++ b/src/tests/radsec/6.singletunnel_originate-coa.request
@@ -0,0 +1,2 @@
+User-Name = "TcpSessionKey",
+Called-Station-Id = "key0"
diff --git a/src/tests/radsec/7.coareply-auth.reply b/src/tests/radsec/7.coareply-auth.reply
new file mode 100644
index 0000000..62e680e
--- /dev/null
+++ b/src/tests/radsec/7.coareply-auth.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received Access-Accept
+Acct-Session-Id = "default:post-auth" "default:pre-proxy" "coa_tls:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "coa_tls:send-coa" "default:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/7.coareply-auth.request b/src/tests/radsec/7.coareply-auth.request
new file mode 100644
index 0000000..bd2e2b4
--- /dev/null
+++ b/src/tests/radsec/7.coareply-auth.request
@@ -0,0 +1,2 @@
+User-Name = "PostAuthCoA",
+Called-Station-Id = "key0",
diff --git a/src/tests/radsec/Makefile b/src/tests/radsec/Makefile
new file mode 100644
index 0000000..d732b29
--- /dev/null
+++ b/src/tests/radsec/Makefile
@@ -0,0 +1,10 @@
+include ../../../Make.inc
+
+all: tests.radsec
+ @echo "All tests done"
+
+include all.mk
+
+
+.PHONY: clean
+clean: clean.tests.radsec \ No newline at end of file
diff --git a/src/tests/radsec/README.rst b/src/tests/radsec/README.rst
new file mode 100644
index 0000000..a016a02
--- /dev/null
+++ b/src/tests/radsec/README.rst
@@ -0,0 +1,103 @@
+=======================
+Tests for radsec flows.
+=======================
+
+ RADIUS CoA
+ ┌─────────────────────────────────────────────────────────────┐
+ │ │
+┌──────▼───────┐ ┌────────────────┐ ┌───────┴────────┐
+│ │ │ │ RADSEC CoA │ │
+│ radiusd │ RADIUS CoA │ radiusd ◄──────────────┤ radiusd │
+│ ◄─────────────┤ │ RADSEC Auth │ │
+│ CoA Server │ │ Proxy Server ├──────────────► Home Server │
+│ │ │ │ │ │
+└──────────────┘ └───────▲────────┘ └───────▲────────┘
+ │ │
+ │ RADIUS │ RADIUS
+ │ Auth │ CoA
+ ┌───────┴────────┐ ┌───────┴────────┐
+ │ radclient │ │ radclient │
+ └────────────────┘ └────────────────┘
+
+
+FreeRADIUS common configuration is located (obviously) in
+src/tests/radsec/radddb directory. Specific configurations for separate radiusd
+instances are located under their respective directories: config-coa,
+config-proxy, config-home.
+
+Each test is a pair of two files ending with \*.request and \*.reply.
+
+To run these tests separately, make sure you run 'make test' from the root
+directory beforehand.
+
+Request files.
+==============
+
+\*.request file specifies attributes to be sent.
+
+The name of the file (the part after the dash) specifies the type of the request
+to be sent.
+
+For example 1.basic-auth.request sends an auth request and 2.basic-coa.request
+sends coa.
+
+* Authentication requests.
+--------------------------
+Radclient sends plain RADIUS Access-Request to Proxy Server. Proxy Server then
+proxies this authentication request with RADSEC to Home Server. An opened TLS
+tunnel is used later to accept CoA requests from Home Server.
+
+* CoA requests.
+---------------
+Radclient sends plain RADIUS CoA request to Home Server. Depending on the
+attributes Home Server does one of the following:
+
+- Originates CoA request to Proxy Server with RADSEC - original flow. This is
+the regular flow where Proxy Server acts as a TCP server and Home Server (as
+a TCP client) first needs to establish a connection to it.
+
+- Originates CoA request to Proxy Server with RADSEC - 'single tunnel flow'.
+This is the new flow where Proxy Server can accept CoA requests from Home Server
+within the same tunnel that it has opened for Access-Request. In this case, the
+Proxy Server is still a TCP client yet in terms of RADIUS protocol it acts as
+a CoA Server.
+
+In both of these two cases, the Proxy Server forwards a CoA request to CoA
+Server to complete the flow. As an example CoA Server responds with CoA-ACK,
+then in turn Proxy Server responds with CoA-ACK to Home Server and the flow
+completes.
+
+- Originates CoA request directly to CoA Server. Although this is not a RADSEC
+flow, that is also good to check.
+
+
+Reply files.
+============
+
+\*.reply file specify a result to be expected for the corresponding \*.request
+file.
+
+
+For each such pair of \*.request \*.reply files runtest.sh is run.
+
+This shell script sends a request with radclient.
+
+Several freeRADIUS instances process requests and add attributes to be checked.
+In the end of the flow all cumulative attributes are written to the detail_test
+file for later checking.
+
+The runtest.sh checks the result following a \*.reply file.
+
+After test is performed a new directory is created with name "$TEST_NAME.result"
+where all intermediate files realted to the test are located, an example of the
+directory structure is like follows:
+
+ok - status file: either ok or fail
+detail_test - helper file to save attributes by freeRADIUS
+2.ipaddrtls-coa.reply.tmp - reply file w/o internal commands (e.g delay)
+fr-home-2.ipaddrtls-coa.log - a part of freeRADIUS logs related to the test
+fr-coa-2.ipaddrtls-coa.log - the same just for radiusd CoA Server
+fr-proxy-2.ipaddrtls-coa.log - the same just for radiusd Proxy Server
+radclient.log - logs for radclient
+result-2.ipaddrtls-coa.log - combined and aggregated radclient.log and
+ - detail_test to be checked against \*.reply file
diff --git a/src/tests/radsec/all.mk b/src/tests/radsec/all.mk
new file mode 100644
index 0000000..1d6140e
--- /dev/null
+++ b/src/tests/radsec/all.mk
@@ -0,0 +1,150 @@
+BUILD_PATH := $(top_builddir)/build
+TEST_PATH := $(top_builddir)/src/tests/radsec
+BIN_PATH := $(BUILD_PATH)/bin/local
+LIB_PATH := $(BUILD_PATH)/lib/.libs/
+RADDB_PATH := $(top_builddir)/raddb
+
+# Naming convention for ports is like follows: port-<owner>-<description>.
+# Owner may be either CoA Server, Proxy Server or Home Server
+port-proxy-auth = 12340
+port-proxy-coa = 12341
+port-home-auth = 12342
+port-home-coa = 12343
+port-coa = 12344
+
+# Port difines for request types: auth or coa
+auth-port = $(port-proxy-auth)
+coa-port = $(port-home-coa)
+
+
+#
+# You can watch what it's doing by:
+#
+# $ VERBOSE=1 make ... args ...
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+raddb:
+ ${Q}echo "Setting up raddb directory"
+ ${Q}cp -r $(top_builddir)/raddb $(TEST_PATH)
+ ${Q}rm -rf $(TEST_PATH)/raddb/sites-enabled/* # we have per server config
+ ${Q}echo 'detail detail_test {' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo ' filename = $${radacctdir}/detail_test' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo '}' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo 'detail detail_coa {' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo ' filename = $${radacctdir}/detail_coa' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo '}' >> $(TEST_PATH)/raddb/mods-enabled/detail
+
+ ${Q}$(MAKE) -C $(TEST_PATH)/raddb/certs
+
+dictionary:
+ ${Q}echo "# test dictionary not install. Delete at any time." > $(TEST_PATH)/dictionary
+ ${Q}echo '$$INCLUDE ' $(top_builddir)/share/dictionary >> $(TEST_PATH)/dictionary
+
+
+define TEST_CONF
+ ${Q}printf "Configuring radiusd $(1) -> "
+ ${Q}echo "# radiusd test configuration file. Do not install. Delete at any time." > $(TEST_PATH)/test-$(1).conf
+ ${Q}echo "libdir =" $(LIB_PATH) >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo "testdir =" $(TEST_PATH) >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'logdir = $${testdir}' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'maindir = ${TEST_PATH}/raddb/' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'radacctdir = $${testdir}' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'pidfile = $${testdir}/radiusd-$(1).pid' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'panic_action = "gdb -batch -x $${testdir}/panic.gdb %e %p > $${testdir}/gdb-$(1).log 2>&1; cat $${testdir}/gdb-$(1).log"' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'security {' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo ' allow_vulnerable_openssl = yes' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo '}' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'modconfdir = $${maindir}mods-config' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'certdir = $${maindir}/certs' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'cadir = $${maindir}/certs' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo '$$INCLUDE $${testdir}/config-$(1)/main.conf' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo '$$INCLUDE $${maindir}/radiusd.conf' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}rm -f $(TEST_PATH)/gdb-$(1).log $(TEST_PATH)/fr-$(1).log
+endef
+
+define START_SERVER
+ ${Q}printf "Starting $(1) server... "
+ ${Q}if ! $(BIN_PATH)/radiusd -Pxxxxml $(TEST_PATH)/fr-$(1).log -d $(TEST_PATH) -n test-$(1) -D $(TEST_PATH); then \
+ echo "failed"; \
+ echo "Last log entries were:"; \
+ tail -n 20 "$(TEST_PATH)/fr-$(1).log"; \
+ else \
+ echo "ok"; \
+ fi
+endef
+
+define PID_SERVER
+ ${Q}sed 's/$${{port-proxy-auth}}/$(port-proxy-auth)/g; \
+ s/$${{port-proxy-coa}}/$(port-proxy-coa)/g; \
+ s/$${{port-home-auth}}/$(port-home-auth)/g; \
+ s/$${{port-home-coa}}/$(port-home-coa)/g; \
+ s/$${{port-coa}}/$(port-coa)/g' \
+ $(TEST_PATH)/config-$(1)/main.conf > $(TEST_PATH)/config-$(1)/main.conf
+ $(call TEST_CONF,$(1))
+ $(call START_SERVER,$(1))
+endef
+
+radiusd.pid: raddb dictionary
+ $(call PID_SERVER,coa)
+ $(call PID_SERVER,home)
+ $(call PID_SERVER,proxy)
+
+define KILL_SERVER
+ ${Q}if [ -f $(TEST_PATH)/radiusd-$(1).pid ]; then \
+ if ! ps `cat $(TEST_PATH)/radiusd-$(1).pid` >/dev/null 2>&1; then \
+ rm -f $(TEST_PATH)/radiusd-$(1).pid; \
+ echo "FreeRADIUS terminated during test"; \
+ echo "GDB output was:"; \
+ cat "$(TEST_PATH)/gdb-$(1).log"; \
+ echo "Last log entries were:"; \
+ tail -n 20 $(TEST_PATH)/fr-$(1).log; \
+ fi; \
+ if ! kill -TERM `cat $(TEST_PATH)/radiusd-$(1).pid` >/dev/null 2>&1; then \
+ echo "Cannot kill $(TEST_PATH)/radiusd-$(1).pid"; \
+ fi; \
+ fi
+ ${Q}rm -f $(TEST_PATH)/radiusd-$(1).pid $(TEST_PATH)/config-$(1)/*.conf
+endef
+
+radiusd-proxy.kill:
+ $(call KILL_SERVER,proxy)
+radiusd-home.kill:
+ $(call KILL_SERVER,home)
+radiusd-coa.kill:
+ $(call KILL_SERVER,coa)
+
+radiusd.kill: radiusd-proxy.kill radiusd-home.kill radiusd-coa.kill
+
+# E.g: basis-auth.request -> TEST_NAME=basic-auth TYPE=auth, PORT=$(auth-port)
+%.request.test:
+ ${Q}printf "RADSEC-TEST $@... "
+ ${Q}if ! TEST_NAME=$(patsubst %.request.test,%,$@) \
+ TYPE=$(word 2, $(subst -, ,$(patsubst %.request.test,%,$@))) \
+ PORT=$($(word 2, $(subst -, ,$(patsubst %.request.test,%,$@)))-port) \
+ TEST_PATH=$(TEST_PATH) $(TEST_PATH)/runtest.sh 2>&1 > /dev/null; then \
+ echo "failed"; \
+ else \
+ echo "ok"; \
+ fi
+
+# kill the server (if it's running)
+# start the server
+# run the tests
+# kill the server
+#TEST_FILES = 2.basic-coa.request.test
+TEST_FILES = $(sort $(addsuffix .test,$(notdir $(wildcard $(TEST_PATH)/*.request))))
+tests.radsec: radiusd.kill radiusd.pid $(TEST_FILES)
+ ${Q}$(MAKE) radiusd.kill
+
+.PHONY: clean.tests.radsec
+clean.tests.radsec: radiusd.kill
+ ${Q}cd $(TEST_PATH) && rm -rf raddb/ detail_coa detail_test *.result *.conf dictionary *.ok *.log *.tmp
+
+
+.PHONY: radiusd.kill radiusd-proxy.kill radiusd-home.kill radiusd-coa.kill dictionary raddb
diff --git a/src/tests/radsec/config-coa/main.conf.template b/src/tests/radsec/config-coa/main.conf.template
new file mode 100644
index 0000000..5baf4b7
--- /dev/null
+++ b/src/tests/radsec/config-coa/main.conf.template
@@ -0,0 +1,37 @@
+listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-coa}}
+ virtual_server = coa
+}
+
+server coa {
+
+ authenticate {
+ Auth-Type PAP {
+ pap
+ }
+
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ Auth-Type EAP {
+ eap
+ }
+ }
+
+ recv-coa {
+ update request {
+ &Acct-Session-Id += "coa:recv-coa"
+ }
+ }
+
+ send-coa {
+ update reply {
+ &reply: += request:[*]
+ &reply:Acct-Session-Id += "coa:send-coa"
+ }
+ }
+}
+
diff --git a/src/tests/radsec/config-home/main.conf b/src/tests/radsec/config-home/main.conf
new file mode 100644
index 0000000..98966fd
--- /dev/null
+++ b/src/tests/radsec/config-home/main.conf
@@ -0,0 +1,322 @@
+listen {
+
+ ipaddr = 127.0.0.1
+ port = ${{port-home-auth}}
+ type = auth+coa
+ proto = tcp
+
+ virtual_server = default
+
+ clients = radsec
+
+ tls {
+ tls_max_version="1.2"
+ private_key_password = whatever
+ private_key_file = ${certdir}/server.pem
+ certificate_file = ${certdir}/server.pem
+ ca_file = ${cadir}/ca.pem
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ cipher_server_preference = no
+
+ cache {
+ enable = no
+ lifetime = 24 # hours
+ }
+
+ require_client_cert = yes
+ }
+
+ # Specify the CoA retransmit parameters for CoA single tunnel
+ coa {
+ irt = 1
+ mrt = 16
+ mrc = 0
+ mrd = 5
+ }
+}
+
+clients radsec {
+ client localhost {
+ ipaddr = 127.0.0.1
+ secret = radsec
+ proto = tls
+
+ limit {
+ max_connections = 16
+ lifetime = 0 # do not close connection
+ idle_timeout = 0 # do not close connection even after an idle period
+ }
+ }
+}
+
+server default {
+ authorize {
+ update control {
+ Originating-Realm-Key := &Called-Station-Id
+ Auth-Type := Accept
+ }
+ }
+
+ authenticate {
+ Auth-Type PAP {
+ pap
+ }
+
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ Auth-Type EAP {
+ eap
+ }
+ }
+
+ post-auth {
+ if(User-Name && User-Name == "PostAuthCoA") {
+ update coa {
+ &Acct-Session-Id += "default:post-auth"
+ &Proxy-To-Originating-Realm := &Called-Station-Id
+ }
+ }
+ }
+
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "default:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-coa-ack"
+ }
+ }
+
+ case CoA-NAK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-coa-nak"
+ }
+ }
+
+ case Disconnect-ACK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-disconnect-ack"
+ }
+ }
+
+ case Disconnect-NAK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-disconnect-nak"
+ }
+ }
+
+ case {
+ fail
+ }
+ }
+
+ # If there was no response at all
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+
+ detail_test.post-proxy
+ }
+}
+
+#
+# CoA Relay
+#
+listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-home-coa}}
+ virtual_server = coa
+}
+
+server coa {
+ recv-coa {
+
+ update request {
+ COA-Packet-Type := "%{Packet-Type}"
+ }
+
+ if(&User-Name == "TcpSessionKey-Proxy") {
+ # Proxying CoA
+ update control {
+ &Proxy-To-Originating-Realm := &Called-Station-Id
+ }
+ } else {
+ # Originating CoA
+ detail_coa.accounting
+ }
+ }
+}
+
+server coa-buffered-reader {
+ listen {
+ type = detail
+ filename = "${radacctdir}/detail_coa"
+ load_factor = 90
+ track = yes
+ }
+
+ accounting {
+ switch &User-Name {
+ case "IpAddress" {
+ update {
+ coa:Packet-DST-IP-Address := &NAS-IP-Address
+ coa:Packet-DST-Port:= &Called-Station-Id
+ }
+ }
+ case "IpAddressSingleTunnel" {
+ update {
+ coa:Packet-DST-IP-Address := &NAS-IP-Address
+ }
+ }
+ case "HomePoolCoA" {
+ update {
+ coa:Home-Server-Pool := &Called-Station-Id
+ }
+ }
+ case "TcpSessionKey"{
+ update {
+ coa:Proxy-To-Originating-Realm := &Called-Station-Id
+ }
+ }
+ }
+
+ switch &COA-Packet-Type {
+ case "Disconnect-Request" {
+ update {
+ # Include given attributes
+ &disconnect: += request:[*]
+ &disconnect:Packet-DST-IP-Address := &COA-Packet-DST-IP-Address
+ &disconnect:Packet-DST-Port := &COA-Packet-DST-Port
+ &disconnect:Acct-Session-Id := &COA-Acct-Session-Id
+ &disconnect:Acct-Delay-Time !* ANY
+ }
+ }
+
+ case "CoA-Request" {
+ update {
+ &coa:Acct-Session-Id = "coa-buffered-reader:accounting:coa-request"
+ }
+ }
+ }
+ ok
+ } # accounting
+
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "coa-buffered-reader:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ update {
+ &proxy-reply:Acct-Session-Id += "coa-buffered-reader:post-proxy"
+ }
+ detail_test.post-proxy
+ }
+}
+
+server home-originate-coa-relay {
+
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "home-originate-coa-relay:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-coa-ack"
+ }
+ }
+
+ case CoA-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-coa-nak"
+ }
+ }
+
+ case Disconnect-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-disconnect-ack"
+ }
+ }
+
+ case Disconnect-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-disconnect-nak"
+ }
+ }
+
+ case {
+ fail
+ }
+ }
+
+ # If there was no response at all
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+
+ detail_test.post-proxy
+ }
+}
+
+home_server coa-nas {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-coa}} # A placeholder to be set in test makefile
+ secret = testing123
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+home_server_pool coa-nas {
+ type = fail-over
+ home_server = coa-nas
+ virtual_server = home-originate-coa-relay
+}
+
+home_server coa-nas-tls {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-proxy-coa}} # A placeholder to be set in test makefile
+ secret = testing123
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+home_server_pool coa-nas-tls {
+ type = fail-over
+ home_server = coa-nas-tls
+ virtual_server = home-originate-coa-relay
+}
diff --git a/src/tests/radsec/config-proxy/main.conf.template b/src/tests/radsec/config-proxy/main.conf.template
new file mode 100644
index 0000000..aa77835
--- /dev/null
+++ b/src/tests/radsec/config-proxy/main.conf.template
@@ -0,0 +1,207 @@
+server proxy-default {
+
+ listen {
+ type = auth+acct
+ ipaddr = 127.0.0.1
+ port = ${{port-proxy-auth}}
+ }
+
+ authorize {
+ update control {
+ &Proxy-To-Realm := "tls"
+ }
+ }
+
+ authenticate {
+ Auth-Type PAP {
+ pap
+ }
+
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ Auth-Type EAP {
+ eap
+ }
+ }
+
+ pre-proxy {
+ update {
+ &Acct-Session-Id += "proxy-default:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ update {
+ &Acct-Session-Id += "proxy-default:post-proxy"
+ }
+ detail_test.recv-coa
+ }
+
+ recv-coa {
+ update {
+ &Acct-Session-Id += "proxy-default:recv-coa"
+ }
+ detail_test.recv-coa
+ }
+
+ send-coa {
+ update {
+ &Acct-Session-Id += "proxy-default:send-coa"
+ }
+ }
+}
+
+server proxy-tls-default {
+
+ listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-proxy-coa}}
+ }
+
+ recv-coa {
+ update {
+ &control:Home-Server-Pool := coa-nas
+ &request:Acct-Session-Id += "proxy-tls-default:recv-coa"
+ }
+ }
+
+ send-coa {
+ update {
+ &reply:Acct-Session-Id += "proxy-tls-default:send-coa"
+ }
+ }
+}
+
+#
+# Proxy To CoA server
+#
+server proxy-originate-coa-relay {
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "proxy-originate-coa-relay:pre-proxy"
+ }
+ }
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-coa-ack"
+ }
+ }
+
+ case CoA-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-coa-nak"
+ }
+ }
+
+ case Disconnect-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-disconnect-ack"
+ }
+ }
+
+ case Disconnect-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-disconnect-nak"
+ }
+ }
+
+ case {
+ fail
+ }
+ }
+
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+ }
+}
+
+home_server coa-nas {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-coa}} # A placeholder to be set in test makefile
+ secret = testing123
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+home_server_pool coa-nas {
+ type = fail-over
+ home_server = coa-nas
+ virtual_server = proxy-originate-coa-relay
+}
+
+
+#
+# Proxy To RADSEC Home server
+#
+server coa_tls {
+ recv-coa {
+ update control {
+ &request:Acct-Session-Id += "coa_tls:recv-coa"
+ &Home-Server-Pool := coa-nas
+ }
+ }
+
+ # When a packet is sent, it is processed through the
+ # send-coa section. This applies to *both* CoA-Request and
+ # Disconnect-Request packets.
+ send-coa {
+ update control {
+ &reply:Acct-Session-Id += "coa_tls:send-coa"
+ }
+ }
+
+ # You can use pre-proxy and post-proxy sections here, too.
+ # They will be processed for sending && receiving proxy packets.
+}
+
+home_server tls {
+ ipaddr = 127.0.0.1
+ port = ${{port-home-auth}} # A placeholder to be set in test makefile
+ type = auth+acct+coa
+ secret = radsec
+ proto = tcp
+ status_check = none
+
+ tls {
+ tls_max_version="1.2"
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.key
+ certificate_file = ${certdir}/client.pem
+ ca_file = ${certdir}/ca.pem
+ random_file = /dev/urandom
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ }
+
+ recv_coa {
+ virtual_server = coa_tls
+ }
+}
+
+home_server_pool tls {
+ type = fail-over
+ home_server = tls
+ virtual_server = coa_tls
+}
+
+realm tls {
+ auth_pool = tls
+}
+
diff --git a/src/tests/radsec/runtest.sh b/src/tests/radsec/runtest.sh
new file mode 100755
index 0000000..811f6bb
--- /dev/null
+++ b/src/tests/radsec/runtest.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+#set -x
+
+: ${TYPE=auth}
+: ${TEST_NAME=1.basic-auth}
+: ${PORT=12340}
+: ${SECRET=testing123}
+
+cd $TEST_PATH
+
+BIN_PATH=../../../build/bin/local
+OUTPUT=radclient.log
+
+RES=result-$TEST_NAME.log
+
+clean() {
+ kill $tailcoa $tailhome $tailproxy 2>&1 > /dev/null
+ wait $tailcoa $tailhome $tailproxy 2>&1 > /dev/null # suppress terminated messages
+ echo "" > detail_test
+ rm ./$TEST_NAME.reply.tmp fr-*-$TEST_NAME.log fail ok $RES radclient.log 2>&1 > /dev/null
+}
+
+# Combine a list of several repeated attributes to a single attribute with delimeter:
+# This:
+# Acct-Session-Id = "coa-buffered-reader:accounting:coa-request"
+# Acct-Session-Id = "default:send-coa"
+# Become:
+# Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "default:send-coa"
+aggregate() {
+ sort -s -t= -k1,1 ./detail_test | awk -F= '
+ prev!=$1 && prev{
+ print prev FS val;
+ prev=val=""}
+ {
+ val=val?val OFS $2:$2;
+ prev=$1
+ }
+ END{
+ if(val){
+ print prev FS val}
+ }' >> $RES
+}
+
+echo "Running test: $TEST_NAME for port: $PORT type: $TYPE"
+
+clean
+
+tail -f fr-coa.log 2> /dev/null > fr-coa-$TEST_NAME.log &
+tailcoa=$(echo $!)
+tail -f fr-home.log 2> /dev/null > fr-home-$TEST_NAME.log &
+tailhome=$(echo $!)
+tail -f fr-proxy.log 2> /dev/null > fr-proxy-$TEST_NAME.log &
+tailproxy=$(echo $!)
+
+$BIN_PATH/radclient -f $TEST_NAME.request -xF -D ./ 127.0.0.1:$PORT $TYPE $SECRET 1> $OUTPUT
+
+# skip comments
+sed '/^\s*#/d' $TEST_NAME.reply > $TEST_NAME.reply.tmp
+
+# wait if needed
+delay=$(grep delay $TEST_NAME.reply.tmp | awk '{print $2}')
+sed '/delay/d' $TEST_NAME.reply.tmp > $TEST_NAME.reply.tmp
+sleep $delay 2>&1 > /dev/null
+
+cat radclient.log > $RES
+aggregate
+
+while read -r line; do
+ if ! grep "$line" $RES >/dev/null 2>&1; then
+ echo "This test failed!" >> fail
+ echo "Testing $TEST_NAME failed. Cannot find $line in $RES." > fail
+ fi
+done < $TEST_NAME.reply.tmp
+
+if [ ! -f fail ]; then echo "This test succeded!" >> ok; fi
+
+mkdir $TEST_NAME.result 2>&1 > /dev/null
+cp ./$TEST_NAME.reply.tmp fr-*-$TEST_NAME.log fail ok \
+ $RES radclient.log detail_test $TEST_NAME.result 2>&1 > /dev/null
+
+clean
+
+test -f $TEST_NAME.result/ok # exit with the status code