Integration GO language into Freeradius
Hi, Is there any plan to integrate GO language into the Freeradius server? Similar to rlm_perl or rlm_python. Thank you very much for the answer. Peter Balsianok
Is there any plan to integrate GO language into the Freeradius server? Similar to rlm_perl or rlm_python.
If it helps, since 2018 I've been using rlm_rest (https://networkradius.com/doc/current/raddb/mods-available/rest.html) with a Go program using the Gin web framework (https://github.com/gin-gonic/gin) for REST communication. It's allowed me to implement the custom logic I want/need in Go. I've integrated with pfSense, Avocent, Raritan, Ubiquiti, Cisco and Juniper. I'm not saying this is the best way to go, but using the REST module has allowed me to use the language I felt most comfortable with, which in this case was Go. -Martin
On 20.03.22 14:56, Martin Gignac wrote:
Is there any plan to integrate GO language into the Freeradius server? Similar to rlm_perl or rlm_python. If it helps, since 2018 I've been using rlm_rest (https://networkradius.com/doc/current/raddb/mods-available/rest.html) with a Go program using the Gin web framework (https://github.com/gin-gonic/gin) for REST communication. It's allowed me to implement the custom logic I want/need in Go. I've integrated with pfSense, Avocent, Raritan, Ubiquiti, Cisco and Juniper. I'm not saying this is the best way to go, but using the REST module has allowed me to use the language I felt most comfortable with, which in this case was Go.
-Martin - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Especially when the rest module will become better parsing the return data in FR version 4. Mit freundlichen Grüßen, -- [*] sys4 AG https://sys4.de, +49 (89) 30 90 46 64 Schleißheimer Straße 26/MG,80333 München Sitz der Gesellschaft: München, Amtsgericht München: HRB 199263 Vorstand: Patrick Ben Koetter, Marc Schiffbauer, Wolfgang Stief Aufsichtsratsvorsitzender: Florian Kirstein
On Mar 20, 2022, at 1:28 AM, Peter Balsianok <balsianok.peter@gmail.com> wrote:
Is there any plan to integrate GO language into the Freeradius server? Similar to rlm_perl or rlm_python.
I don't think it's very easy. That being said, if someone supplied patches, we'd be happy to add them in. But if there's plan for the core FR team to do it. We're trying to get v4 out, among other priorities. Alan DeKok.
On Mon, 21 Mar 2022 at 03:34, Alan DeKok <aland@deployingradius.com> wrote:
On Mar 20, 2022, at 1:28 AM, Peter Balsianok <balsianok.peter@gmail.com> wrote:
Is there any plan to integrate GO language into the Freeradius server? Similar to rlm_perl or rlm_python.
I don't think it's very easy.
Go can be complied into an executable so I would assume if the OP wanted to do it they could just use rlm_exec and do it that way. That being said, if someone supplied patches, we'd be happy to add them
in.
But if there's plan for the core FR team to do it. We're trying to get v4 out, among other priorities.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
Go can be complied into an executable so I would assume if the OP wanted to do it they could just use rlm_exec and do it that way.
That's true. I think I even went this route in the beginning, but ultimately opted from rlm_rest. The documentation for rlm_exec states that "This module is useful for gluing third-party programs into FreeRADIUS. However, executing programs is very slow. The exec module may look like it works for one or two tests, but in a live situation it can cause the server to become unresponsive under load. The perl module is recommended for general-purpose computing.", so I don't know how performant it is compared with rlm_rest. -Martin
Martin Gignac <martin.gignac@gmail.com> wrote:
The documentation for rlm_exec states that "This module is useful for gluing third-party programs into FreeRADIUS. However, executing programs is very slow. The exec module may look like it works for one or two tests, but in a live situation it can cause the server to become unresponsive under load. The perl module is recommended for general-purpose computing.", so I don't know how performant it is compared with rlm_rest.
rlm_perl uses a Perl ecosystem library which actually fires up a Perl interpreter and runs all it's init code until it is just about to start running a script, then freezes that state in memory ready to run code. It can then fork copies of that state off. That's why it is performant. You'd need to find something like that for GO... but if it is a compiled language that's less likely to exist since there is less need for that than there is for an interpreted language like Perl5. (Writing that makes me wonder if there would be a way to do a "pre_exec" on generic stuff run by rlm_exec, if the executed code was cooperative enough to wait on a socket after loading and before proceeding.)
On Mar 21, 2022, at 10:13 AM, Brian Julin <BJulin@clarku.edu> wrote:
(Writing that makes me wonder if there would be a way to do a "pre_exec" on generic stuff run by rlm_exec, if the executed code was cooperative enough to wait on a socket after loading and before proceeding.)
Sure. The "rlm_java" module did that back in the v2 days. It was removed was it was entirely unmaintained. :( TBH, any "pre-exec" thing would end up having to serialize attributes down a pipe, at which point it's starting to look like json + REST. It's likely better to re-use an existing ecosystem, instead of creating another one. Alan DeKok.
I have read documentation for rlm_rest. As I can see there is no possibility to process/manipulate the whole REQUEST ( in case the rlm_perl module is RLM_REQUEST ) attributes ( because the module sends only a limited attribute set via uri ). And I assume the rest module won't send any attribute CONFIG ( in case the rlm_perl mode is RLM_CONFIG ). Therefore this module I can use only for basic authentication, not for complex business logic. Peter Balsianok On Mon, Mar 21, 2022 at 4:20 PM Alan DeKok <aland@deployingradius.com> wrote:
On Mar 21, 2022, at 10:13 AM, Brian Julin <BJulin@clarku.edu> wrote:
(Writing that makes me wonder if there would be a way to do a "pre_exec" on generic stuff run by rlm_exec, if the executed code was cooperative enough to wait on a socket after loading and before proceeding.)
Sure. The "rlm_java" module did that back in the v2 days. It was removed was it was entirely unmaintained. :(
TBH, any "pre-exec" thing would end up having to serialize attributes down a pipe, at which point it's starting to look like json + REST. It's likely better to re-use an existing ecosystem, instead of creating another one.
Alan DeKok.
- List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html
On Mar 21, 2022, at 12:24 PM, Peter Balsianok <balsianok.peter@gmail.com> wrote:
I have read documentation for rlm_rest. As I can see there is no possibility to process/manipulate the whole REQUEST ( in case the rlm_perl module is RLM_REQUEST ) attributes ( because the module sends only a limited attribute set via uri ). And I assume the rest module won't send any attribute CONFIG ( in case the rlm_perl mode is RLM_CONFIG ). Therefore this module I can use only for basic authentication, not for complex business logic.
Source code is available. Patches are accepted. I would rather update rlm_rest, instead of adding a whole new thing which is specific to FreeRADIUS. Alan DeKok.
As I can see there is no possibility to process/manipulate the whole REQUEST ( in case the rlm_perl module is RLM_REQUEST ) attributes ( because the module sends only a limited attribute set via uri ). And I assume the rest module won't send any attribute CONFIG ( in case the rlm_perl mode is RLM_CONFIG ). Therefore this module I can use only for basic authentication, not for complex business logic.
You can modify the default rlm_rest config file (https://github.com/FreeRADIUS/freeradius-server/blob/master/raddb/mods-avail...) to use the POST method at the authenticate step to get attributes from the RADIUS request: authenticate { uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authenticate" method = 'post' body = 'post' tls = ${..tls} } Using Gin, you can extract the attributes of interest for later use in logic: r.POST("/user/:username/mac/*calledStationID?action=authenticate", func(c *gin.Context) { // Extract all of the expected data that FreeRADIUS sends username := c.PostForm("User-Name") password := c.PostForm("User-Password") callingStationID := c.PostForm("Calling-Station-Id") calledStationID := c.PostForm("Called-Station-Id") nasPortType := c.PostForm("NAS-Port-Type") nasPort := c.PostForm("NAS-Port") nasPortID := c.PostForm("NAS-Port-Id") nasIPAddress := c.PostForm("NAS-IP-Address") nasIdentifier := c.PostForm("NAS-Identifier")
On Mar 21, 2022, at 1:09 PM, Martin Gignac <martin.gignac@gmail.com> wrote:
As I can see there is no possibility to process/manipulate the whole REQUEST ( in case the rlm_perl module is RLM_REQUEST ) attributes ( because the module sends only a limited attribute set via uri ). And I assume the rest module won't send any attribute CONFIG ( in case the rlm_perl mode is RLM_CONFIG ). Therefore this module I can use only for basic authentication, not for complex business logic.
You can modify the default rlm_rest config file (https://github.com/FreeRADIUS/freeradius-server/blob/master/raddb/mods-avail...) to use the POST method at the authenticate step to get attributes from the RADIUS request:
authenticate { uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=authenticate" method = 'post' body = 'post' tls = ${..tls} }
Using Gin, you can extract the attributes of interest for later use in logic:
r.POST("/user/:username/mac/*calledStationID?action=authenticate", func(c *gin.Context) { // Extract all of the expected data that FreeRADIUS sends username := c.PostForm("User-Name") password := c.PostForm("User-Password") callingStationID := c.PostForm("Calling-Station-Id") calledStationID := c.PostForm("Called-Station-Id") nasPortType := c.PostForm("NAS-Port-Type") nasPort := c.PostForm("NAS-Port") nasPortID := c.PostForm("NAS-Port-Id") nasIPAddress := c.PostForm("NAS-IP-Address") nasIdentifier := c.PostForm("NAS-Identifier") -
Note sure what the issue here is with Go... You can already write FreeRADIUS modules in Go you just export the same symbols as one of the C modules. There's a Stack Overflow post https://stackoverflow.com/questions/32215509/using-go-code-in-an-existing-c-... here. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
On 21/03/2022 21:49, Arran Cudbard-Bell wrote:
On Mar 21, 2022, at 1:09 PM, Martin Gignac <martin.gignac@gmail.com> wrote:
As I can see there is no possibility to process/manipulate the whole REQUEST ( in case the rlm_perl module is RLM_REQUEST ) attributes ( because the module sends only a limited attribute set via uri ).
Note sure what the issue here is with Go... You can already write FreeRADIUS modules in Go you just export the same symbols as one of the C modules.
This sounds to me like another case of "just learn how to use unlang". In over a decade of building FreeRADIUS configs I have never used any of the scripting language modules. Unlang might not always be the prettiest, but it does work, and is pretty much going to be the fastest option. There may be a few unusual cases where something more flexible could possibly be justified (and unlang does fall slightly short in a few areas, occasionally requiring some "creative" config), but I've never found it hard enough to need to use something else. There's been too many cases where people have written configs in python or perl because that's what they're used to... and the result has been much simpler and faster once that's all ripped out and it's recreated in unlang. I really don't see adding yet another language much of a help. -- Matthew
On Mar 21, 2022, at 6:22 PM, Matthew Newton <mcn@freeradius.org> wrote:
In over a decade of building FreeRADIUS configs I have never used any of the scripting language modules. Unlang might not always be the prettiest, but it does work, and is pretty much going to be the fastest option.
My favorite is things like "write a Perl script which opens a connection to MySQL for every packet, and does one SQL query". Generally followed by "why is it so slow?" The server already has that functionality. It works, and it's fast.
There may be a few unusual cases where something more flexible could possibly be justified (and unlang does fall slightly short in a few areas, occasionally requiring some "creative" config), but I've never found it hard enough to need to use something else.
There's been too many cases where people have written configs in python or perl because that's what they're used to... and the result has been much simpler and faster once that's all ripped out and it's recreated in unlang. I really don't see adding yet another language much of a help.
I'm happy to look at patches, but you're right here. FreeRADIUS implements authentication protocols and database queries. It has just enough of a policy language to allow those two things to be "glued" together. Policies should NOT be written in a general-purpose programming language. If they are, odds are that the policies are way too complex, and/or re-implement things which are already in the server. In most cases, a good chunk of policy complexity is really *data* complexity. i.e. If you have 10 million users, you don't write a policy like: if (User-Name == "a") { ... get password for "a" } else if (User-Name == "b") { ... get password for "b" ... That's unmaintainable. Instead, put complexity into a database, with a good database schema. Most policies then become 2-3 database queries, and a tiny bit of logic around that. Alan DeKok.
On Mar 21, 2022, at 6:22 PM, Matthew Newton <mcn@freeradius.org> wrote:
On 21/03/2022 21:49, Arran Cudbard-Bell wrote:
On Mar 21, 2022, at 1:09 PM, Martin Gignac <martin.gignac@gmail.com> wrote:
As I can see there is no possibility to process/manipulate the whole REQUEST ( in case the rlm_perl module is RLM_REQUEST ) attributes ( because the module sends only a limited attribute set via uri ).
Not sure what the issue here is with Go... You can already write FreeRADIUS modules in Go you just export the same symbols as one of the C modules.
This sounds to me like another case of "just learn how to use unlang".
In over a decade of building FreeRADIUS configs I have never used any of the scripting language modules. Unlang might not always be the prettiest, but it does work, and is pretty much going to be the fastest option.
There may be a few unusual cases where something more flexible could possibly be justified (and unlang does fall slightly short in a few areas, occasionally requiring some "creative" config), but I've never found it hard enough to need to use something else.
There's been too many cases where people have written configs in python or perl because that's what they're used to... and the result has been much simpler and faster once that's all ripped out and it's recreated in unlang. I really don't see adding yet another language much of a help.
Especially with async in v4. Doing blocking I/O in a dynamic language becomes the quickest way to kill the performance of the server. If people really wanted to avoid REST it'd be fairly easy to make rlm_exec execute long running processes, especially since all the exec code in v4 is fully async (what a complete PITA that was). That'd avoid the overhead of starting up and shutting down processes every time a request came through. But then you need some awful hacked together pipe based FFI/CGI thing... and just... why... Every language has a lease one HTTP framework. Go probably has several hundred by this point. The REST support in v4 is much better. It's got one of the new style argument based xlats that allows custom bodies to be sent, and a JSON module that allows custom encoding of request, and parsing of responses. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS Development Team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
Arran wrote:
Especially with async in v4. Doing blocking I/O in a dynamic language becomes the quickest way to kill the performance of the server.
If people really wanted to avoid REST it'd be fairly easy to make rlm_exec execute long running processes, especially since all the exec code in v4 is fully async (what a complete PITA that was). That'd avoid the overhead of starting up and shutting down processes every time a request came through. But then you need some awful hacked together pipe based FFI/CGI thing... and just... why... Every language has a lease one HTTP framework. Go probably has several hundred by this point.
The REST support in v4 is much better. It's got one of the new style argument based xlats that allows custom bodies to be sent, and a JSON module that allows custom encoding of request, and parsing of responses.
Sounds good. I last looked at rlm_rest several years ago and it was tied in primarily to the auth/autx/etc stage model and not very useful for generic stuff. Primarily when I have used either rlm_exec or rlm_perl, it has been integration with other services like MFA or feeding data into security appliances. Mostly it has been no-wait stuff where we just need timely data to leave FreeRADIUS and kick off a sequence of events which involve interacting with rather complicated APIs. Something worth mentioning on the relative merits of unlang versus external scripts, is what happens on a HUP... IIRC for unlang and other configuration directives, only syntax/config nodes that change actually get touched, whereas an external script needs to be reread in its entirety and if it is carrying state, it will need to restore that somehow.
participants (8)
-
Alan DeKok -
Arran Cudbard-Bell -
Brian Julin -
Martin Gignac -
Matthew Newton -
Michael Schwartzkopff -
Peter Balsianok -
Peter Lambrechtsen