Cleanup and improve client error handling

This commit is contained in:
William Brown 2020-08-01 20:31:05 +10:00 committed by Firstyear
parent c4805d2915
commit 217e3455a2
19 changed files with 532 additions and 292 deletions

View file

@ -23,7 +23,7 @@ impl KanidmAsyncClient {
// format doesn't work in async ?! // format doesn't work in async ?!
// let dest = format!("{}{}", self.addr, dest); // let dest = format!("{}{}", self.addr, dest);
let req_string = serde_json::to_string(&request).unwrap(); let req_string = serde_json::to_string(&request).map_err(ClientError::JSONEncode)?;
let response = self let response = self
.client .client
@ -34,21 +34,28 @@ impl KanidmAsyncClient {
.await .await
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().await.ok())), unexpect => {
return Err(ClientError::Http(
unexpect,
response.json().await.ok(),
opid,
))
}
} }
// TODO #253: What about errors response
let r: T = response.json().await.unwrap(); .json()
.await
Ok(r) .map_err(|e| ClientError::JSONDecode(e, opid))
} }
async fn perform_put_request<R: Serialize, T: DeserializeOwned>( async fn perform_put_request<R: Serialize, T: DeserializeOwned>(
@ -61,7 +68,7 @@ impl KanidmAsyncClient {
// format doesn't work in async ?! // format doesn't work in async ?!
// let dest = format!("{}{}", self.addr, dest); // let dest = format!("{}{}", self.addr, dest);
let req_string = serde_json::to_string(&request).unwrap(); let req_string = serde_json::to_string(&request).map_err(ClientError::JSONEncode)?;
let response = self let response = self
.client .client
@ -72,21 +79,29 @@ impl KanidmAsyncClient {
.await .await
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().await.ok())), unexpect => {
return Err(ClientError::Http(
unexpect,
response.json().await.ok(),
opid,
))
}
} }
// TODO #253: What about errors response
let r: T = response.json().await.unwrap(); .json()
.await
Ok(r) .map_err(|e| ClientError::JSONDecode(e, opid))
} }
async fn perform_get_request<T: DeserializeOwned>(&self, dest: &str) -> Result<T, ClientError> { async fn perform_get_request<T: DeserializeOwned>(&self, dest: &str) -> Result<T, ClientError> {
@ -100,21 +115,29 @@ impl KanidmAsyncClient {
.await .await
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().await.ok())), unexpect => {
return Err(ClientError::Http(
unexpect,
response.json().await.ok(),
opid,
))
}
} }
// TODO #253: What about errors response
let r: T = response.json().await.unwrap(); .json()
.await
Ok(r) .map_err(|e| ClientError::JSONDecode(e, opid))
} }
async fn perform_delete_request(&self, dest: &str) -> Result<bool, ClientError> { async fn perform_delete_request(&self, dest: &str) -> Result<bool, ClientError> {
@ -126,20 +149,28 @@ impl KanidmAsyncClient {
.await .await
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().await.ok())), unexpect => {
return Err(ClientError::Http(
unexpect,
response.json().await.ok(),
opid,
))
}
} }
let r: bool = response.json().await.unwrap(); response
.json()
Ok(r) .await
.map_err(|e| ClientError::JSONDecode(e, opid))
} }
pub async fn auth_step_init(&self, ident: &str) -> Result<AuthState, ClientError> { pub async fn auth_step_init(&self, ident: &str) -> Result<AuthState, ClientError> {
@ -205,17 +236,37 @@ impl KanidmAsyncClient {
let whoami_dest = [self.addr.as_str(), "/v1/self"].concat(); let whoami_dest = [self.addr.as_str(), "/v1/self"].concat();
// format!("{}/v1/self", self.addr); // format!("{}/v1/self", self.addr);
debug!("{:?}", whoami_dest); debug!("{:?}", whoami_dest);
let response = self.client.get(whoami_dest.as_str()).send().await.unwrap(); let response = self
.client
.get(whoami_dest.as_str())
.send()
.await
.map_err(ClientError::Transport)?;
let opid = response
.headers()
.get(KOPID)
.and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
.unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
// Continue to process. // Continue to process.
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
reqwest::StatusCode::UNAUTHORIZED => return Ok(None), reqwest::StatusCode::UNAUTHORIZED => return Ok(None),
unexpect => return Err(ClientError::Http(unexpect, response.json().await.ok())), unexpect => {
return Err(ClientError::Http(
unexpect,
response.json().await.ok(),
opid,
))
}
} }
let r: WhoamiResponse = let r: WhoamiResponse = response
serde_json::from_str(response.text().await.unwrap().as_str()).unwrap(); .json()
.await
.map_err(|e| ClientError::JSONDecode(e, opid))?;
Ok(Some((r.youare, r.uat))) Ok(Some((r.youare, r.uat)))
} }

View file

@ -1,5 +1,12 @@
#![deny(warnings)] #![deny(warnings)]
#![warn(unused_extern_crates)] #![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@ -8,6 +15,7 @@ use reqwest::header::CONTENT_TYPE;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Serialize; use serde::Serialize;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::error::Error as SerdeJsonError;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs::{metadata, File, Metadata}; use std::fs::{metadata, File, Metadata};
use std::io::Read; use std::io::Read;
@ -35,12 +43,13 @@ pub const KOPID: &str = "X-KANIDM-OPID";
#[derive(Debug)] #[derive(Debug)]
pub enum ClientError { pub enum ClientError {
Unauthorized, Unauthorized,
Http(reqwest::StatusCode, Option<OperationError>), Http(reqwest::StatusCode, Option<OperationError>, String),
Transport(reqwest::Error), Transport(reqwest::Error),
AuthenticationFailed, AuthenticationFailed,
JsonParse,
EmptyResponse, EmptyResponse,
TOTPVerifyFailed(Uuid, TOTPSecret), TOTPVerifyFailed(Uuid, TOTPSecret),
JSONDecode(reqwest::Error, String),
JSONEncode(SerdeJsonError),
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -341,7 +350,7 @@ impl KanidmClient {
) -> Result<T, ClientError> { ) -> Result<T, ClientError> {
let dest = format!("{}{}", self.addr, dest); let dest = format!("{}{}", self.addr, dest);
let req_string = serde_json::to_string(&request).unwrap(); let req_string = serde_json::to_string(&request).map_err(ClientError::JSONEncode)?;
let response = self let response = self
.client .client
@ -351,21 +360,21 @@ impl KanidmClient {
.send() .send()
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())), unexpect => return Err(ClientError::Http(unexpect, response.json().ok(), opid)),
} }
// TODO #253: What about errors response
let r: T = response.json().unwrap(); .json()
.map_err(|e| ClientError::JSONDecode(e, opid))
Ok(r)
} }
fn perform_put_request<R: Serialize, T: DeserializeOwned>( fn perform_put_request<R: Serialize, T: DeserializeOwned>(
@ -375,7 +384,7 @@ impl KanidmClient {
) -> Result<T, ClientError> { ) -> Result<T, ClientError> {
let dest = format!("{}{}", self.addr, dest); let dest = format!("{}{}", self.addr, dest);
let req_string = serde_json::to_string(&request).unwrap(); let req_string = serde_json::to_string(&request).map_err(ClientError::JSONEncode)?;
let response = self let response = self
.client .client
@ -385,21 +394,21 @@ impl KanidmClient {
.send() .send()
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())), unexpect => return Err(ClientError::Http(unexpect, response.json().ok(), opid)),
} }
// TODO #253: What about errors response
let r: T = response.json().unwrap(); .json()
.map_err(|e| ClientError::JSONDecode(e, opid))
Ok(r)
} }
fn perform_get_request<T: DeserializeOwned>(&self, dest: &str) -> Result<T, ClientError> { fn perform_get_request<T: DeserializeOwned>(&self, dest: &str) -> Result<T, ClientError> {
@ -410,21 +419,21 @@ impl KanidmClient {
.send() .send()
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())), unexpect => return Err(ClientError::Http(unexpect, response.json().ok(), opid)),
} }
// TODO #253: What about errors response
let r: T = response.json().unwrap(); .json()
.map_err(|e| ClientError::JSONDecode(e, opid))
Ok(r)
} }
fn perform_delete_request(&self, dest: &str) -> Result<bool, ClientError> { fn perform_delete_request(&self, dest: &str) -> Result<bool, ClientError> {
@ -435,36 +444,50 @@ impl KanidmClient {
.send() .send()
.map_err(ClientError::Transport)?; .map_err(ClientError::Transport)?;
let opid = response.headers().get(KOPID); let opid = response
debug!( .headers()
"opid -> {:?}", .get(KOPID)
opid.expect("Missing opid? Refusing to proceed ...") .and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
); .unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())), unexpect => return Err(ClientError::Http(unexpect, response.json().ok(), opid)),
} }
let r: bool = response.json().unwrap(); response
.json()
Ok(r) .map_err(|e| ClientError::JSONDecode(e, opid))
} }
// whoami // whoami
// Can't use generic get due to possible un-auth case. // Can't use generic get due to possible un-auth case.
pub fn whoami(&self) -> Result<Option<(Entry, UserAuthToken)>, ClientError> { pub fn whoami(&self) -> Result<Option<(Entry, UserAuthToken)>, ClientError> {
let whoami_dest = format!("{}/v1/self", self.addr); let whoami_dest = format!("{}/v1/self", self.addr);
let response = self.client.get(whoami_dest.as_str()).send().unwrap(); let response = self
.client
.get(whoami_dest.as_str())
.send()
.map_err(ClientError::Transport)?;
let opid = response
.headers()
.get(KOPID)
.and_then(|hv| hv.to_str().ok().map(|s| s.to_string()))
.unwrap_or_else(|| "missing_kopid".to_string());
debug!("opid -> {:?}", opid);
match response.status() { match response.status() {
// Continue to process. // Continue to process.
reqwest::StatusCode::OK => {} reqwest::StatusCode::OK => {}
reqwest::StatusCode::UNAUTHORIZED => return Ok(None), reqwest::StatusCode::UNAUTHORIZED => return Ok(None),
unexpect => return Err(ClientError::Http(unexpect, response.json().ok())), unexpect => return Err(ClientError::Http(unexpect, response.json().ok(), opid)),
} }
let r: WhoamiResponse = serde_json::from_str(response.text().unwrap().as_str()).unwrap(); let r: WhoamiResponse = response
.json()
.map_err(|e| ClientError::JSONDecode(e, opid))?;
Ok(Some((r.youare, r.uat))) Ok(Some((r.youare, r.uat)))
} }
@ -608,12 +631,12 @@ impl KanidmClient {
self.perform_get_request(format!("/v1/group/{}/_attr/member", id).as_str()) self.perform_get_request(format!("/v1/group/{}/_attr/member", id).as_str())
} }
pub fn idm_group_set_members(&self, id: &str, members: Vec<&str>) -> Result<bool, ClientError> { pub fn idm_group_set_members(&self, id: &str, members: &[&str]) -> Result<bool, ClientError> {
let m: Vec<_> = members.iter().map(|v| (*v).to_string()).collect(); let m: Vec<_> = members.iter().map(|v| (*v).to_string()).collect();
self.perform_put_request(format!("/v1/group/{}/_attr/member", id).as_str(), m) self.perform_put_request(format!("/v1/group/{}/_attr/member", id).as_str(), m)
} }
pub fn idm_group_add_members(&self, id: &str, members: Vec<&str>) -> Result<bool, ClientError> { pub fn idm_group_add_members(&self, id: &str, members: &[&str]) -> Result<bool, ClientError> {
let m: Vec<_> = members.iter().map(|v| (*v).to_string()).collect(); let m: Vec<_> = members.iter().map(|v| (*v).to_string()).collect();
self.perform_post_request(format!("/v1/group/{}/_attr/member", id).as_str(), m) self.perform_post_request(format!("/v1/group/{}/_attr/member", id).as_str(), m)
} }
@ -881,7 +904,12 @@ impl KanidmClient {
// pub fn idm_domain_get_attr // pub fn idm_domain_get_attr
pub fn idm_domain_get_ssid(&self, id: &str) -> Result<String, ClientError> { pub fn idm_domain_get_ssid(&self, id: &str) -> Result<String, ClientError> {
self.perform_get_request(format!("/v1/domain/{}/_attr/domain_ssid", id).as_str()) self.perform_get_request(format!("/v1/domain/{}/_attr/domain_ssid", id).as_str())
.and_then(|mut r: Vec<String>| Ok(r.pop().unwrap())) .and_then(|mut r: Vec<String>|
// Get the first result
r.pop()
.ok_or(
ClientError::EmptyResponse
))
} }
// pub fn idm_domain_put_attr // pub fn idm_domain_put_attr

View file

@ -63,9 +63,7 @@ fn create_user(rsclient: &KanidmClient, id: &str, group_name: &str) -> () {
None => rsclient.idm_group_create(&group_name).unwrap(), None => rsclient.idm_group_create(&group_name).unwrap(),
}; };
rsclient rsclient.idm_group_add_members(&group_name, &[id]).unwrap();
.idm_group_add_members(&group_name, vec![id])
.unwrap();
} }
fn is_attr_writable(rsclient: &KanidmClient, id: &str, attr: &str) -> Option<bool> { fn is_attr_writable(rsclient: &KanidmClient, id: &str, attr: &str) -> Option<bool> {
@ -115,7 +113,7 @@ fn is_attr_writable(rsclient: &KanidmClient, id: &str, attr: &str) -> Option<boo
fn add_all_attrs(mut rsclient: &mut KanidmClient, id: &str, group_name: &str) { fn add_all_attrs(mut rsclient: &mut KanidmClient, id: &str, group_name: &str) {
// Extend with posix attrs to test read attr: gidnumber and loginshell // Extend with posix attrs to test read attr: gidnumber and loginshell
rsclient rsclient
.idm_group_add_members("idm_admins", vec!["admin"]) .idm_group_add_members("idm_admins", &["admin"])
.unwrap(); .unwrap();
rsclient rsclient
.idm_account_unix_extend(id, None, Some(&"/bin/bash")) .idm_account_unix_extend(id, None, Some(&"/bin/bash"))
@ -157,10 +155,10 @@ fn create_user_with_all_attrs(
fn login_account(rsclient: &mut KanidmClient, id: &str) -> () { fn login_account(rsclient: &mut KanidmClient, id: &str) -> () {
rsclient rsclient
.idm_group_add_members("idm_people_account_password_import_priv", vec!["admin"]) .idm_group_add_members("idm_people_account_password_import_priv", &["admin"])
.unwrap(); .unwrap();
rsclient rsclient
.idm_group_add_members("idm_people_extend_priv", vec!["admin"]) .idm_group_add_members("idm_people_extend_priv", &["admin"])
.unwrap(); .unwrap();
rsclient rsclient
@ -215,7 +213,7 @@ fn test_modify_group(rsclient: &KanidmClient, group_names: &[&str], is_modificab
["description", "name"].iter().for_each(|attr| { ["description", "name"].iter().for_each(|attr| {
assert!(is_attr_writable(&rsclient, group, attr).unwrap() == is_modificable) assert!(is_attr_writable(&rsclient, group, attr).unwrap() == is_modificable)
}); });
assert!(rsclient.idm_group_add_members(group, vec!["test"]).is_ok() == is_modificable); assert!(rsclient.idm_group_add_members(group, &["test"]).is_ok() == is_modificable);
}); });
} }
@ -326,7 +324,7 @@ fn test_default_entries_rbac_group_managers() {
rsclient.idm_group_create("test_group").unwrap(); rsclient.idm_group_create("test_group").unwrap();
rsclient rsclient
.idm_group_add_members("test_group", vec!["test"]) .idm_group_add_members("test_group", &["test"])
.unwrap(); .unwrap();
assert!(is_attr_writable(&rsclient, "test_group", "description").unwrap()); assert!(is_attr_writable(&rsclient, "test_group", "description").unwrap());
}); });
@ -588,7 +586,7 @@ fn test_default_entries_rbac_anonymous_entry() {
.unwrap(); .unwrap();
create_user_with_all_attrs(&mut rsclient, "test", Some("test_group")); create_user_with_all_attrs(&mut rsclient, "test", Some("test_group"));
rsclient rsclient
.idm_group_add_members("test_group", vec!["anonymous"]) .idm_group_add_members("test_group", &["anonymous"])
.unwrap(); .unwrap();
add_all_attrs(&mut rsclient, "anonymous", "test_group"); add_all_attrs(&mut rsclient, "anonymous", "test_group");

View file

@ -251,14 +251,14 @@ fn test_server_rest_group_lifecycle() {
// Add a member. // Add a member.
rsclient rsclient
.idm_group_add_members("demo_group", vec!["admin"]) .idm_group_add_members("demo_group", &["admin"])
.unwrap(); .unwrap();
let members = rsclient.idm_group_get_members("demo_group").unwrap(); let members = rsclient.idm_group_get_members("demo_group").unwrap();
assert!(members == Some(vec!["admin@example.com".to_string()])); assert!(members == Some(vec!["admin@example.com".to_string()]));
// Set the list of members // Set the list of members
rsclient rsclient
.idm_group_set_members("demo_group", vec!["admin", "demo_group"]) .idm_group_set_members("demo_group", &["admin", "demo_group"])
.unwrap(); .unwrap();
let members = rsclient.idm_group_get_members("demo_group").unwrap(); let members = rsclient.idm_group_get_members("demo_group").unwrap();
assert!( assert!(
@ -395,7 +395,7 @@ fn test_server_rest_account_lifecycle() {
// To enable the admin to actually make some of these changes, we have // To enable the admin to actually make some of these changes, we have
// to make them a people admin. NOT recommended in production! // to make them a people admin. NOT recommended in production!
rsclient rsclient
.idm_group_add_members("idm_account_write_priv", vec!["admin"]) .idm_group_add_members("idm_account_write_priv", &["admin"])
.unwrap(); .unwrap();
// Create a new account // Create a new account
@ -499,7 +499,7 @@ fn test_server_rest_posix_lifecycle() {
assert!(res.is_ok()); assert!(res.is_ok());
// Not recommended in production! // Not recommended in production!
rsclient rsclient
.idm_group_add_members("idm_admins", vec!["admin"]) .idm_group_add_members("idm_admins", &["admin"])
.unwrap(); .unwrap();
// Create a new account // Create a new account
@ -517,7 +517,7 @@ fn test_server_rest_posix_lifecycle() {
// Extend the group with posix attrs // Extend the group with posix attrs
rsclient.idm_group_create("posix_group").unwrap(); rsclient.idm_group_create("posix_group").unwrap();
rsclient rsclient
.idm_group_add_members("posix_group", vec!["posix_account"]) .idm_group_add_members("posix_group", &["posix_account"])
.unwrap(); .unwrap();
rsclient.idm_group_unix_extend("posix_group", None).unwrap(); rsclient.idm_group_unix_extend("posix_group", None).unwrap();
@ -576,7 +576,7 @@ fn test_server_rest_posix_auth_lifecycle() {
// Not recommended in production! // Not recommended in production!
rsclient rsclient
.idm_group_add_members("idm_admins", vec!["admin"]) .idm_group_add_members("idm_admins", &["admin"])
.unwrap(); .unwrap();
// Setup a unix user // Setup a unix user
@ -634,7 +634,7 @@ fn test_server_rest_recycle_lifecycle() {
// Not recommended in production! // Not recommended in production!
rsclient rsclient
.idm_group_add_members("idm_admins", vec!["admin"]) .idm_group_add_members("idm_admins", &["admin"])
.unwrap(); .unwrap();
// Setup a unix user // Setup a unix user
@ -674,10 +674,10 @@ fn test_server_rest_account_import_password() {
// To enable the admin to actually make some of these changes, we have // To enable the admin to actually make some of these changes, we have
// to make them a password import admin. NOT recommended in production! // to make them a password import admin. NOT recommended in production!
rsclient rsclient
.idm_group_add_members("idm_people_account_password_import_priv", vec!["admin"]) .idm_group_add_members("idm_people_account_password_import_priv", &["admin"])
.unwrap(); .unwrap();
rsclient rsclient
.idm_group_add_members("idm_people_extend_priv", vec!["admin"]) .idm_group_add_members("idm_people_extend_priv", &["admin"])
.unwrap(); .unwrap();
// Create a new account // Create a new account
@ -718,7 +718,7 @@ fn test_server_rest_totp_auth_lifecycle() {
// Not recommended in production! // Not recommended in production!
rsclient rsclient
.idm_group_add_members("idm_admins", vec!["admin"]) .idm_group_add_members("idm_admins", &["admin"])
.unwrap(); .unwrap();
// Create a new account // Create a new account

View file

@ -171,70 +171,82 @@ impl AccountOpt {
} }
}; };
client if let Err(e) = client.idm_account_primary_credential_set_password(
.idm_account_primary_credential_set_password(
acsopt.aopts.account_id.as_str(), acsopt.aopts.account_id.as_str(),
password.as_str(), password.as_str(),
) ) {
.unwrap(); eprintln!("Error -> {:?}", e);
}
} }
AccountCredential::GeneratePassword(acsopt) => { AccountCredential::GeneratePassword(acsopt) => {
let client = acsopt.copt.to_client(); let client = acsopt.copt.to_client();
let npw = client match client.idm_account_primary_credential_set_generated(
.idm_account_primary_credential_set_generated(
acsopt.aopts.account_id.as_str(), acsopt.aopts.account_id.as_str(),
) ) {
.unwrap(); Ok(npw) => {
println!( println!(
"Generated password for {}: {}", "Generated password for {}: {}",
acsopt.aopts.account_id, npw acsopt.aopts.account_id, npw
); );
} }
Err(e) => {
eprintln!("Error -> {:?}", e);
}
}
}
}, // end AccountOpt::Credential }, // end AccountOpt::Credential
AccountOpt::Radius(aropt) => match aropt { AccountOpt::Radius(aropt) => match aropt {
AccountRadius::Show(aopt) => { AccountRadius::Show(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
let rcred = client let rcred =
.idm_account_radius_credential_get(aopt.aopts.account_id.as_str()) client.idm_account_radius_credential_get(aopt.aopts.account_id.as_str());
.unwrap();
match rcred { match rcred {
Some(s) => println!("Radius secret: {}", s), Ok(Some(s)) => println!("Radius secret: {}", s),
None => println!("NO Radius secret"), Ok(None) => println!("NO Radius secret"),
Err(e) => {
eprintln!("Error -> {:?}", e);
}
} }
} }
AccountRadius::Generate(aopt) => { AccountRadius::Generate(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
client if let Err(e) = client
.idm_account_radius_credential_regenerate(aopt.aopts.account_id.as_str()) .idm_account_radius_credential_regenerate(aopt.aopts.account_id.as_str())
.unwrap(); {
eprintln!("Error -> {:?}", e);
}
} }
AccountRadius::Delete(aopt) => { AccountRadius::Delete(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
client if let Err(e) =
.idm_account_radius_credential_delete(aopt.aopts.account_id.as_str()) client.idm_account_radius_credential_delete(aopt.aopts.account_id.as_str())
.unwrap(); {
eprintln!("Error -> {:?}", e);
}
} }
}, // end AccountOpt::Radius }, // end AccountOpt::Radius
AccountOpt::Posix(apopt) => match apopt { AccountOpt::Posix(apopt) => match apopt {
AccountPosix::Show(aopt) => { AccountPosix::Show(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
let token = client match client.idm_account_unix_token_get(aopt.aopts.account_id.as_str()) {
.idm_account_unix_token_get(aopt.aopts.account_id.as_str()) Ok(token) => println!("{}", token),
.unwrap(); Err(e) => {
println!("{}", token); eprintln!("Error -> {:?}", e);
}
}
} }
AccountPosix::Set(aopt) => { AccountPosix::Set(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
client if let Err(e) = client.idm_account_unix_extend(
.idm_account_unix_extend(
aopt.aopts.account_id.as_str(), aopt.aopts.account_id.as_str(),
aopt.gidnumber, aopt.gidnumber,
aopt.shell.as_deref(), aopt.shell.as_deref(),
) ) {
.unwrap(); eprintln!("Error -> {:?}", e);
}
} }
AccountPosix::SetPassword(aopt) => { AccountPosix::SetPassword(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
@ -246,77 +258,74 @@ impl AccountOpt {
} }
}; };
client if let Err(e) = client.idm_account_unix_cred_put(
.idm_account_unix_cred_put(
aopt.aopts.account_id.as_str(), aopt.aopts.account_id.as_str(),
password.as_str(), password.as_str(),
) ) {
.unwrap(); eprintln!("Error -> {:?}", e);
}
} }
}, // end AccountOpt::Posix }, // end AccountOpt::Posix
AccountOpt::Ssh(asopt) => match asopt { AccountOpt::Ssh(asopt) => match asopt {
AccountSsh::List(aopt) => { AccountSsh::List(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
let pkeys = client match client.idm_account_get_ssh_pubkeys(aopt.aopts.account_id.as_str()) {
.idm_account_get_ssh_pubkeys(aopt.aopts.account_id.as_str()) Ok(pkeys) => pkeys.iter().for_each(|pkey| println!("{}", pkey)),
.unwrap(); Err(e) => {
eprintln!("Error -> {:?}", e);
for pkey in pkeys { }
println!("{}", pkey)
} }
} }
AccountSsh::Add(aopt) => { AccountSsh::Add(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
client if let Err(e) = client.idm_account_post_ssh_pubkey(
.idm_account_post_ssh_pubkey(
aopt.aopts.account_id.as_str(), aopt.aopts.account_id.as_str(),
aopt.tag.as_str(), aopt.tag.as_str(),
aopt.pubkey.as_str(), aopt.pubkey.as_str(),
) ) {
.unwrap(); eprintln!("Error -> {:?}", e);
}
} }
AccountSsh::Delete(aopt) => { AccountSsh::Delete(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
client if let Err(e) = client.idm_account_delete_ssh_pubkey(
.idm_account_delete_ssh_pubkey(
aopt.aopts.account_id.as_str(), aopt.aopts.account_id.as_str(),
aopt.tag.as_str(), aopt.tag.as_str(),
) ) {
.unwrap(); eprintln!("Error -> {:?}", e);
}
} }
}, // end AccountOpt::Ssh }, // end AccountOpt::Ssh
AccountOpt::List(copt) => { AccountOpt::List(copt) => {
let client = copt.to_client(); let client = copt.to_client();
let r = client.idm_account_list().unwrap(); match client.idm_account_list() {
for e in r { Ok(r) => r.iter().for_each(|ent| println!("{}", ent)),
println!("{}", e); Err(e) => eprintln!("Error -> {:?}", e),
} }
} }
AccountOpt::Get(aopt) => { AccountOpt::Get(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
let e = client match client.idm_account_get(aopt.aopts.account_id.as_str()) {
.idm_account_get(aopt.aopts.account_id.as_str()) Ok(Some(e)) => println!("{}", e),
.unwrap(); Ok(None) => println!("No matching entries"),
match e { Err(e) => eprintln!("Error -> {:?}", e),
Some(e) => println!("{}", e),
None => println!("No matching entries"),
} }
} }
AccountOpt::Delete(aopt) => { AccountOpt::Delete(aopt) => {
let client = aopt.copt.to_client(); let client = aopt.copt.to_client();
client if let Err(e) = client.idm_account_delete(aopt.aopts.account_id.as_str()) {
.idm_account_delete(aopt.aopts.account_id.as_str()) eprintln!("Error -> {:?}", e)
.unwrap(); }
} }
AccountOpt::Create(acopt) => { AccountOpt::Create(acopt) => {
let client = acopt.copt.to_client(); let client = acopt.copt.to_client();
client if let Err(e) = client.idm_account_create(
.idm_account_create(
acopt.aopts.account_id.as_str(), acopt.aopts.account_id.as_str(),
acopt.display_name.as_str(), acopt.display_name.as_str(),
) ) {
.unwrap(); eprintln!("Error -> {:?}", e)
}
} }
} }
} }

View file

@ -27,35 +27,54 @@ impl CommonOpt {
let config_path: String = shellexpand::tilde("~/.config/kanidm").into_owned(); let config_path: String = shellexpand::tilde("~/.config/kanidm").into_owned();
debug!("Attempting to use config {}", "/etc/kanidm/config"); debug!("Attempting to use config {}", "/etc/kanidm/config");
let client_builder = KanidmClientBuilder::new() let client_builder = match KanidmClientBuilder::new()
.read_options_from_optional_config("/etc/kanidm/config") .read_options_from_optional_config("/etc/kanidm/config")
.and_then(|cb| { .and_then(|cb| {
debug!("Attempting to use config {}", config_path); debug!("Attempting to use config {}", config_path);
cb.read_options_from_optional_config(config_path) cb.read_options_from_optional_config(config_path)
}) }) {
.expect("Failed to parse config (if present)"); Ok(c) => c,
Err(e) => {
error!("Failed to parse config (if present) -- {:?}", e);
std::process::exit(1);
}
};
let client_builder = match &self.addr { let client_builder = match &self.addr {
Some(a) => client_builder.address(a.to_string()), Some(a) => client_builder.address(a.to_string()),
None => client_builder, None => client_builder,
}; };
let ca_path: Option<&str> = self.ca_path.as_ref().map(|p| p.to_str().unwrap()); let ca_path: Option<&str> = self.ca_path.as_ref().map(|p| p.to_str()).flatten();
let client_builder = match ca_path { let client_builder = match ca_path {
Some(p) => client_builder Some(p) => match client_builder.add_root_certificate_filepath(p) {
.add_root_certificate_filepath(p) Ok(cb) => cb,
.expect("Failed to access CA file"), Err(e) => {
error!("Failed to add ca certificate -- {:?}", e);
std::process::exit(1);
}
},
None => client_builder, None => client_builder,
}; };
let client = client_builder let client = match client_builder.build() {
.build() Ok(c) => c,
.expect("Failed to build client instance"); Err(e) => {
error!("Failed to build client instance -- {:?}", e);
std::process::exit(1);
}
};
let r = if self.username == "anonymous" { let r = if self.username == "anonymous" {
client.auth_anonymous() client.auth_anonymous()
} else { } else {
let password = rpassword::prompt_password_stderr("Enter password: ").unwrap(); let password = match rpassword::prompt_password_stderr("Enter password: ") {
Ok(p) => p,
Err(e) => {
error!("Failed to create password prompt -- {:?}", e);
std::process::exit(1);
}
};
client.auth_simple_password(self.username.as_str(), password.as_str()) client.auth_simple_password(self.username.as_str(), password.as_str())
}; };

View file

@ -70,29 +70,38 @@ impl GroupOpt {
match self { match self {
GroupOpt::List(copt) => { GroupOpt::List(copt) => {
let client = copt.to_client(); let client = copt.to_client();
let r = client.idm_group_list().unwrap(); match client.idm_group_list() {
for e in r { Ok(r) => r.iter().for_each(|ent| println!("{}", ent)),
println!("{}", e); Err(e) => {
eprintln!("Error -> {:?}", e);
}
} }
} }
GroupOpt::Create(gcopt) => { GroupOpt::Create(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
client.idm_group_create(gcopt.name.as_str()).unwrap(); if let Err(e) = client.idm_group_create(gcopt.name.as_str()) {
eprintln!("Error -> {:?}", e);
}
} }
GroupOpt::Delete(gcopt) => { GroupOpt::Delete(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
client.idm_group_delete(gcopt.name.as_str()).unwrap(); if let Err(e) = client.idm_group_delete(gcopt.name.as_str()) {
eprintln!("Error -> {:?}", e);
}
} }
GroupOpt::PurgeMembers(gcopt) => { GroupOpt::PurgeMembers(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
client.idm_group_purge_members(gcopt.name.as_str()).unwrap(); if let Err(e) = client.idm_group_purge_members(gcopt.name.as_str()) {
eprintln!("Error -> {:?}", e);
}
} }
GroupOpt::ListMembers(gcopt) => { GroupOpt::ListMembers(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
let members = client.idm_group_get_members(gcopt.name.as_str()).unwrap(); match client.idm_group_get_members(gcopt.name.as_str()) {
if let Some(groups) = members { Ok(Some(groups)) => groups.iter().for_each(|m| println!("{:?}", m)),
for m in groups { Ok(None) => {}
println!("{:?}", m); Err(e) => {
eprintln!("Error -> {:?}", e);
} }
} }
} }
@ -100,31 +109,33 @@ impl GroupOpt {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
let new_members: Vec<&str> = gcopt.members.iter().map(|s| s.as_str()).collect(); let new_members: Vec<&str> = gcopt.members.iter().map(|s| s.as_str()).collect();
client if let Err(e) = client.idm_group_add_members(gcopt.name.as_str(), &new_members) {
.idm_group_add_members(gcopt.name.as_str(), new_members) eprintln!("Error -> {:?}", e);
.unwrap(); }
} }
GroupOpt::SetMembers(gcopt) => { GroupOpt::SetMembers(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
let new_members: Vec<&str> = gcopt.members.iter().map(|s| s.as_str()).collect(); let new_members: Vec<&str> = gcopt.members.iter().map(|s| s.as_str()).collect();
client if let Err(e) = client.idm_group_set_members(gcopt.name.as_str(), &new_members) {
.idm_group_set_members(gcopt.name.as_str(), new_members) eprintln!("Error -> {:?}", e);
.unwrap(); }
} }
GroupOpt::Posix(gpopt) => match gpopt { GroupOpt::Posix(gpopt) => match gpopt {
GroupPosix::Show(gcopt) => { GroupPosix::Show(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
let token = client match client.idm_group_unix_token_get(gcopt.name.as_str()) {
.idm_group_unix_token_get(gcopt.name.as_str()) Ok(token) => println!("{}", token),
.unwrap(); Err(e) => eprintln!("Error -> {:?}", e),
println!("{}", token); }
} }
GroupPosix::Set(gcopt) => { GroupPosix::Set(gcopt) => {
let client = gcopt.copt.to_client(); let client = gcopt.copt.to_client();
client if let Err(e) =
.idm_group_unix_extend(gcopt.name.as_str(), gcopt.gidnumber) client.idm_group_unix_extend(gcopt.name.as_str(), gcopt.gidnumber)
.unwrap(); {
eprintln!("Error -> {:?}", e);
}
} }
}, },
} // end match } // end match

View file

@ -1,3 +1,13 @@
#![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;
use structopt::StructOpt; use structopt::StructOpt;
@ -52,9 +62,17 @@ impl SelfOpt {
SelfOpt::SetPassword(copt) => { SelfOpt::SetPassword(copt) => {
let client = copt.to_client(); let client = copt.to_client();
let password = rpassword::prompt_password_stderr("Enter new password: ").unwrap(); let password = match rpassword::prompt_password_stderr("Enter new password: ") {
Ok(p) => p,
Err(e) => {
eprintln!("Error -> {:?}", e);
return;
}
};
client.idm_account_set_password(password).unwrap(); if let Err(e) = client.idm_account_set_password(password) {
eprintln!("Error -> {:?}", e);
}
} }
} }
} }
@ -103,14 +121,23 @@ impl ClientOpt {
} }
pub(crate) fn password_prompt(prompt: &str) -> Option<String> { pub(crate) fn password_prompt(prompt: &str) -> Option<String> {
let password = rpassword::prompt_password_stderr(prompt).unwrap(); for _ in 0..3 {
let password = match rpassword::prompt_password_stderr(prompt) {
Ok(p) => p,
Err(_e) => return None,
};
let password_confirm = let password_confirm =
rpassword::prompt_password_stderr("Retype the new password to confirm: ").unwrap(); match rpassword::prompt_password_stderr("Retype the new password to confirm: ") {
Ok(p) => p,
Err(_e) => return None,
};
if password == password_confirm { if password == password_confirm {
Some(password) return Some(password);
} else { } else {
eprintln!("Passwords do not match");
}
}
None None
} }
}

View file

@ -11,14 +11,6 @@ use std::path::PathBuf;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
fn read_file<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T, Box<dyn Error>> {
let f = File::open(path)?;
let r = BufReader::new(f);
let t: T = serde_json::from_reader(r)?;
Ok(t)
}
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
pub struct FilterOpt { pub struct FilterOpt {
#[structopt()] #[structopt()]
@ -30,7 +22,7 @@ pub struct FilterOpt {
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
pub struct CreateOpt { pub struct CreateOpt {
#[structopt(parse(from_os_str))] #[structopt(parse(from_os_str))]
file: Option<PathBuf>, file: PathBuf,
#[structopt(flatten)] #[structopt(flatten)]
commonopts: CommonOpt, commonopts: CommonOpt,
} }
@ -42,7 +34,7 @@ pub struct ModifyOpt {
#[structopt()] #[structopt()]
filter: String, filter: String,
#[structopt(parse(from_os_str))] #[structopt(parse(from_os_str))]
file: Option<PathBuf>, file: PathBuf,
} }
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
@ -57,6 +49,14 @@ pub enum RawOpt {
Delete(FilterOpt), Delete(FilterOpt),
} }
fn read_file<T: DeserializeOwned, P: AsRef<Path>>(path: P) -> Result<T, Box<dyn Error>> {
let f = File::open(path)?;
let r = BufReader::new(f);
let t: T = serde_json::from_reader(r)?;
Ok(t)
}
impl RawOpt { impl RawOpt {
pub fn debug(&self) -> bool { pub fn debug(&self) -> bool {
match self { match self {
@ -72,46 +72,75 @@ impl RawOpt {
RawOpt::Search(sopt) => { RawOpt::Search(sopt) => {
let client = sopt.commonopts.to_client(); let client = sopt.commonopts.to_client();
let filter: Filter = serde_json::from_str(sopt.filter.as_str()).unwrap(); let filter: Filter = match serde_json::from_str(sopt.filter.as_str()) {
let rset = client.search(filter).unwrap(); Ok(f) => f,
Err(e) => {
eprintln!("Error -> {:?}", e);
return;
}
};
rset.iter().for_each(|e| { match client.search(filter) {
println!("{}", e); Ok(rset) => rset.iter().for_each(|e| println!("{}", e)),
}); Err(e) => {
eprintln!("Error -> {:?}", e);
}
}
} }
RawOpt::Create(copt) => { RawOpt::Create(copt) => {
let client = copt.commonopts.to_client(); let client = copt.commonopts.to_client();
// Read the file? // Read the file?
match &copt.file { let r_entries: Vec<BTreeMap<String, Vec<String>>> = match read_file(&copt.file) {
Some(p) => { Ok(r) => r,
let r_entries: Vec<BTreeMap<String, Vec<String>>> = read_file(p).unwrap(); Err(e) => {
eprintln!("Error -> {:?}", e);
return;
}
};
let entries = r_entries.into_iter().map(|b| Entry { attrs: b }).collect(); let entries = r_entries.into_iter().map(|b| Entry { attrs: b }).collect();
client.create(entries).unwrap();
} if let Err(e) = client.create(entries) {
None => { eprintln!("Error -> {:?}", e);
println!("Must provide a file");
}
} }
} }
RawOpt::Modify(mopt) => { RawOpt::Modify(mopt) => {
let client = mopt.commonopts.to_client(); let client = mopt.commonopts.to_client();
// Read the file? // Read the file?
match &mopt.file { let filter: Filter = match serde_json::from_str(mopt.filter.as_str()) {
Some(p) => { Ok(f) => f,
let filter: Filter = serde_json::from_str(mopt.filter.as_str()).unwrap(); Err(e) => {
let r_list: Vec<Modify> = read_file(p).unwrap(); eprintln!("Error -> {:?}", e);
return;
}
};
let r_list: Vec<Modify> = match read_file(&mopt.file) {
Ok(r) => r,
Err(e) => {
eprintln!("Error -> {:?}", e);
return;
}
};
let modlist = ModifyList::new_list(r_list); let modlist = ModifyList::new_list(r_list);
client.modify(filter, modlist).unwrap(); if let Err(e) = client.modify(filter, modlist) {
} eprintln!("Error -> {:?}", e);
None => {
println!("Must provide a file");
}
} }
} }
RawOpt::Delete(dopt) => { RawOpt::Delete(dopt) => {
let client = dopt.commonopts.to_client(); let client = dopt.commonopts.to_client();
let filter: Filter = serde_json::from_str(dopt.filter.as_str()).unwrap(); let filter: Filter = match serde_json::from_str(dopt.filter.as_str()) {
client.delete(filter).unwrap(); Ok(f) => f,
Err(e) => {
eprintln!("Error -> {:?}", e);
return;
}
};
if let Err(e) = client.delete(filter) {
eprintln!("Error -> {:?}", e);
}
} }
} }
} }

View file

@ -27,22 +27,28 @@ impl RecycleOpt {
match self { match self {
RecycleOpt::List(copt) => { RecycleOpt::List(copt) => {
let client = copt.to_client(); let client = copt.to_client();
let r = client.recycle_bin_list().unwrap(); match client.recycle_bin_list() {
for e in r { Ok(r) => r.iter().for_each(|e| println!("{}", e)),
println!("{}", e); Err(e) => {
eprintln!("Error -> {:?}", e);
}
} }
} }
RecycleOpt::Get(nopt) => { RecycleOpt::Get(nopt) => {
let client = nopt.copt.to_client(); let client = nopt.copt.to_client();
let e = client.recycle_bin_get(nopt.name.as_str()).unwrap(); match client.recycle_bin_get(nopt.name.as_str()) {
match e { Ok(Some(e)) => println!("{}", e),
Some(e) => println!("{}", e), Ok(None) => println!("No matching entries"),
None => println!("No matching entries"), Err(e) => {
eprintln!("Error -> {:?}", e);
}
} }
} }
RecycleOpt::Revive(nopt) => { RecycleOpt::Revive(nopt) => {
let client = nopt.copt.to_client(); let client = nopt.copt.to_client();
client.recycle_bin_revive(nopt.name.as_str()).unwrap(); if let Err(e) = client.recycle_bin_revive(nopt.name.as_str()) {
eprintln!("Error -> {:?}", e);
}
} }
} }
} }

View file

@ -1,4 +1,13 @@
#![deny(warnings)] #![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[macro_use] #[macro_use]
extern crate libnss; extern crate libnss;
#[macro_use] #[macro_use]

View file

@ -1,5 +1,14 @@
#![deny(warnings)] #![deny(warnings)]
extern crate libc; #![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
// extern crate libc;
mod pam; mod pam;
use crate::pam::constants::*; use crate::pam::constants::*;

View file

@ -271,8 +271,12 @@ impl CacheLayer {
ClientError::Http( ClientError::Http(
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,
Some(OperationError::NotAuthenticated), Some(OperationError::NotAuthenticated),
opid,
) => { ) => {
error!("transport unauthenticated, moving to offline"); error!(
"transport unauthenticated, moving to offline - eventid {}",
opid
);
// Something went wrong, mark offline. // Something went wrong, mark offline.
let time = SystemTime::now().add(Duration::from_secs(15)); let time = SystemTime::now().add(Duration::from_secs(15));
self.set_cachestate(CacheState::OfflineNextCheck(time)) self.set_cachestate(CacheState::OfflineNextCheck(time))
@ -282,14 +286,16 @@ impl CacheLayer {
ClientError::Http( ClientError::Http(
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Some(OperationError::NoMatchingEntries), Some(OperationError::NoMatchingEntries),
opid,
) )
| ClientError::Http( | ClientError::Http(
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Some(OperationError::InvalidAccountState(_)), Some(OperationError::InvalidAccountState(_)),
opid,
) => { ) => {
// We wele able to contact the server but the entry has been removed, or // We wele able to contact the server but the entry has been removed, or
// is not longer a valid posix account. // is not longer a valid posix account.
debug!("entry has been removed or is no longer a valid posix account, clearing from cache ..."); debug!("entry has been removed or is no longer a valid posix account, clearing from cache ... - eventid {}", opid);
token token
.map(|tok| self.delete_cache_usertoken(&tok.uuid)) .map(|tok| self.delete_cache_usertoken(&tok.uuid))
// Now an option<result<t, _>> // Now an option<result<t, _>>
@ -335,8 +341,12 @@ impl CacheLayer {
ClientError::Http( ClientError::Http(
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,
Some(OperationError::NotAuthenticated), Some(OperationError::NotAuthenticated),
opid,
) => { ) => {
error!("transport unauthenticated, moving to offline"); error!(
"transport unauthenticated, moving to offline - eventid {}",
opid
);
// Something went wrong, mark offline. // Something went wrong, mark offline.
let time = SystemTime::now().add(Duration::from_secs(15)); let time = SystemTime::now().add(Duration::from_secs(15));
self.set_cachestate(CacheState::OfflineNextCheck(time)) self.set_cachestate(CacheState::OfflineNextCheck(time))
@ -346,12 +356,14 @@ impl CacheLayer {
ClientError::Http( ClientError::Http(
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Some(OperationError::NoMatchingEntries), Some(OperationError::NoMatchingEntries),
opid,
) )
| ClientError::Http( | ClientError::Http(
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Some(OperationError::InvalidAccountState(_)), Some(OperationError::InvalidAccountState(_)),
opid,
) => { ) => {
debug!("entry has been removed or is no longer a valid posix group, clearing from cache ..."); debug!("entry has been removed or is no longer a valid posix group, clearing from cache ... - eventid {}", opid);
token token
.map(|tok| self.delete_cache_grouptoken(&tok.uuid)) .map(|tok| self.delete_cache_grouptoken(&tok.uuid))
// Now an option<result<t, _>> // Now an option<result<t, _>>
@ -620,8 +632,12 @@ impl CacheLayer {
ClientError::Http( ClientError::Http(
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,
Some(OperationError::NotAuthenticated), Some(OperationError::NotAuthenticated),
opid,
) => { ) => {
error!("transport unauthenticated, moving to offline"); error!(
"transport unauthenticated, moving to offline - eventid {}",
opid
);
// Something went wrong, mark offline. // Something went wrong, mark offline.
let time = SystemTime::now().add(Duration::from_secs(15)); let time = SystemTime::now().add(Duration::from_secs(15));
self.set_cachestate(CacheState::OfflineNextCheck(time)) self.set_cachestate(CacheState::OfflineNextCheck(time))
@ -634,12 +650,17 @@ impl CacheLayer {
ClientError::Http( ClientError::Http(
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Some(OperationError::NoMatchingEntries), Some(OperationError::NoMatchingEntries),
opid,
) )
| ClientError::Http( | ClientError::Http(
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Some(OperationError::InvalidAccountState(_)), Some(OperationError::InvalidAccountState(_)),
opid,
) => { ) => {
error!("unknown account or is not a valid posix account"); error!(
"unknown account or is not a valid posix account - eventid {}",
opid
);
Ok(None) Ok(None)
} }
er => { er => {

View file

@ -1,4 +1,13 @@
#![deny(warnings)] #![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View file

@ -7,7 +7,7 @@ use std::convert::TryFrom;
use std::fmt; use std::fmt;
use crate::cache::Id; use crate::cache::Id;
use std::sync::{Mutex, MutexGuard}; use tokio::sync::{Mutex, MutexGuard};
use kanidm::be::dbvalue::DbPasswordV1; use kanidm::be::dbvalue::DbPasswordV1;
use kanidm::credential::Password; use kanidm::credential::Password;

View file

@ -1,5 +1,12 @@
#![deny(warnings)] #![deny(warnings)]
#![warn(unused_extern_crates)] #![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;

View file

@ -101,7 +101,7 @@ fn test_fixture(rsclient: &KanidmClient) -> () {
assert!(res.is_ok()); assert!(res.is_ok());
// Not recommended in production! // Not recommended in production!
rsclient rsclient
.idm_group_add_members("idm_admins", vec!["admin"]) .idm_group_add_members("idm_admins", &["admin"])
.unwrap(); .unwrap();
// Create a new account // Create a new account
@ -126,7 +126,7 @@ fn test_fixture(rsclient: &KanidmClient) -> () {
// Setup a group // Setup a group
rsclient.idm_group_create("testgroup1").unwrap(); rsclient.idm_group_create("testgroup1").unwrap();
rsclient rsclient
.idm_group_add_members("testgroup1", vec!["testaccount1"]) .idm_group_add_members("testgroup1", &["testaccount1"])
.unwrap(); .unwrap();
rsclient rsclient
.idm_group_unix_extend("testgroup1", Some(20001)) .idm_group_unix_extend("testgroup1", Some(20001))

View file

@ -63,12 +63,12 @@ macro_rules! try_from_entry {
let uuid = $value.get_uuid().clone(); let uuid = $value.get_uuid().clone();
Ok(Account { Ok(Account {
uuid: uuid, uuid,
name: name, name,
displayname: displayname, displayname,
groups: groups, groups,
primary: primary, primary,
spn: spn, spn,
}) })
}}; }};
} }

View file

@ -1,5 +1,12 @@
#![deny(warnings)] #![deny(warnings)]
#![warn(unused_extern_crates)] #![warn(unused_extern_crates)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;