From e61f7abdb2136d8dfbf73729dbc14c3b5ab2ecba Mon Sep 17 00:00:00 2001 From: Jamie Austin Date: Fri, 27 Jan 2023 17:32:29 +1100 Subject: T4958: ocserv: openconnect: adds support for configuring RADIUS accounting Adds CLI configuration options to configure RADIUS accounting for OpenConnect VPN sessions. This functionality cannot be used outside of the RADIUS OpenConnect VPN authentication mode --- src/conf_mode/vpn_openconnect.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py index 57eba17b0..12ddac23c 100755 --- a/src/conf_mode/vpn_openconnect.py +++ b/src/conf_mode/vpn_openconnect.py @@ -121,6 +121,14 @@ def verify(ocserv): not is_listen_port_bind_service(int(port), 'ocserv-main'): raise ConfigError(f'"{proto}" port "{port}" is used by another service') + # Check accounting + if "accounting" in ocserv: + if "mode" in ocserv["accounting"] and "radius" in ocserv["accounting"]["mode"]: + if "authentication" not in ocserv or "mode" not in ocserv["authentication"]: + raise ConfigError('Accounting depends on OpenConnect authentication configuration') + elif "radius" not in ocserv["authentication"]["mode"]: + raise ConfigError('RADIUS accounting must be used with RADIUS authentication') + # Check authentication if "authentication" in ocserv: if "mode" in ocserv["authentication"]: @@ -202,10 +210,20 @@ def generate(ocserv): return None if "radius" in ocserv["authentication"]["mode"]: - # Render radius client configuration - render(radius_cfg, 'ocserv/radius_conf.j2', ocserv["authentication"]["radius"]) - # Render radius servers - render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"]) + if "accounting" in ocserv and "mode" in ocserv["accounting"] and "radius" in ocserv["accounting"]["mode"]: + acct_and_auth_config = {'accounting': ocserv["accounting"], 'authentication': ocserv["authentication"]} + # Render radius client configuration + render(radius_cfg, 'ocserv/radius_conf.j2', acct_and_auth_config) + merged_servers = ocserv["accounting"]["radius"]["server"] | ocserv["authentication"]["radius"]["server"] + # Render radius servers + # Merge the accounting and authentication servers into a single dictionary + render(radius_servers, 'ocserv/radius_servers.j2', {'server': merged_servers}) + else: + acct_and_auth_config = {'accounting': {'mode': ''}, 'authentication': ocserv['authentication']} + # Render radius client configuration + render(radius_cfg, 'ocserv/radius_conf.j2', acct_and_auth_config) + # Render radius servers + render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"]) elif "local" in ocserv["authentication"]["mode"]: # if mode "OTP", generate OTP users file parameters if "otp" in ocserv["authentication"]["mode"]["local"]: -- cgit v1.2.3 From 9db8c197ab170d18a93d70fca4227e802a7154c1 Mon Sep 17 00:00:00 2001 From: Jamie Austin Date: Sat, 28 Jan 2023 01:13:25 +1100 Subject: T4958: ocserv: openconnect: refactor RADIUS accounting support --- data/templates/ocserv/ocserv_config.j2 | 2 +- data/templates/ocserv/radius_conf.j2 | 24 ++++++++++-------------- src/conf_mode/vpn_openconnect.py | 8 +++----- 3 files changed, 14 insertions(+), 20 deletions(-) (limited to 'src/conf_mode') diff --git a/data/templates/ocserv/ocserv_config.j2 b/data/templates/ocserv/ocserv_config.j2 index aa8897703..aa1073bca 100644 --- a/data/templates/ocserv/ocserv_config.j2 +++ b/data/templates/ocserv/ocserv_config.j2 @@ -10,7 +10,7 @@ udp-port = {{ listen_ports.udp }} run-as-user = nobody run-as-group = daemon -{% if "radius" in accounting.mode %} +{% if accounting.mode.radius is vyos_defined %} acct = "radius [config=/run/ocserv/radiusclient.conf]" {% endif %} diff --git a/data/templates/ocserv/radius_conf.j2 b/data/templates/ocserv/radius_conf.j2 index 65548e3ad..1ab322f69 100644 --- a/data/templates/ocserv/radius_conf.j2 +++ b/data/templates/ocserv/radius_conf.j2 @@ -2,27 +2,23 @@ nas-identifier VyOS #### Accounting -{% if "radius" in accounting['mode'] %} -{% for acctsrv in accounting['radius']['server'] %} -{% if not "disable" in accounting['radius']['server'][acctsrv] %} -{% if "port" in accounting['radius']['server'][acctsrv] %} -acctserver {{ acctsrv }}:{{ accounting['radius']['server'][acctsrv]['port'] }} -{% else %} +{% if accounting.mode.radius is vyos_defined %} +{% for acctsrv, srv_conf in accounting.radius.server.items() if 'disable' not in srv_conf %} +{% if srv_conf.port is vyos_defined %} +acctserver {{ acctsrv }}:{{ srv_conf.port }} +{% else %} acctserver {{ acctsrv }} -{% endif %} {% endif %} {% endfor %} {% endif %} #### Authentication -{% if "radius" in authentication['mode'] %} -{% for authsrv in authentication['radius']['server'] %} -{% if not "disable" in authentication['radius']['server'][authsrv] %} -{% if "port" in authentication['radius']['server'][authsrv] %} -authserver {{ authsrv }}:{{ authentication['radius']['server'][authsrv]['port'] }} -{% else %} +{% if authentication.mode.radius is vyos_defined %} +{% for authsrv, srv_conf in authentication.radius.server.items() if 'disable' not in srv_conf %} +{% if srv_conf.port is vyos_defined %} +authserver {{ authsrv }}:{{ srv_conf.port }} +{% else %} authserver {{ authsrv }} -{% endif %} {% endif %} {% endfor %} radius_timeout {{ authentication['radius']['timeout'] }} diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py index 12ddac23c..737e23145 100755 --- a/src/conf_mode/vpn_openconnect.py +++ b/src/conf_mode/vpn_openconnect.py @@ -210,18 +210,16 @@ def generate(ocserv): return None if "radius" in ocserv["authentication"]["mode"]: - if "accounting" in ocserv and "mode" in ocserv["accounting"] and "radius" in ocserv["accounting"]["mode"]: - acct_and_auth_config = {'accounting': ocserv["accounting"], 'authentication': ocserv["authentication"]} + if dict_search(ocserv, 'accounting.mode.radius'): # Render radius client configuration - render(radius_cfg, 'ocserv/radius_conf.j2', acct_and_auth_config) + render(radius_cfg, 'ocserv/radius_conf.j2', ocserv) merged_servers = ocserv["accounting"]["radius"]["server"] | ocserv["authentication"]["radius"]["server"] # Render radius servers # Merge the accounting and authentication servers into a single dictionary render(radius_servers, 'ocserv/radius_servers.j2', {'server': merged_servers}) else: - acct_and_auth_config = {'accounting': {'mode': ''}, 'authentication': ocserv['authentication']} # Render radius client configuration - render(radius_cfg, 'ocserv/radius_conf.j2', acct_and_auth_config) + render(radius_cfg, 'ocserv/radius_conf.j2', ocserv) # Render radius servers render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"]) elif "local" in ocserv["authentication"]["mode"]: -- cgit v1.2.3 From 9321e75d1edbffe10b6194062c6fad7cbf205e3e Mon Sep 17 00:00:00 2001 From: Jamie Austin Date: Sat, 28 Jan 2023 15:26:53 +1100 Subject: openconnect: T4955: Removed wrong acctserver in radiusclient.conf Removes port key from accounting server merged config dictionary. --- src/conf_mode/vpn_openconnect.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py index 737e23145..63ffe2a41 100755 --- a/src/conf_mode/vpn_openconnect.py +++ b/src/conf_mode/vpn_openconnect.py @@ -82,13 +82,26 @@ def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict: del origin['authentication']['radius']['server']['port'] if not origin["authentication"]['radius']['server']: raise ConfigError( - 'Openconnect mode radius required at least one radius server') + 'Openconnect authentication mode radius required at least one radius server') default_values_radius_port = \ default_values['authentication']['radius']['server']['port'] for server, params in origin['authentication']['radius'][ 'server'].items(): if 'port' not in params: params['port'] = default_values_radius_port + + if 'mode' in origin["accounting"] and "radius" in \ + origin["accounting"]["mode"]: + del origin['accounting']['radius']['server']['port'] + if not origin["accounting"]['radius']['server']: + raise ConfigError( + 'Openconnect accounting mode radius required at least one radius server') + default_values_radius_port = \ + default_values['accounting']['radius']['server']['port'] + for server, params in origin['accounting']['radius'][ + 'server'].items(): + if 'port' not in params: + params['port'] = default_values_radius_port return origin -- cgit v1.2.3