]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
tests for radsec
authorVadim Cargatser <vcargats@cisco.com>
Thu, 1 Apr 2021 20:04:11 +0000 (16:04 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 22 Jul 2021 13:55:21 +0000 (09:55 -0400)
22 files changed:
src/tests/radsec/.gitignore [new file with mode: 0644]
src/tests/radsec/1.basic-auth.reply [new file with mode: 0644]
src/tests/radsec/1.basic-auth.request [new file with mode: 0644]
src/tests/radsec/2.ipaddrtls-coa.reply [new file with mode: 0644]
src/tests/radsec/2.ipaddrtls-coa.request [new file with mode: 0644]
src/tests/radsec/3.homepooludp-coa.reply [new file with mode: 0644]
src/tests/radsec/3.homepooludp-coa.request [new file with mode: 0644]
src/tests/radsec/4.homepooltls-coa.reply [new file with mode: 0644]
src/tests/radsec/4.homepooltls-coa.request [new file with mode: 0644]
src/tests/radsec/5.singletunnel_ipaddr-coa.reply [new file with mode: 0644]
src/tests/radsec/5.singletunnel_ipaddr-coa.request [new file with mode: 0644]
src/tests/radsec/6.singletunnel_key-coa.reply [new file with mode: 0644]
src/tests/radsec/6.singletunnel_key-coa.request [new file with mode: 0644]
src/tests/radsec/7.coareply-auth.reply [new file with mode: 0644]
src/tests/radsec/7.coareply-auth.request [new file with mode: 0644]
src/tests/radsec/Makefile [new file with mode: 0644]
src/tests/radsec/README.rst [new file with mode: 0644]
src/tests/radsec/all.mk [new file with mode: 0644]
src/tests/radsec/config-coa/main.conf.template [new file with mode: 0644]
src/tests/radsec/config-home/main.conf [new file with mode: 0644]
src/tests/radsec/config-proxy/main.conf.template [new file with mode: 0644]
src/tests/radsec/runtest.sh [new file with mode: 0755]

diff --git a/src/tests/radsec/.gitignore b/src/tests/radsec/.gitignore
new file mode 100644 (file)
index 0000000..9daa835
--- /dev/null
@@ -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 (file)
index 0000000..77aa6b1
--- /dev/null
@@ -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 (file)
index 0000000..a6ddb8e
--- /dev/null
@@ -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.ipaddrtls-coa.reply b/src/tests/radsec/2.ipaddrtls-coa.reply
new file mode 100644 (file)
index 0000000..8ea0bfd
--- /dev/null
@@ -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.ipaddrtls-coa.request b/src/tests/radsec/2.ipaddrtls-coa.request
new file mode 100644 (file)
index 0000000..9d3f5eb
--- /dev/null
@@ -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 (file)
index 0000000..ab9f0a1
--- /dev/null
@@ -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 (file)
index 0000000..e3bff09
--- /dev/null
@@ -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 (file)
index 0000000..4666894
--- /dev/null
@@ -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 (file)
index 0000000..7038e25
--- /dev/null
@@ -0,0 +1,2 @@
+User-Name = "HomePoolCoA",
+Called-Station-Id = "coa-nas-tls"
diff --git a/src/tests/radsec/5.singletunnel_ipaddr-coa.reply b/src/tests/radsec/5.singletunnel_ipaddr-coa.reply
new file mode 100644 (file)
index 0000000..6a242b0
--- /dev/null
@@ -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/5.singletunnel_ipaddr-coa.request b/src/tests/radsec/5.singletunnel_ipaddr-coa.request
new file mode 100644 (file)
index 0000000..0a61194
--- /dev/null
@@ -0,0 +1,2 @@
+User-Name = "IpAddressSingleTunnel",
+NAS-IP-Address = "127.0.0.1",
diff --git a/src/tests/radsec/6.singletunnel_key-coa.reply b/src/tests/radsec/6.singletunnel_key-coa.reply
new file mode 100644 (file)
index 0000000..6a242b0
--- /dev/null
@@ -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_key-coa.request b/src/tests/radsec/6.singletunnel_key-coa.request
new file mode 100644 (file)
index 0000000..a838730
--- /dev/null
@@ -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 (file)
index 0000000..62e680e
--- /dev/null
@@ -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 (file)
index 0000000..0e3d5af
--- /dev/null
@@ -0,0 +1 @@
+User-Name = "PostAuthCoA",
diff --git a/src/tests/radsec/Makefile b/src/tests/radsec/Makefile
new file mode 100644 (file)
index 0000000..d732b29
--- /dev/null
@@ -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 (file)
index 0000000..c21ee4a
--- /dev/null
@@ -0,0 +1,100 @@
+=======================
+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.
+
+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 (file)
index 0000000..1d6140e
--- /dev/null
@@ -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 (file)
index 0000000..5baf4b7
--- /dev/null
@@ -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 (file)
index 0000000..9a52cf6
--- /dev/null
@@ -0,0 +1,312 @@
+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
+               dh_file = ${certdir}/dh
+               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"
+                       }
+               }
+       }
+
+       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}"
+               }
+               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:Originating-Realm-Key := &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 (file)
index 0000000..e4ee7df
--- /dev/null
@@ -0,0 +1,208 @@
+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
+               dh_file = ${certdir}/dh
+               random_file = /dev/urandom
+               fragment_size = 8192
+               ca_path = ${cadir}
+               cipher_list = "DEFAULT"
+       }
+
+       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 (executable)
index 0000000..3fef2fb
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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
+
+delay=$(grep delay $TEST_NAME.reply | awk '{print $2}')
+
+sed '/delay/d' $TEST_NAME.reply > $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