#  -*- text -*-
#
#
#  $Id: 953139b5334b84396d65d8b2877b25006fa0dc0b $

#######################################################################
#
#  = 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 RFC 2616 for more details about HTTP.
#

rest {
	#
	#  tls { ... }:: Configure the tls related items that control how
	#  FreeRADIUS connects to a HTTPS server.
	#
	tls {
		#
		#  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_file	             = "${certdir}/cacert.pem"

		#
		#  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_issuer_file     = "${certdir}/caissuer.pem"

		#
		#  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.
		#
#		ca_path	             = "${certdir}"

		#
		#  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).
		#
#		certificate_file     = /path/to/radius.pem

		#
		#  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_file     = /path/to/radius.key

		#
		#  private_key_password:: Password used to decrypt the private key
		#  file.
		#
		#  Should only be specified in the private_key_file is encrypted.
		#
#		private_key_password = "supersecret"

		#
		#  random_file:: Source of random data used for various
		#  cryptographic functions.
		#
#		random_file          = /dev/urandom

		#
		#  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 = no

		#
		#  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`
		#
#		check_cert_cn = no

		#
		#  extract_cert_attrs:: Extract OIDs from presented certificates as
		#  OIDs.
		#
		#  Default is `no`
		#
#		extract_cert_attrs = 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.
		#
#		keylog_file = '/path/to/keylog_file'
	}

	#
	#  connect_uri:: Base URI used to avoid repetition in sections below.
	#
	connect_uri = "http://127.0.0.1:9090/"

	#
	#  connect_proxy:: Proxy server used for all outbound connections.
	#
#	connect_proxy = "socks://127.0.0.1"

	#
	#  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`.
	#  |===
	#
#	http_negotiation = "default"

	#
	#  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.
	#
#	multiplex = yes

	#
	#  chunk:: Max chunk-size.
	#
#	chunk = 0

	#
	#  == 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 `recv Access-Request`
	#  section of a `virtual server`, the settings from the `recv
	#  access-request` section here will be used.
	#
	#  Where sections have two parts to the name, if a section which
	#  matches both names is not found, then one using just the first
	#  name will be looked for. E.g. a call in `accounting Start`, will
	#  look for `accounting start` and fall back to `accounting`.
	#
	#  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.
	#		      `%url.quote(<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.
	#
	#  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.
	#
	xlat {
		tls = ${..tls}

		#
		#  binary:: Is the output of %rest() expected to be binary data
		#
		#  Setting this to "yes" will result in the %rest() xlat outputting
		#  octet data rather than string data.
		#
		#  When it is "no" then the output type will be determined from the
		#  body type of the response.
		#
#		binary = yes
	}

	#
	#  === recv { ... }
	#
	#  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
	#  |===
	#
	recv {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?section=authorize"
			method = 'GET'
		}
		tls = ${..tls}
	}

	#
	#  === Authenticate { ... }
	#
	#  Default action when called in `authenticate` sections.
	#
	#  Return codes handled the same as `Authorize { ... }`
	#
	authenticate {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?section=authenticate"
			method = 'GET'
		}
		tls = ${..tls}
	}

	#
	#  === 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
	#  |===
	#
	accounting {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/sessions/%{Acct-Unique-Session-ID}"
			method = 'POST'
		}
		tls = ${..tls}
	}

	#
	#  === send { ... }
	#
	#  Default action when called in `send` sections.
	#
	#  Return codes handled the same as `Accounting { ... }`
	#
	send {
		request {
			uri = "${...connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-auth"
			method = 'POST'
		}
		tls = ${..tls}
	}

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

		#
		#  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.
		#
		reuse {

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

			#
			#  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.
			max = 100

			#
			#  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.
			#
			cleanup_interval = 30s

		}

		#
		#  connect_timeout:: Connection timeout (in seconds).
		#
		#  The maximum amount of time to wait for a new connection to be
		#  established.
		#
		connect_timeout = 3.0
	}
}
