Standardised JSON VP list format

Arran Cudbard-Bell a.cudbardb at freeradius.org
Tue Nov 8 17:04:28 CET 2011


On 8 Nov 2011, at 16:30, Brian Candler wrote:

> On Tue, Nov 08, 2011 at 01:32:12PM +0100, Arran Cudbard-Bell wrote:
>>   I'm proposing the following JSON structures for VP lists being sent
>>   from and parsed by FreeRADIUS. If anyone has any suggestions regarding
>>   other fields they'd like to see included, let me know.
> 
> I think we should keep it simple, and I would also like to see it
> symmetrical for data in and out of a module.
> 
> If a regular FreeRadius output has
> 
>    Service-Type = Framed-User
>    Framed-Protocol = PPP
> 
> then a starting point would be:
> 
> #1
>   {"Service-Type": "Framed-User",
>    "Framed-Protocol": "PPP"}
> 
> That is, I don't see a need to include an explicit Type, since the receiver
> will presumably have a dictionary;
> and the value can be whatever format is
> used when FreeRadius normally inputs or outputs a string of that type (e.g.
> radclient, rlm_sql etc)
> 
> Then there is the requirement for keeping ordering between repeated
> attributes.  Simple options like
> 
> #2
>   [{"Service-Type": "Framed-User"},
>    {"Framed-Protocol": "PPP"},
>    {"Reply-Message": "Foo"},
>    {"Reply-Message": "Bar"}]
> 
> #3
>   [["Service-Type": "Framed-User"],
>    ["Framed-Protocol": "PPP"],
>    ["Reply-Message": "Foo"],
>    ["Reply-Message": "Bar"]]
> 
> are direct but inconvenient when you want to look up the value for a
> particular attribute.  So I would go as you suggest:
> 
> #4
>   {"Service-Type":["Framed-User"],
>    "Framed-Protocol":["PPP"],
>    "Reply-Message":["Foo","Bar"]}
> 
> Aside: it would be convenient to permit modules which generate this format
> to be allowed to omit the [array] for single-valued attributes.  But the
> above would be the normalised form which FreeRadius itself would always
> generate.
> 
>>   Inbound (response):
> 
> RADIUS packets themselves of course don't include "+=" or ":=" or "=", but
> I guess this format needs to work for internal communication between modules
> and FR.
> 
> So there are several options I can think of:
> 
> #5 - Non-extensible
>  {"Service-Type": [{"+=": "Framed-User"}],
>   "Framed-Protocol": [{":=": "PPP"}]},
>   "Reply-Message": [{"+=": "Foo"}, {"+=": "Bar"}]}
> 
> #6 - Verbose but extensible
>  {"Service-Type": [{"op":"+=","value":"Framed-User"}],
>   "Framed-Protocol": [{"op":":=","value":"PPP"}]}
>   "Reply-Message": [{"op":"+=","value":"Foo"}, {"op":"+=","value":"Bar"}]}
> 
> 5 and 6 are butt-ugly and should be discounted for that reason alone.
> 
> #7 - Like #3 with third value. Missing third value implies "+="
> 
>  [["Service-Type", "Framed-User", "+="],
>   ["Framed-Protocol", "PPP", ":="],
>   ["Reply-Message", "Foo", "+="],
>   ["Reply-Message", "Bar", "+="]]
> 
> Easy to use when generating responses, but I hate the asymmetry with #4.
> 
> So how about including the update operator in the label?
> 
> #8
>  {"Service-Type+=": "Framed-User",
>   "Framed-Protocol:=": "PPP",
>   "Reply-Message+=": ["Foo","Bar"]}
> 
> So basically, "+=" would always add (and is perhaps the default?), ":="
> would always erase the list first and then add, and = would do nothing if
> the attribute already exists.  And so
> 
>  {"Reply-Message:=",[]}
> 
> could be used to remove an attribute; perhaps also value null could do that.
> 
> Finally, I'd also like to be able to update request/control/reply lists in
> one go, and the simplest way I can think of is:
> 
> #9
>  {"request:Huntgroup-Name:=", "Foo",
>   "reply:Framed-Protocol+=", "PPP"}
> 
> The list: prefix would be optional and could be implied from context
> normally (e.g. default to request: list for queries and reply: for
> responses)
> 
> Final idea: if you want the labels to be easier to parse, split them on a
> character which is unlikely to occur.
> 
> #10
>  {"request|Huntgroup-Name|:=", "Foo",
>   "reply|Framed-Protocol|+=", "PPP"}
> 
> Just a few random thoughts :-)
> 
> Regards,
> 
> Brian.
> -
> List info/subscribe/unsubscribe? See http://www.freeradius.org/list/devel.html
> 

Phew... Lots of feedback. Ok.

#1 It's useful for validation purposes, I agree, it's not strictly needed but I don't see the harm in it. I don't think servers will have dictionaries, but I think they'll probably know the types of  the attributes they're interested in

#2 Most JSON decoders don't support duplicate keys, which is the reason behind aggregating multiple values together in one declaration.

#3 Hmm, no, attribute names should be in a hash for easy and fast lookup by the receiver.

#4 Yes the original format with type removed, but this doesn't allow for tags. The standard is the standard, it makes it easier for the client to parse attributes and allows nested arrays to be used to specify more complex values. If you made the outer array optional, you couldn't have nested arrays.

#5, #6 Json-C does support iterating over hash keys so the duplicate keys are not an issue for received data. Using objects in values to specify operators breaks support for nested VPs. I actually like the fact that there's a single op for a collection of values, it makes it really easy to write filters based on -= and the regex ops.

For rlm_rest I added some special behaviour for := and = where it'll automatically switch to += after the first value in the list has been processed, this behaviour should be specified somewhere.

#7 I guess there's no need for hash based lookups on the server... Possibly.

#8 #9 Difficult to parse and a little fuggly

#10 Yes in theory it does help if they're trying to do handcrafted JSON responses. Maybe support both? Just substitute pipes for colons in the name. Of course if they're trying to return text strings with commas they're going to run into the same issues ;)

-Arran


Arran Cudbard-Bell
a.cudbardb at networkradius.com

Technical consultant and solutions architect

15 Ave. du Granier, Meylan, France
+33 4 69 66 54 50









More information about the Freeradius-Devel mailing list