



= Rest Module

The `rest` module sends HTTP requests to remote servers and decodes
the responses. Can also perform basic auth with user's credentials.

See https://tools.ietf.org/html/rfc2616[RFC 2616] for more details about HTTP.



tls { ... }:: Configure the tls related items that control
how FreeRADIUS connects to a HTTPS server.


.Certificate validation options

Specifies how the certificate(s) presented by the HTTPS server being contacted
are validated, and which certificates (if any) to send to the HTTPS server.



ca_file:: PEM formatted file containing the chain to validate the HTTPS server's cert

Should usually contain a concatenation of one or more intermediary CA
files, shallowest (i.e. the one that signed the HTTPS server's cert) first, and
deepest (the root CA) last.

Providing a complete certificate chain here is the most common way of validating
the certificate presented by a HTTPS server.



ca_issuer_file:: PEM formatted file containing the CA that signed the HTTPS server's cert

Specifies the certificate that directly signed the certificate presented by the
HTTPS server.

This configuration option can be used to prevent certificates passing validation that
were signed by other intermediary CAs or root CAs in the trusted certificate chain.



ca_path:: A directory containing multiple root CA certs named by their hash

See the OpenSSL documentation for more details:
- https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_default_verify_paths.html
- https://www.openssl.org/docs/man1.1.1/man1/c_rehash.html

This configuration option should only be used when the HTTPS server being contacted
is not known ahead of time (using a URL from an external source), and/or the CA used
to sign the HTTPS server certificate is unknown.

If not set, then whatever libcurl has as its default will be used, which typically
will be the operating system's set of trusted CAs.  This will be visible in the debug
output when FreeRADIUS starts.



certificate_file:: PEM formatted file containing the certificate we present to the HTTPS server

Specifies a certificate and any intermediary CAs we should send to the HTTPS server.

This file should usually contain the client certificate file first, then any
intermediary signing CAs, shallowest (direct signee of the certificate_file)
to deepest (signed directly by the root CA).



private_key_file:: PEM formatted file containing the private key for the specified certificate_file

Must be specified if certificate_file is being used.



private_key_password:: Password used to decrypt the private key file.

Should only be specified in the private_key_file is encrypted.



random_file:: Source of random data used for various cryptographic functions.



check_cert:: Server certificate verification requirements.

May be one of:

[options="header,autowidth"]
|===
| Option | Description
| `no`   | Server certificate can be signed by any CA or be self-signed.
| `yes`  | Server certificate must be issued by one of the trusted CAs.
|===

Default is `yes`



check_cert_cn:: Server certificate CN verification requirements.

May be one of:

[options="header,autowidth"]
|===
| Option | Description
| `no`   | Server certificate CN can be any value.
| `yes`  | Server certificate CN matches the host in the URI.
|===

Default is `yes`



extract_cert_attrs:: Extract OIDs from presented certificates as OIDs.

Default is `no`



keylog_file:: Write out session keys in SSLKEYLOGFILE format

The SSLKEYLOGFILE format is specified here https://www.ietf.org/archive/id/draft-thomson-tls-keylogfile-00.html.

The contents of the keylog file allows wireshark captures to be decrypted for debugging purposes.

Note:: keylog_file is not expanded at runtime.



connect_uri:: Base URI used to avoid repetition in sections below.



connect_proxy:: Proxy server used for all outbound connections.



http_negotiation:: The negotiation scheme and target HTTP version.

May be one of:

[options="header,autowidth"]
|===
| Option     | Description
| `default`  | Use whichever negotiation scheme and version is the default
               for `libcurl`.
| `1.0`      | Disable negotiation.  Force HTTP `1.0`.
| `1.1`      | Disable negotiation.  Force HTTP `1.1`.
| `2.0`      | Disable negotiation.  Force HTTP `2.0`.
| `2.0+auto` | Try and negotiate 2.0 and fallback to `1.1`.
| `2.0+tls`  | For `https` try and negotiate 2.0 and fallback to `1.1`.
               For `http` try and negotiate 2.0 and fallback to `1.1`.
|===



multiplex:: Execute multiple requests simultaneously using the same HTTP connection.

NOTE: HTTP >= 2.0 is required for multiplexing to succeed. If we can't negotiate
a high enough http version, multiplexing will be silently disabled.



chunk:: Max chunk-size.



## Sections

The following config items can be used in each of the sections.
The sections themselves reflect the sections in the server.

For example, if you list `rest` in the `authorize` section of a `virtual server`,
the settings from the `authorize` section here will be used.

The following sections are supported:

- `authorize { ... }`
- `authenticate { ... }`
- `accounting { ... }`
- `post-auth { ... }`
- `xlat { ... }`

At the top level of each section, the following config items may be listed:

[options="header,autowidth"]
|===
| Option        		| Description
| `request { ... }`          | How to create the HTTP request.
| `response { ... }`         | How to decode the response.
| `tls`          		| TLS settings for HTTPS.
| `timeout`      		| HTTP request timeout in seconds, defaults to 4.0.
|===

In the `request { ... }` subsection, the following config items may be listed:

[options="header,autowidth"]
|===
| Option         | Description								| Allowed in `xlat { ... }`
| `uri`          | To send the request to.							| no
| `proxy`        | The request via this server, supports `socks/http/https` uri and `:port`. | no
                   May be set to "none" to disable proxying, overriding any environmental
      variables set like http_proxy.
| `method`       | HTTP method to use, one of 'get', 'post', 'put', 'patch',			| no
                   'delete' or any custom HTTP method.
| `header`       | A custom header in the format '<header>: <value>'.			| yes
      May be specified multiple times.  Will be expanded.
| `body`         | The format of the HTTP body sent to the remote server.			| yes
                   May be 'none', 'post' or 'json', defaults to 'none'.
| `data`         | Send custom freeform data in the HTTP body. `Content-type`		| yes
                   may be specified with `body`. Will be expanded.
                   Values from expansion will not be escaped, this should be
      done using the appropriate `xlat` method e.g.
      `%urlquote(<attr>)`
| `auth`         | HTTP auth method to use, one of 'none', 'srp', 'basic',			| yes
                   'digest', 'digest-ie', 'gss-negotiate', 'ntlm',
                   'ntlm-winbind', 'any', 'safe'. defaults to _'none'_.
| `require_auth` | Require HTTP authentication or fail the request.				| yes
| `username`     | User to authenticate as.  Will be expanded.				| yes
      Defaults to `%{User-Name}` in the `authenticate { ... }` section.
| `password`     | Password to use for authentication.  Will be expanded.			| yes
      Defaults to `%{User-Password}` in the `authenticate { ... }` section.
|===


In the `response { ... }` subsection, the following config items may be listed:

[options="header,autowidth"]
|===
| Option         | Description
| `header`       | Where to write out HTTP headers included in the response.
      Must resolve to a leaf attribute i.e. &reply.REST-HTTP-Header.
      If unspecified, headers will be discarded.
      Values will be in the format '<header>: <value>'.
| `force_to`     | Force the response to be decoded with this decoder.
                   May be 'plain' (creates reply.REST-HTTP-Body), 'post' or 'json'.
| `max_body_in`  | Maximum size of incoming HTTP body, defaults to 16k.
|===

Additional HTTP headers may be specified with `control.REST-HTTP-Header`.

The values of those attributes should be in the format:

  <attribute>: <value>

`control.REST-HTTP-Header` attributes will be consumed after each call
to the rest module, and each `%rest(...)` expansion.



.Body encodings are the same for requests and responses

POST - All attributes and values are urlencoded.

e.g:

`[outer.][<list>.]<attribute0>=<value0>&[outer.][<list>.]<attributeN>=<valueN>`

JSON - All attributes and values are escaped according to the JSON specification.

e.g:

[source,json]
----
{
    "<attribute0>":{
        "type":"<type0>",
        "value":[<value0>,<value1>,<valueN>]
    },
    "<attribute1>":{
        "type":"<type1>",
        "value":[...]
    },
    "<attributeN>":{
        "type":"<typeN>",
        "value":[...]
    },
}
----

The response format adds three optional fields:

[options="header,autowidth"]
|===
| Fields    | Description
| `do_xlat` | If `true`, any values will be xlat expanded. Defaults to `true`.
| `is_json` | If `true`, any nested JSON data will be copied to the attribute
              in string form. Defaults to `true`.
| `op`      | Controls how the attribute is inserted into the target list.
              Defaults to `:=`. To create multiple attributes from multiple
              values, this should be set to `+=`, otherwise only the last
              value will be used, and it will be assigned to a single
              attribute.
|===

[source,json]
----
{
    "[outer.][<list>.]<attribute0>":{
        "is_json":<bool>,
        "do_xlat":<bool>,
        "op":"<operator>",
        "value":[<value0>,<value1>,<valueN>]
    },
    "<attribute1>":"value",
    "<attributeN>":{
        "value":[<value0>,<value1>,<valueN>],
        "op":"+="
    }
}
----

[NOTE]
====
  * Module return codes are determined by HTTP response codes. These vary depending on the
section.

  * If the `body` is processed and found to be malformed or unsupported `fail` will be returned.
  * If the `body` is processed and found to contain attribute updated will be returned,
except in the case of a `401` code.
====



xlat { ... }::: Allows a subset of section configuration items to be configured for
any calls to this module's `xlat` function.



### Authorize { ... }

Default action when called in `recv` sections except `recv Accounting-Request`.

[options="header,autowidth"]
|===
| Code | Meaning      | Process body? | Module code
| 404  | not found    | no            | notfound
| 410  | gone         | no            | notfound
| 403  | forbidden    | no            | disallow
| 401  | unauthorized | yes           | reject
| 204  | no content   | no            | ok
| 2xx  | successful   | yes           | ok/updated
| 5xx  | server error | no            | fail
| xxx  | -            | no            | invalid
|===



### Authenticate { ... }

Default action when called in `authenticate` sections.

Return codes handled the same as `Authorize { ... }`



### Accounting { ... }

Default action when called in `recv Accounting-Request` or `accounting` sections.

[options="header,autowidth"]
|===
| Code | Meaning      | Process body? | Module code
| 204  | no content   | no            | ok
| 2xx  | successful   | yes           | ok/updated
| 5xx  | server error | no            | fail
| xxx  | -            | no            | invalid
|===



### Post-Auth { ... }

Default action when called in `send` sections.

Return codes handled the same as `Accounting { ... }`



connection { ... }::  Configure how connection handles are
managed per thread.



Reusable connection handles are allocated in blocks.  These
parameters allow for tuning how that is done.

Since http requests are performed async, the settings here
represent outstanding http requests per thread.



min:: The minimum number of connection handles to
keep allocated.



max:: The maximum number of reusable connection handles
to allocate.

Any requests to allocate a connection handle beyond
this number will cause a temporary handle to be allocated.
This is less efficient than the block allocation so
`max` should be set to reflect the number of outstanding
requests expected at peak load.


cleanup_interval:: How often to free un-used connection
handles.

Every `cleanup_interval` a cleanup routine runs which
will free any blocks of handles which are not in use,
ensuring that at least `min` handles are kept.




connect_timeout:: Connection timeout (in seconds).

The maximum amount of time to wait for a new connection to be established.


== Default Configuration

```
rest {
	tls {
#		ca_file	             = "${certdir}/cacert.pem"
#		ca_issuer_file     = "${certdir}/caissuer.pem"
#		ca_path	             = "${certdir}"
#		certificate_file     = /path/to/radius.pem
#		private_key_file     = /path/to/radius.key
#		private_key_password = "supersecret"
#		random_file          = /dev/urandom
#		check_cert = no
#		check_cert_cn = no
#		extract_cert_attrs = no
#		keylog_file = '/path/to/keylog_file'
	}
	connect_uri = "http://127.0.0.1:9090/"
#	connect_proxy = "socks://127.0.0.1"
#	http_negotiation = "default"
#	multiplex = yes
#	chunk = 0
	xlat {
		tls = ${..tls}
	}
	authorize {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?section=authorize"
			method = 'GET'
		}
		tls = ${..tls}
	}
	authenticate {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?section=authenticate"
			method = 'GET'
		}
		tls = ${..tls}
	}
	accounting {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/sessions/%{Acct-Unique-Session-ID}"
			method = 'POST'
		}
		tls = ${..tls}
	}
	post-auth {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-auth"
			method = 'POST'
		}
		tls = ${..tls}
	}
	connection {
		reuse {
			min = 10
			max = 100
			cleanup_interval = 30s
		}
		connect_timeout = 3.0
	}
}
```
