Skip to content
Snippets Groups Projects
Verified Commit dcaf0e1a authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Add some documentaion commentary

parent 33612ba5
No related branches found
No related tags found
No related merge requests found
......@@ -151,6 +151,29 @@ fn get_data(conf: &Config, prefix: &str, endpoint: &str, param: String, token: &
.text()?)
}
/// Retrieve a jq program from the config
///
/// Arguments
/// ---------
///
/// `conf` - reference to the config object
/// `prefix` - current prefix (probably `nss` or `pam`)
/// `endpoint` - name of the URL endpoint operating on, e.g. `passwd.list`
/// `multi` - `true` if the nndpoint will return an array
/// `rev` - `true` if looking for the reverse mapping program (see `get_data_jq`)
///
/// The endpoint will be truncated starting from the right if no program is found under
/// the config key, so that a single jq programm can be configured for `passwd` instead of
/// three separate programs for `passwd.list`, `passwd.by_uid` and `passwd.by_name`.
///
/// Lookup of the program in the config is done through the general config fetching mechanism
/// (see `get_optional`).
///
/// The programm will be looked up unter `<prefix>.maps`. If `rev` is true, the programm will
/// be looked up under `maps.rev` instead of `maps`.
///
/// If `multi` is `true`, the resulting program will be wrapped into jq's `map()` function
/// to be applied to an array of objects.
fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str, multi: bool, rev: bool) -> jq_rs::Result<jq_rs::JqProgram> {
// Generate config key to find jq program under
let prog_key = match rev {
......@@ -191,6 +214,83 @@ fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str, multi: bool, rev: bo
jq_rs::compile(&jq_code)
}
/// Retrieve JSON data from a configured endpoint, transforming using configured jq programs
///
/// This function takes a prefix (probably `nss` or `pam`, and an endpoint name to lookup
/// information in the passed configuration. It then uses this information and the passed
/// parameter to construct a URL to retrieve data from the HTTP API.
///
/// Transformation occurs both for the passed parameter and for the retrieved data.
/// Consider the following scenario:
///
/// The configured backend server provides three URLs for doing NSS-like lookups:
///
/// * `https://example.com/users/` - get a JSON array of all users
/// * `https://example.com/user/1234/` - get a single JSON object for a user with a numeric user ID
/// * `https://example.com/user/janedoe/` - get a single JSON object for a user with a user name
///
/// Any user object returned by the server looks like this:
///
/// ```json
/// {
/// "username": "janedoe",
/// "uid": 1234,
/// "primary_gid": 100,
/// "home_directory": "/home/janedoe",
/// "login_shell": "/bin/bash",
/// "full_name": "Doe, Jane"
/// }
/// ```
///
/// To integrate the information in our system, which also has other user sources,
/// we need to ensure the following:
///
/// * Numeric user IDs need to be mapped starting at 10000
/// * Home directories need to be re-mapped to /srv/remote_users
/// * The full name (GECOS) shall be suffixed with "(Remote)" for clarity
/// * We need to set a static password of "x" because the API (correctly) does not serve passwords
/// * All field names need to be renamed to the fields of the passwd struct
///
/// To accomplish this, we will configure two jq programs:
///
/// ```toml
/// nss.maps.passwd = """
/// {
/// name: .username,
/// # No passwords in passwd
/// passwd: "x",
/// # Map user and group IDs starting at 10000
/// uid: (.uid + 10000),
/// gid: (.primary_gid + 10000),
/// # Append organisation name to Gecos field
/// gecos: (.full_name + " (Remote)"),
/// # Remap /home from server to /srv/teckids locally
/// dir: ("/srv/remote_users/" + (.home_directory|ltrimstr("/home/"))),
/// shell: .login_shell
/// }
/// """
///
/// # Reverse mapping to make sure uid lookups on entries mapped above still work
/// nss.maps.rev.passwd.by_uid = ". - 10000"
/// ```
///
/// The first program maps result objects into new JSON objects with the rules described
/// inline. The `map()` function from jq that is needed to apply the program to every
/// object in an array will be added automatically if a list is retrieved (`multi` is `true`).
///
/// The second program is used when a single user is queried by their numeric user ID, and it
/// reverses the transformation done to the uid field so the lookup on the server gets the
/// expected user ID.
///
/// Along with the following URL configuration, this brings everything into place:
///
/// ```toml
/// nss.urls.passwd.list = "https://example.com/users/"
/// nss.urls.passwd.by_uid = "https://example.com/users/{}/"
/// nss.urls.passwd.by_name = "https://example.com/users/{}/"
/// ```
///
/// In the second and thrid URL, the placeholder `{}` will be replaced with the lookup key.
pub fn get_data_jq<T: for<'de> Deserialize<'de>, V: Serialize>(conf: &Config, prefix: &str, endpoint: &str, param: V, token: &BasicTokenResponse, multi: bool) -> Result<T, Box<dyn error::Error>> {
// Get jq mapping programs for forward and reverse mappings
let mut jq_prog_fwd = get_jq_prog(&conf, prefix, endpoint, multi, false)?;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment