Proposed behaviour for rlm_mruby (which might impact rlm_perl and rlm_python too)

Arran Cudbard-Bell a.cudbardb at freeradius.org
Sun Nov 27 18:11:59 CET 2016


> On 26 Nov 2016, at 15:04, Herwin Weststrate <herwin at quarantainenet.nl> wrote:
> 
> This weekend I've been trying to get some work done in this very old ticket[1] to remove rlm_ruby and replace it with rlm_mruby. mruby is a kind of minified ruby that is suitable for embedding in processes (as opposed to ruby, which does things like hooking its own signal handlers into freeradius). It was definitely an interesting experience, not in the least because documentation like this[2] is far from exceptional.
> 
> The code I currently have is feature complete[3], but during construction I thought of a few limitations that I would like to solve. This reminded me of the documented I wanted to write earlier this year about my vision on the rlm_language-modules, and how to solve the current problems.
> 
> There are currently 4 modules for scripting languages: rlm_perl, rlm_python, rlm_ruby and rlm_lua. I haven't looked at that last one,

Look at the last one :)

> I don't like any of these interfaces, so I'm trying to propose a new one. We could use that in every rlm_language-module, so switching between languages would be easier and functionality will be preserved.
> 
> Use an object for the input. This object has methods like request, reply and session_state to get the correct lists. This means no more globale variables (perl) and no excessive lists of argument (python, ruby).
> The result of these method calls would be objects too. These object have methods like get_attribute and get_attributes. The first one returns a scalar value, if there are multiple attributes it returns the first one, If there is no attribute, it does something that is expected in the language (perl and ruby would return a NULL-like value here, in python a KeyError would be more suiteable). The second method always returns a list, that might contain 0 or 1 elements. In the general case, people are only interested in the first value.
> Updates should be performed via those objects too, so we could use code like `control.set_attribute('Cleartext-Password', 'hello')`. This means we can update all lists from rlm_python/rlm_ruby as well, and we no longer have to remember in what order "control" and "reply" were.

Most languages allow you to catch modifications or calls/accesses to/of non-existent class properties/methods.  I know that's the case in ruby.  So in most languages you'd be able to implement a simplified interface with:

	control.foo_attribute = bar
	or bar = control.foo_attribute

For complex modifications something like control.get/set_attribute('Cleartext-Password', value) would definitely be useful, though for efficiency, set_attribute would need to be a polymorphic method to deal with the different value types.

i.e.

	set_attribute(string attribute, integer value)
	set_attribute(string attribute, string value)

The internal APIs and structures are significantly better than they were when the language modules were originally written, which means conversion from native language types to FR types without going through strings is often possible, even though it's not been implemented.

> One of the drawbacks of the current implementation is that a lot of attributes have to be copied from the request and converted into language-specific strings. It is not unlikely that we copy and convert a load of EAP-data, while the called script is only interested in the User-Name attribute. By converting everything to objects we can make these conversions on-demand, instead of doing everything up front.

Yes, it's awful.

> We might even want to skip the parameter to the methods, and just define an abstract base class that has to be subclassed in the script. The downside of this being that it would become hard to test the script without freeradius, because the base class has been implemented there. Then again, the same problem arises with the rest of this proposal.

Have you got an example of that?

One thing whilst your head is still in the mruby code... If you can run each of the requests inside their own fiber:

	https://github.com/mruby/mruby/blob/master/mrbgems/mruby-fiber/src/fiber.c

It would make scripts that can return control to the unlang interpreter whilst they wait on I/O events possible.

That's definitely the gold standard for language modules.

-Arran

Arran Cudbard-Bell <a.cudbardb at freeradius.org>
FreeRADIUS Development Team

FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2





More information about the Freeradius-Users mailing list