JSON Module
The json
module registers a map
function to allow mapping fields from
JSON structures to attributes. It also adds some xlats for processing and
generating JSON documents.
JSON 'map' function
The path through the JSON document’s tree is specified with FR jpath, which is the FreeRADIUS implementation of the jpath grammar described at http://goessner.net/articles/JsonPath/
Selectors currently implemented are:
Selector | Description |
---|---|
$ |
Root node (only valid at the start of the path). |
@ |
Current node (only valid at the start of the path). |
.<name> |
A field within an object. |
[<idx>] |
Index within an array. |
[<start>:<end>[:<step>]] |
A slice within an array (identical to the Python syntax). |
[<idx>,<start>:<end>] |
Multiple indexes/slices within an array. |
.* |
All the children of the current node. |
.. |
Recursive descent. |
|
Sample
Assuming that the URL http://example.org/api/user/$username replies with some JSON content as below.
{
"user": "bob",
"account number": 7124503,
"groups": [
"admin",
"networks",
"bob"
]
}
In this case, the rest
module can be used to get the JSON data and the
fields can be accessed using 'map' as shown in the example below.
map json "%rest(GET http://example.org/api/user/%{User-Name})" {
&Foo := '$.account number'
&Group += '$.groups.*'
}
Configuration Settings
The only options for the JSON module are to control the output
format of the json.encode
xlat.
- output_mode
-
set the format of JSON documenta that should be created. This may be one of:
-
object
-
object_simple
-
array
-
array_of_names
-
array_of_values
-
Examples of each format are given below.
Formatting options for attribute names
- prefix
-
Add a colon-delimited prefix to all attribute names in the output document. For example, with a prefix of "foo",
User-Name
will be output asfoo:User-Name
.
Formatting options for attribute values
- single_value_as_array
-
always put values in an array
Output formats will by default put single values as a JSON object (string, integer, etc). More than one value will, depending on the output format, be added as an array.
When this option is enabled, values will always be added as an array.
- enum_as_integer
-
output the integer value of enumerated attributes
Where an attribute has enum values, the textual representation of the value will normally be output. Enable this option to force the numeric value instead.
- always_string
-
force all values to be strings
Integer values are normally written to the JSON document as numbers (i.e. without quotes). Enable this option to force all values to be as quoted strings.
Expansions
rlm_json provides the below xlat functions to handle the JSON documents.
%json.jpath_validate(…)
Determine if a jpath expression is valid.
Validate parser for everything except unions and expressions. |
string payload
payload := '$.my.json.payload[1]'
&reply.Reply-Message := "Validation of %{payload} is %json.jpath_validate($.my.json.payload[1])"
Validation of $.my.json.payload[1] is 20:$.my.json.payload[1]
%json.quote(…)
Escapes string for use as a JSON string.
string path
&path := "caipirinha/gelada"
&reply.Reply-Message := "The string %{path} should be %json.quote(%{path}) to be a valid JSON string."
The string caipirinha/gelada should be caipirinha\\/gelada to be a valid JSON string.
%json.encode(…)
Generates a JSON document from a given list of attribute templates. The format of document generated can be controlled with the 'encode' section in the module configuration. Attribute values will automatically be escaped so they are JSON-safe.
The name of the xlat is based on the instance name of this module. If
the module was defined as json jdoc {…} , then the xlat name will be
jdoc_encode .
|
The xlat should be passed a list of attributes to encode. Each attribute
(after template expansion) will be added to a list of attributes to include
in the JSON document. If any of the attributes given are preceded with a !
then they are removed from the list. Once all attributes have been processed,
the JSON document will be created using this list.
For example, the following will produce a JSON document with two attributes in
it, User-Name
and Calling-Station-Id
, from the RADIUS request:
%json.encode(&User-Name, &Calling-Station-Id)
The following will include all attributes in the RADIUS request, except for
User-Password
:
%json.encode(&request[*], !&User-Password)
In another (contrived) example, all the attributes in the RADIUS request will
be included in the document, except any attributes in the RADIUS reply.
&User-Name
will be included from the control list, too, if it exists:
%json.encode(&request[*], !&reply[*], &control.User-Name)
Output format modes
There are a number of output modes, each generating a different format of JSON document.
In the JSON document, "type" is the type of the attribute, which is
not necessarily the same as the type of the "value" in the document. See e.g.
Login-Service above, an enumerated value.
|
The following examples assume the three attributes are being added to the JSON document:
User-Name = bob
Filter-Id = ab
Filter-Id += cd
Object output mode examples
These modes output a JSON object.
{
"User-Name": {
"type": "string",
"value": "bob"
},
"Filter-Id": {
"type": "string",
"value": ["ab","cd"]
}
}
{
"User-Name": "bob",
"Filter-Id": ["ab","cd"]
}
Array output mode examples
The "array" mode is a list of objects, each containing an attribute. If the "single_value_as_array" value option is set then each attribute will only appear once in the array, and "value" will be a list of all the values from the same attribute.
[
{
"name": "User-Name",
"type": "string",
"value": "bob"
},
{
"name": "Filter-Id",
"type": "string",
"value": "ab"
},
{
"name": "Filter-Id",
"type": "string",
"value": "cd"
}
]
[
{
"name": "User-Name",
"type": "string",
"value": ["bob"]
},
{
"name": "Filter-Id",
"type": "string",
"value": ["ab","cd"]
}
]
The following output modes either do not include the attribute names or
values. They are likely to be useful only when the attributes are
individually specified and guaranteed to exist. In this case the attribute
names in array_of_names
will have corresponding indexes to the values in
array_of_values
.
[
"User-Name",
"Filter-Id",
"Filter-Id"
]
[
"bob",
"ab",
"cd"
]