diff --git a/netjsonconfig/backends/openwrt/converters/wireless.py b/netjsonconfig/backends/openwrt/converters/wireless.py index 66b365352..6679c39fd 100644 --- a/netjsonconfig/backends/openwrt/converters/wireless.py +++ b/netjsonconfig/backends/openwrt/converters/wireless.py @@ -110,7 +110,7 @@ def __intermediate_encryption(self, wireless): return {'encryption': 'none'} # otherwise configure encryption uci = encryption.copy() - for option in ['protocol', 'key', 'cipher', 'disabled']: + for option in ['protocol', 'key', 'cipher', 'disabled', 'acct_server_port']: if option in uci: del uci[option] protocol = encryption['protocol'] @@ -124,15 +124,8 @@ def __intermediate_encryption(self, wireless): if protocol == 'wep_open': uci['key1'] = 's:{0}'.format(uci['key1']) else: - if ( - 'enterprise' in protocol - and 'eap_type' in uci - and uci['eap_type'] == 'tls' - and 'auth' in uci - ): - # remove auth if not needed - # (not applicable to EAP-TLS) - del uci['auth'] + if 'enterprise' in protocol: + self.__intermediate_encryption_wpa_enterprise(wireless, encryption, uci) if 'key' in encryption: uci['key'] = encryption['key'] # add ciphers @@ -141,6 +134,21 @@ def __intermediate_encryption(self, wireless): uci['encryption'] += '+{0}'.format(cipher) return uci + def __intermediate_encryption_wpa_enterprise(self, wireless, encryption, uci): + if 'eap_type' in uci and uci['eap_type'] == 'tls' and 'auth' in uci: + # remove auth if not needed + # (not applicable to EAP-TLS) + del uci['auth'] + if wireless['mode'] == 'ap': + for option in ['server', 'port']: + if option in encryption: + uci[f'auth_{option}'] = encryption[option] + uci['auth_secret'] = encryption['key'] + if 'acct_secret' not in encryption: + uci['acct_secret'] = encryption['key'] + if 'acct_server_port' in encryption: + uci['acct_port'] = encryption.pop('acct_server_port') + roaming_properties = ( 'ft_over_ds', 'ft_psk_generate_local', @@ -251,6 +259,8 @@ def __netjson_wifi_typecast(self, wifi): 'auth_cache', 'acct_port', 'acct_server', + 'acct_secret', + 'acct_interval', 'nasid', 'ownip', 'dae_client', @@ -325,6 +335,18 @@ def __netjson_encryption(self, wifi): # noqa: C901 if key.startswith('s:'): key = key[2:] settings['key'] = key + if 'enterprise' in settings['protocol']: + if 'auth_secret' in settings: + settings['key'] = settings.pop('auth_secret') + if 'acct_secret' in settings and settings['acct_secret'] == settings.get( + 'key' + ): + settings.pop('acct_secret') + for option in ['server', 'port']: + if f'auth_{option}' in settings: + settings[option] = settings.pop(f'auth_{option}') + if 'acct_port' in settings: + settings['acct_server_port'] = settings.pop('acct_port') # Management Frame Protection if 'ieee80211w' in wifi: settings['ieee80211w'] = wifi.pop('ieee80211w') @@ -335,8 +357,12 @@ def __netjson_encryption_typecast(self, encryption): # type casting if 'port' in encryption: encryption['port'] = int(encryption['port']) - if 'acct_port' in encryption: - encryption['acct_port'] = int(encryption['acct_port']) + if 'acct_server_port' in encryption: + encryption['acct_server_port'] = int(encryption['acct_server_port']) + if 'dae_port' in encryption: + encryption['dae_port'] = int(encryption['dae_port']) + if 'acct_interval' in encryption: + encryption['acct_interval'] = int(encryption['acct_interval']) if 'wps_label' in encryption: encryption['wps_label'] = encryption['wps_label'] == '1' if 'wps_pushbutton' in encryption: diff --git a/netjsonconfig/backends/openwrt/schema.py b/netjsonconfig/backends/openwrt/schema.py index 32111cee7..b7efb0c76 100644 --- a/netjsonconfig/backends/openwrt/schema.py +++ b/netjsonconfig/backends/openwrt/schema.py @@ -704,6 +704,50 @@ {"$ref": "#/definitions/radio_60g_band"}, ] }, + "encryption_wpa_enterprise_ap_base_settings": { + "properties": { + "acct_secret": { + "title": "accounting shared secret", + "type": "string", + "propertyOrder": 9, + }, + "acct_interval": { + "type": "integer", + "title": "accounting interval", + "default": 600, + "propertyOrder": 10, + }, + "dae_client": { + "title": "DAE client", + "type": "string", + "description": ( + "Dynamic Authorization Extension client." + " This client can send \"Disconnect-Request\"" + " or \"CoA-Request\" packets to forcibly disconnect a client" + " or change connection parameters." + ), + "propertyOrder": 11, + }, + "dae_port": { + "type": "integer", + "title": "DAE port", + # "description": "port the Dynamic Authorization Extension server listens on.", + "default": 3799, + "propertyOrder": 12, + }, + "dae_secret": { + "title": "DAE secret", + "type": "string", + "propertyOrder": 13, + }, + "nasid": { + "title": "NAS ID", + "type": "string", + "description": "NAS ID for RADIUS authentication requests", + "propertyOrder": 13, + }, + } + }, }, "properties": { "general": { diff --git a/tests/openwrt/test_encryption.py b/tests/openwrt/test_encryption.py index aeaa25490..ff81110ee 100644 --- a/tests/openwrt/test_encryption.py +++ b/tests/openwrt/test_encryption.py @@ -288,6 +288,9 @@ def test_parse_wpa_personal(self): package wireless config wifi-iface 'wifi_wlan0' + option acct_secret 'radius_secret' + option auth_secret 'radius_secret' + option auth_server '192.168.0.1' option device 'radio0' option encryption 'wpa3-mixed+ccmp' option ieee80211w '1' @@ -324,7 +327,11 @@ def test_parse_wpa2_enterprise_mixed_ap(self): "server": "192.168.0.1", "port": 1812, "acct_server": "192.168.0.2", - "acct_port": 1813, + "acct_server_port": 1813, + "acct_interval": 300, + "dae_client": "192.168.0.2", + "dae_port": 3799, + "dae_secret": "radius_secret", "nasid": "2", "wpa_group_rekey": "350", "ieee80211w": "2", @@ -345,8 +352,16 @@ def test_parse_wpa2_enterprise_mixed_ap(self): package wireless config wifi-iface 'wifi_wlan0' + option acct_interval '300' option acct_port '1813' + option acct_secret 'radius_secret' option acct_server '192.168.0.2' + option auth_port '1812' + option auth_secret 'radius_secret' + option auth_server '192.168.0.1' + option dae_client '192.168.0.2' + option dae_port '3799' + option dae_secret 'radius_secret' option device 'radio0' option encryption 'wpa3+ccmp' option ieee80211w '2' @@ -386,7 +401,7 @@ def test_parse_wpa3_enterprise(self): "server": "192.168.0.1", "port": 1812, "acct_server": "192.168.0.2", - "acct_port": 1813, + "acct_server_port": 1813, "nasid": "2", "wpa_group_rekey": "350", }, @@ -407,7 +422,11 @@ def test_parse_wpa3_enterprise(self): config wifi-iface 'wifi_wlan0' option acct_port '1813' + option acct_secret 'radius_secret' option acct_server '192.168.0.2' + option auth_port '1812' + option auth_secret 'radius_secret' + option auth_server '192.168.0.1' option device 'radio0' option encryption 'wpa2+tkip' option ifname 'wlan0' @@ -461,6 +480,9 @@ def test_parse_wpa2_enterprise(self): package wireless config wifi-iface 'wifi_wlan0' + option acct_secret 'radius_secret' + option auth_secret 'radius_secret' + option auth_server '192.168.0.1' option device 'radio0' option encryption 'wpa-mixed' option ifname 'wlan0' @@ -511,6 +533,9 @@ def test_parse_wpa_enterprise_mixed_ap(self): package wireless config wifi-iface 'wifi_wlan0' + option acct_secret 'radius_secret' + option auth_secret 'radius_secret' + option auth_server '192.168.0.1' option device 'radio0' option encryption 'wpa+ccmp' option ifname 'wlan0'