diff --git a/src/nss.rs b/src/nss.rs index 38fe9a7e693f5f3f0e8c6c31fe1350dcdb733f19..9eeb5b96042cfb4dcad20d14cd5e9fd647c13c67 100644 --- a/src/nss.rs +++ b/src/nss.rs @@ -13,13 +13,44 @@ * limitations under the License. */ -use crate::config::get_config; +use crate::config::{ + get_config, + get_optional +}; use config::Config; use crate::logging::setup_log; +use serde::de::Deserialize; + +use oauth2::{ + AuthUrl, + ClientId, + ClientSecret, + RequestTokenError, + Scope, + TokenUrl +}; +use oauth2::basic::BasicClient; +use oauth2::reqwest; +use oauth2::reqwest::http_client; + +use libnss::interop::Response; use libnss::passwd::{PasswdHooks, Passwd}; +fn get_or_nss_error<'de, T: Deserialize<'de>>(config: &Config, key: &str) -> Result<T, Response> { + match get_optional(config, key) { + Some(v) => { + debug!("Configuration key found: {}", key); + return Ok(v); + }, + None => { + error!("Configuration key not found: {}", key); + return Err(Response::Unavail); + }, + } +} + fn nss_hook_prepare() -> Config { let conf = get_config(None); @@ -32,10 +63,85 @@ fn nss_hook_prepare() -> Config { return conf; } +fn get_bearer_token(config: Config) -> Result<String, Response> { + let client_id = ClientId::new(get_or_nss_error(&config, "nss.client_id")?); + let client_secret = match get_optional(&config, "nss.client_secret") { + Some(v) => Some(ClientSecret::new(v)), + None => None, + }; + let auth_url = match AuthUrl::new(get_or_nss_error(&config, "nss.auth_url")?) { + Ok(u) => u, + _ => { + error!("Could not parse authorization URL"); + return Err(Response::Unavail); + }, + }; + let token_url = match get_optional(&config, "nss.token_url") { + Some(v) => match TokenUrl::new(v) { + Ok(u) => Some(u), + Err(_) => { + error!("Could not parse token URL"); + return Err(Response::Unavail); + } + }, + None => None, + }; + let scopes: Vec<&str> = get_or_nss_error(&config, "nss.scopes")?; + + let client = BasicClient::new(client_id, client_secret, auth_url, token_url); + let mut request = client.exchange_client_credentials(); + for scope in scopes { + request = request.add_scope(Scope::new(scope.to_string())); + } + let result = request.request(http_client); + + match result { + Ok(t) => Ok(t), + Err(e) => match e { + RequestTokenError::Request(re) => match re { + reqwest::Error::Reqwest(ree) => { + error!("Request error requesting token: {}", ree); + return Err(Response::Unavail); + }, + reqwest::Error::Http(he) => { + error!("HTTP error requesting token: {}", he); + return Err(Response::Unavail); + }, + reqwest::Error::Io(ioe) => { + error!("IO error requesting token: {}", ioe); + return Err(Response::Unavail); + }, + _ => { + error!("Unknown error: {}", re); + return Err(Response::Unavail); + }, + }, + RequestTokenError::ServerResponse(t) => { + error!("Authorization server returned error: {}", t); + return Err(Response::Unavail); + }, + RequestTokenError::Parse(pe, _) => { + error!("Error parsing response: {}", pe); + return Err(Response::Unavail); + }, + _ => { + error!("Unknown error: {}", e); + return Err(Response::Unavail); + }, + }, + } +} + +fn do_json_request(config: Config, url: String) -> Result<String, Response> { + let token = get_bearer_token(config)?; +} + struct OidcPasswd; impl PasswdHooks for OidcPasswd { fn get_all_entries() -> Vec<Passwd> { + let config = nss_hook_prepare(); + vec![ Passwd { name: "test".to_string(),