#  -*- text -*-
#
#
#  $Id: 1f8fd66b20a0b13fa3c0b7a0391768487fc2a9bd $

#######################################################################
#
#  = 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 `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.
	#
	xlat {
		tls = ${..tls}
	}

	#
	#  ### 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
	#  |===
	#
	authorize {
		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}
	}

	#
	#  ### Post-Auth { ... }
	#
	#  Default action when called in `send` sections.
	#
	#  Return codes handled the same as `Accounting { ... }`
	#
	post-auth {
		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
	}
}
