[RADIATOR] MapResponseHook sample (Was: Re: (no subject))
Heikki Vatiainen
hvn at open.com.au
Thu May 25 14:29:23 UTC 2023
On 23.5.2023 0.19, Heikki Vatiainen via radiator wrote:
> On 22.5.2023 9.37, Greg Haverkamp via radiator wrote:
>> I get a JSON response that looks something like this:
>> {
>> "version": "LinOTP 2.11.2",
>> "jsonrpc": "2.0802",
>> "result": {
>> "status": true,
>> "value": false
>> },
>> "id": 0
>> }
>>
>
> I can create an example of how to access the contents of the "result"
> key. The default is to create a Perl hash for the keys but more complex
> structures require more configuration.
Here's a configuration snippet followed by a hook. Trace 5 and Debug are
set because they allow logging the requests and responses sent over HTTP(S).
The RestAuthReplyDef parameters use values set by the hook. The first
ones that use Auth-Type check item, trigger failure if "result" is not
present in the JSON reply or one of "status" or "value" is false. This
means the above JSON response triggers a failure.
The RestAuthReplyDef parameters that add X-Result-Status and
X-Result-Value to request show how to something to the current request
based on the JSON response.
Trace 5
<AuthBy REST>
# Config parameters ...
Debug
# Call the hook code in this file.
MapResponseHook file:"%D/rest-map-hook.pl"
# How to handle a response from the server.
#
# With Auth-Type check items you can trigger reject here.
RestAuthReplyDef auth_type_result, Auth-Type, check
RestAuthReplyDef auth_type_status, Auth-Type, check
RestAuthReplyDef auth_type_value, Auth-Type, check
# As an alternative, you can store the values in request or
# reply and process them later.
RestAuthReplyDef result_status, X-Result-Status, request
RestAuthReplyDef result_value, X-Result-Value, request
# Log the Radius request to show the new X-Result- attributes.
PostAuthHook sub { my $p = ${$_[0]}; main::log($main::LOG_DEBUG,
"Request after AuthBy\n" . $p->dump(), $p); }
</AuthBy>
A rest-map-hook.pl sample is below. It first calls log to show how the
default JSON to Perl mapping was done. It then makes additional keys
available for the RestAuthReplyDef configuration parameters to use. Note
that if a key, for example 'auth_type_result', is not present, the
RestAuthReplyDef is skipped.
The log() calls are simply to aid debugging so that it's easier to see
how JSON responses map to Perl data structures by default and ensure
that the changes done within the hook are correct. With a hook, any
complex JSON responses can be processed because the hook sees them in
Perl mapped format.
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
sub {
main::log($main::LOG_DEBUG, "Default processed response\n" .
Dumper(@_));
# $response_hash does not directly contain the mapped JSON
# response. To update values RestAuthReplyDef configuration
# parameter uses, modify 'server_response' within $response_hash.
my $response_hash = $_[0];
my $server_response = $response_hash->{server_response};
# Successful reply must have 'result'.
if ($server_response->{result})
{
# Trigger reject if 'status' or 'value' within 'result' is
# false. Requires Auth-Type check item in the configuration.
$server_response->{auth_type_status} = 'Reject:Status is false'
if !$server_response->{result}->{status};
$server_response->{auth_type_value} = 'Reject:Value is false'
if !$server_response->{result}->{value};
# 'status' and 'value' are JSON booleans that are mapped to
# Perl objects. Convert them to plain numeric zero or one.
$server_response->{result_status} =
$server_response->{result}->{status} ? 1 : 0;
$server_response->{result_value} =
$server_response->{result}->{value} ? 1 : 0;
}
else
{
# Trigger reject if there's no JSON object named 'result'
$server_response->{auth_type_result} = 'Reject:No result in reply';
}
# Log the mapping to show the new keys 'result_value' and
# 'result_status' and optionally 'auth_type' is 'status' within
# 'result' was not true.
main::log($main::LOG_DEBUG, "Updated processed response\n" .
Dumper(@_));
return;
}
Here's a snippet from Radiator log. Note that JSON booleans map to Perl
objects. Therefore the 'result_status' and 'result_value' are made to
simple zero and one which are easy to compare. A string comparison
against an object is unlikely to produce expected results. The zero and
one values are shown in the message logged from PostAuthHook as values
of X-Result-Value and X-Result-Status. A PostAuthHook, AuthLog, a
subsequent AuthBy etc. can later use them as required.
Thu May 25 17:14:02 2023 330808: DEBUG: AuthREST 'rest-authby'
'127.0.0.1 port 8888' received HTTP response:
HTTP/1.1 200 OK
Date: Mon, 23 May 2021 22:38:34 GMT
Content-Type: application/json
Content-Length: 112
Last-Modified: Wed, 08 Jan 2021 23:11:55 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
Accept-Ranges: bytes
Connection: close
{
"version": "LinOTP 2.11.2",
"jsonrpc": "2.0802",
"result": {
"status": true,
"value": false
},
"id": 0
}
Thu May 25 17:14:02 2023 331130: DEBUG: HTTPClientConnection
'127.0.0.1-8888' Stream disconnected from 127.0.0.1 (127.0.0.1 port 8888)
Thu May 25 17:14:02 2023 331674: DEBUG: Default processed response
$VAR1 = {
'server_response' => {
'id' => 0,
'jsonrpc' => '2.0802',
'result' => {
'status' => bless(
do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
'value' => bless(
do{\(my $o = 0)}, 'JSON::PP::Boolean' )
},
'version' => 'LinOTP 2.11.2'
},
'status_line' => '200 OK'
};
Thu May 25 17:14:02 2023 331964: DEBUG: Updated processed response
$VAR1 = {
'server_response' => {
'auth_type_value' => 'Reject:Value is
false',
'id' => 0,
'jsonrpc' => '2.0802',
'result' => {
'status' => bless(
do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
'value' => bless(
do{\(my $o = 0)}, 'JSON::PP::Boolean' )
},
'result_status' => 1,
'result_value' => 0,
'version' => 'LinOTP 2.11.2'
},
'status_line' => '200 OK'
};
Thu May 25 17:14:02 2023 332250: DEBUG: Handling with Radius::AuthREST:
rest-authby
Thu May 25 17:14:02 2023 332642: DEBUG: Radius::AuthREST looks for match
with 'mikem' [mikem]
Thu May 25 17:14:02 2023 332882: DEBUG: Radius::AuthREST
REJECT_IMMEDIATE: Value is false: 'mikem' [mikem]
Thu May 25 17:14:02 2023 333270: DEBUG: Request after AuthBy
Code: Access-Request
Identifier: 117
Authentic: <11>Im<168>#<202><149><243>$N><217><131>P-<197>
Attributes:
User-Name = "mikem"
Service-Type = Framed-User
NAS-IP-Address = 203.63.154.1
NAS-Identifier = "203.63.154.1"
NAS-Port = 1234
Called-Station-Id = "123456789"
Calling-Station-Id = "987654321"
NAS-Port-Type = Async
User-Password =
<138><237><247><10>)<203>g<127><235>I<194><129>D<133>YX
X-Result-Status = 1
X-Result-Value = 0
Thu May 25 17:14:02 2023 333467: DEBUG: AuthBy REST result:
REJECT_IMMEDIATE, Value is false
Thu May 25 17:14:02 2023 333761: INFO: Access rejected for mikem: Value
is false
I'll add the above to goodies.
Thanks,
Heikki
--
Heikki Vatiainen
OSC, makers of Radiator
Visit radiatorsoftware.com for Radiator AAA server software
More information about the radiator
mailing list