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

[NSS] Implement reverse-mapping of getent search fields

Closes #7
parent 828c1aed
No related branches found
No related tags found
No related merge requests found
...@@ -32,3 +32,6 @@ maps.passwd = """ ...@@ -32,3 +32,6 @@ maps.passwd = """
shell: .login_shell shell: .login_shell
} }
""" """
# Reverse mapping to make sure uid lookups on entries mapped above still work
maps.rev.passwd.by_uid = ". - 10000"
...@@ -119,7 +119,7 @@ impl PasswdHooks for OidcPasswd { ...@@ -119,7 +119,7 @@ impl PasswdHooks for OidcPasswd {
} }
}; };
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_uid", uid.to_string(), &token, false).map(|PasswdHelper(p)| p) { let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_uid", uid, &token, false).map(|PasswdHelper(p)| p) {
Ok(d) => d, Ok(d) => d,
Err(e) => { Err(e) => {
error!("Could not load JSON data for passwd: {}", e); error!("Could not load JSON data for passwd: {}", e);
......
...@@ -39,7 +39,7 @@ use oauth2::reqwest::http_client; ...@@ -39,7 +39,7 @@ use oauth2::reqwest::http_client;
use std::error; use std::error;
use serde::Deserialize; use serde::{Deserialize, Serialize};
use reqwest; use reqwest;
use serde_json; use serde_json;
...@@ -151,15 +151,23 @@ fn get_data(conf: &Config, prefix: &str, endpoint: &str, param: String, token: & ...@@ -151,15 +151,23 @@ fn get_data(conf: &Config, prefix: &str, endpoint: &str, param: String, token: &
.text()?) .text()?)
} }
fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str) -> Option<String> { fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str, rev: bool) -> Option<String> {
match get_optional(&conf, &full_key(vec![prefix, "maps", endpoint])) { let prog_key = match rev {
false => full_key(vec![prefix, "maps", endpoint]),
true => full_key(vec![prefix, "maps.rev", endpoint]),
};
match get_optional(&conf, &prog_key) {
Some(v) => Some (v), Some(v) => Some (v),
None => { None => {
if rev {
// Do not fallback to more generic program for reverse mapping
return None;
}
// Try falling back to more generic program // Try falling back to more generic program
match endpoint.find('.') { match endpoint.find('.') {
Some(i) => { Some(i) => {
debug!("JQ mapping program for {} not found; trying more generic definition", endpoint); debug!("JQ mapping program for {} not found; trying more generic definition", endpoint);
get_jq_prog(conf, prefix, &endpoint[..i]) get_jq_prog(conf, prefix, &endpoint[..i], rev)
}, },
None => None None => None
} }
...@@ -167,11 +175,11 @@ fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str) -> Option<String> { ...@@ -167,11 +175,11 @@ fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str) -> Option<String> {
} }
} }
pub fn get_data_jq<T: for<'de> Deserialize<'de>>(conf: &Config, prefix: &str, endpoint: &str, param: String, token: &BasicTokenResponse, multi: bool) -> Result<T, Box<dyn error::Error>> { 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>> {
let res: Option<String> = get_jq_prog(&conf, prefix, endpoint); let res: Option<String> = get_jq_prog(&conf, prefix, endpoint, false);
let jq_code = match res { let jq_code = match res {
Some(s) => { Some(s) => {
debug!("Found jq mapping program for endpoint {}", endpoint); debug!("Found jq mapping program for endpoint {}: {}", endpoint, s);
match multi { match multi {
true => "map(".to_string() + &s + ")", true => "map(".to_string() + &s + ")",
false => s false => s
...@@ -183,6 +191,30 @@ pub fn get_data_jq<T: for<'de> Deserialize<'de>>(conf: &Config, prefix: &str, en ...@@ -183,6 +191,30 @@ pub fn get_data_jq<T: for<'de> Deserialize<'de>>(conf: &Config, prefix: &str, en
} }
}; };
let mut jq_prog = jq_rs::compile(&jq_code)?; let mut jq_prog = jq_rs::compile(&jq_code)?;
let res: Option<String> = get_jq_prog(&conf, prefix, endpoint, true);
let jq_code = match res {
Some(s) => {
debug!("Found jq reverse mapping program for endpoint {}: {}", endpoint, s);
s
},
None => {
debug!("No jq reverse mapping program for endpoint {}; using default (no-op)", endpoint);
".".to_string()
}
};
let mut jq_prog_rev = jq_rs::compile(&jq_code)?;
// Convert and transform the passed param using the reverse JQ mapping program
// 1. Serialize into JSON value (atomic) to be bale to pass into jq
let param_serialized = serde_json::to_string(&param)?;
// 2. Transform using the JQ program loaded above
let param_trans = jq_prog_rev.run(&param_serialized)?.trim().to_string();
// 3. Deserialize into serde_json value so we get numbers as numbers, strings properly unquoted
let param_deserialized: serde_json::Value = serde_json::from_str(&param_trans)?;
let param = match param_deserialized {
serde_json::Value::String(v) => v, // We want strings verbatim without JSON quoting
_ => param_deserialized.to_string() // We want numbers converted to string
};
let data_raw = get_data(&conf, prefix, endpoint, param, token)?; let data_raw = get_data(&conf, prefix, endpoint, param, token)?;
let data_trans = jq_prog.run(&data_raw)?; let data_trans = jq_prog.run(&data_raw)?;
......
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