diff --git a/renderer/templates/services/radius_proxy.uc b/renderer/templates/services/radius_proxy.uc new file mode 100644 index 0000000..150b220 --- /dev/null +++ b/renderer/templates/services/radius_proxy.uc @@ -0,0 +1,39 @@ +{% + if (!radius_proxy.host || !radius_proxy.port || !radius_proxy.secret) { + warn("Can't start radius-proxy due to missing settings."); + + return; + } +%} + +add radsecproxy options +add_list radsecproxy.@options[-1].ListenUDP='localhost:1812' +add_list radsecproxy.@options[-1].ListenUDP='localhost:1813' + +add radsecproxy client +set radsecproxy.@client[-1].name='client' +set radsecproxy.@client[-1].host='localhost' +set radsecproxy.@client[-1].type='udp' +set radsecproxy.@client[-1].secret='secret' + +add radsecproxy tls +set radsecproxy.@tls[-1].name='tls' +set radsecproxy.@tls[-1].CACertificateFile='/etc/ucentral/cas.pem' +set radsecproxy.@tls[-1].certificateFile='/etc/ucentral/cert.pem' +set radsecproxy.@tls[-1].certificateKeyFile='/etc/ucentral/cert.key' +set radsecproxy.@tls[-1].certificateKeyPassword='' + +add radsecproxy server +set radsecproxy.@server[-1].name='server' +set radsecproxy.@server[-1].host={{ s(radius_proxy.host) }} +set radsecproxy.@server[-1].port='{{ radius_proxy.port }}' +set radsecproxy.@server[-1].secret={{ s(radius_proxy.secret) }} +set radsecproxy.@server[-1].type='tls' +set radsecproxy.@server[-1].tls='tls' +set radsecproxy.@server[-1].statusServer='0' +set radsecproxy.@server[-1].certificateNameCheck='0' + +add radsecproxy realm +set radsecproxy.@realm[-1].name='*' +set radsecproxy.@realm[-1].server='server' +set radsecproxy.@realm[-1].accountingServer='server' diff --git a/schema/service.radius-proxy.yml b/schema/service.radius-proxy.yml new file mode 100644 index 0000000..c6d4614 --- /dev/null +++ b/schema/service.radius-proxy.yml @@ -0,0 +1,22 @@ +description: + This section can be used to setup a radius security proxy instance (radsecproxy). +type: object +required: [ "host", "port", "secret" ] +properties: + host: + description: + The remote proxy server that the device shall connect to. + type: string + format: uc-host + examples: + - 192.168.1.10 + port: + description: + The remote proxy port that the device shall connect to. + type: integer + maximum: 65535 + default: 2083 + secret: + description: + The radius secret that will be used for the connection. + type: string diff --git a/schema/service.yml b/schema/service.yml index e52c31e..d1e3d1b 100644 --- a/schema/service.yml +++ b/schema/service.yml @@ -21,5 +21,7 @@ properties: $ref: "https://ucentral.io/schema/v1/service/igmp/" ieee8021x: $ref: "https://ucentral.io/schema/v1/service/ieee8021x/" + radius-proxy: + $ref: "https://ucentral.io/schema/v1/service/radius-proxy/" wifi-steering: $ref: "https://ucentral.io/schema/v1/service/wifi-steering/" diff --git a/schemareader.uc b/schemareader.uc index c7a8ee0..e15ca91 100644 --- a/schemareader.uc +++ b/schemareader.uc @@ -3444,6 +3444,73 @@ function instantiateServiceIeee8021x(location, value, errors) { return value; } +function instantiateServiceRadiusProxy(location, value, errors) { + if (type(value) == "object") { + let obj = {}; + + function parseHost(location, value, errors) { + if (type(value) == "string") { + if (!matchUcHost(value)) + push(errors, [ location, "must be a valid hostname or IP address" ]); + + } + + if (type(value) != "string") + push(errors, [ location, "must be of type string" ]); + + return value; + } + + if (exists(value, "host")) { + obj.host = parseHost(location + "/host", value["host"], errors); + } + else { + push(errors, [ location, "is required" ]); + } + + function parsePort(location, value, errors) { + if (type(value) in [ "int", "double" ]) { + if (value > 65535) + push(errors, [ location, "must be lower than or equal to 65535" ]); + + } + + if (type(value) != "int") + push(errors, [ location, "must be of type integer" ]); + + return value; + } + + if (exists(value, "port")) { + obj.port = parsePort(location + "/port", value["port"], errors); + } + else { + obj.port = 2083; + } + + function parseSecret(location, value, errors) { + if (type(value) != "string") + push(errors, [ location, "must be of type string" ]); + + return value; + } + + if (exists(value, "secret")) { + obj.secret = parseSecret(location + "/secret", value["secret"], errors); + } + else { + push(errors, [ location, "is required" ]); + } + + return obj; + } + + if (type(value) != "object") + push(errors, [ location, "must be of type object" ]); + + return value; +} + function instantiateServiceWifiSteering(location, value, errors) { if (type(value) == "object") { let obj = {}; @@ -3595,6 +3662,10 @@ function instantiateService(location, value, errors) { obj.ieee8021x = instantiateServiceIeee8021x(location + "/ieee8021x", value["ieee8021x"], errors); } + if (exists(value, "radius-proxy")) { + obj.radius_proxy = instantiateServiceRadiusProxy(location + "/radius-proxy", value["radius-proxy"], errors); + } + if (exists(value, "wifi-steering")) { obj.wifi_steering = instantiateServiceWifiSteering(location + "/wifi-steering", value["wifi-steering"], errors); } diff --git a/ucentral.schema.json b/ucentral.schema.json index e7b3b41..3de6cf1 100644 --- a/ucentral.schema.json +++ b/ucentral.schema.json @@ -1347,6 +1347,31 @@ } } }, + "service.radius-proxy": { + "type": "object", + "required": [ + "host", + "port", + "secret" + ], + "properties": { + "host": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "port": { + "type": "integer", + "maximum": 65535, + "default": 2083 + }, + "secret": { + "type": "string" + } + } + }, "service.wifi-steering": { "type": "object", "properties": { @@ -1416,6 +1441,9 @@ "ieee8021x": { "$ref": "#/$defs/service.ieee8021x" }, + "radius-proxy": { + "$ref": "#/$defs/service.radius-proxy" + }, "wifi-steering": { "$ref": "#/$defs/service.wifi-steering" }