mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Cleanup and improve client error handling
This commit is contained in:
parent
c4805d2915
commit
217e3455a2
|
@ -23,7 +23,7 @@ impl KanidmAsyncClient {
|
|||
// format doesn't work in async ?!
|
||||
// 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
|
||||
.client
|
||||
|
@ -34,21 +34,28 @@ impl KanidmAsyncClient {
|
|||
.await
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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
|
||||
let r: T = response.json().await.unwrap();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
async fn perform_put_request<R: Serialize, T: DeserializeOwned>(
|
||||
|
@ -61,7 +68,7 @@ impl KanidmAsyncClient {
|
|||
// format doesn't work in async ?!
|
||||
// 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
|
||||
.client
|
||||
|
@ -72,21 +79,29 @@ impl KanidmAsyncClient {
|
|||
.await
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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
|
||||
let r: T = response.json().await.unwrap();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
async fn perform_get_request<T: DeserializeOwned>(&self, dest: &str) -> Result<T, ClientError> {
|
||||
|
@ -100,21 +115,29 @@ impl KanidmAsyncClient {
|
|||
.await
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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
|
||||
let r: T = response.json().await.unwrap();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
async fn perform_delete_request(&self, dest: &str) -> Result<bool, ClientError> {
|
||||
|
@ -126,20 +149,28 @@ impl KanidmAsyncClient {
|
|||
.await
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
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();
|
||||
// format!("{}/v1/self", self.addr);
|
||||
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() {
|
||||
// Continue to process.
|
||||
reqwest::StatusCode::OK => {}
|
||||
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 =
|
||||
serde_json::from_str(response.text().await.unwrap().as_str()).unwrap();
|
||||
let r: WhoamiResponse = response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))?;
|
||||
|
||||
Ok(Some((r.youare, r.uat)))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#![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]
|
||||
extern crate log;
|
||||
|
@ -8,6 +15,7 @@ use reqwest::header::CONTENT_TYPE;
|
|||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use serde_derive::Deserialize;
|
||||
use serde_json::error::Error as SerdeJsonError;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{metadata, File, Metadata};
|
||||
use std::io::Read;
|
||||
|
@ -35,12 +43,13 @@ pub const KOPID: &str = "X-KANIDM-OPID";
|
|||
#[derive(Debug)]
|
||||
pub enum ClientError {
|
||||
Unauthorized,
|
||||
Http(reqwest::StatusCode, Option<OperationError>),
|
||||
Http(reqwest::StatusCode, Option<OperationError>, String),
|
||||
Transport(reqwest::Error),
|
||||
AuthenticationFailed,
|
||||
JsonParse,
|
||||
EmptyResponse,
|
||||
TOTPVerifyFailed(Uuid, TOTPSecret),
|
||||
JSONDecode(reqwest::Error, String),
|
||||
JSONEncode(SerdeJsonError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -341,7 +350,7 @@ impl KanidmClient {
|
|||
) -> Result<T, ClientError> {
|
||||
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
|
||||
.client
|
||||
|
@ -351,21 +360,21 @@ impl KanidmClient {
|
|||
.send()
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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
|
||||
let r: T = response.json().unwrap();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
fn perform_put_request<R: Serialize, T: DeserializeOwned>(
|
||||
|
@ -375,7 +384,7 @@ impl KanidmClient {
|
|||
) -> Result<T, ClientError> {
|
||||
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
|
||||
.client
|
||||
|
@ -385,21 +394,21 @@ impl KanidmClient {
|
|||
.send()
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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
|
||||
let r: T = response.json().unwrap();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
fn perform_get_request<T: DeserializeOwned>(&self, dest: &str) -> Result<T, ClientError> {
|
||||
|
@ -410,21 +419,21 @@ impl KanidmClient {
|
|||
.send()
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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
|
||||
let r: T = response.json().unwrap();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
fn perform_delete_request(&self, dest: &str) -> Result<bool, ClientError> {
|
||||
|
@ -435,36 +444,50 @@ impl KanidmClient {
|
|||
.send()
|
||||
.map_err(ClientError::Transport)?;
|
||||
|
||||
let opid = response.headers().get(KOPID);
|
||||
debug!(
|
||||
"opid -> {:?}",
|
||||
opid.expect("Missing opid? Refusing to proceed ...")
|
||||
);
|
||||
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() {
|
||||
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();
|
||||
|
||||
Ok(r)
|
||||
response
|
||||
.json()
|
||||
.map_err(|e| ClientError::JSONDecode(e, opid))
|
||||
}
|
||||
|
||||
// whoami
|
||||
// Can't use generic get due to possible un-auth case.
|
||||
pub fn whoami(&self) -> Result<Option<(Entry, UserAuthToken)>, ClientError> {
|
||||
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() {
|
||||
// Continue to process.
|
||||
reqwest::StatusCode::OK => {}
|
||||
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)))
|
||||
}
|
||||
|
@ -608,12 +631,12 @@ impl KanidmClient {
|
|||
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();
|
||||
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();
|
||||
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_ssid(&self, id: &str) -> Result<String, ClientError> {
|
||||
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
|
||||
|
|
|
@ -63,9 +63,7 @@ fn create_user(rsclient: &KanidmClient, id: &str, group_name: &str) -> () {
|
|||
None => rsclient.idm_group_create(&group_name).unwrap(),
|
||||
};
|
||||
|
||||
rsclient
|
||||
.idm_group_add_members(&group_name, vec![id])
|
||||
.unwrap();
|
||||
rsclient.idm_group_add_members(&group_name, &[id]).unwrap();
|
||||
}
|
||||
|
||||
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) {
|
||||
// Extend with posix attrs to test read attr: gidnumber and loginshell
|
||||
rsclient
|
||||
.idm_group_add_members("idm_admins", vec!["admin"])
|
||||
.idm_group_add_members("idm_admins", &["admin"])
|
||||
.unwrap();
|
||||
rsclient
|
||||
.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) -> () {
|
||||
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();
|
||||
rsclient
|
||||
.idm_group_add_members("idm_people_extend_priv", vec!["admin"])
|
||||
.idm_group_add_members("idm_people_extend_priv", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
rsclient
|
||||
|
@ -215,7 +213,7 @@ fn test_modify_group(rsclient: &KanidmClient, group_names: &[&str], is_modificab
|
|||
["description", "name"].iter().for_each(|attr| {
|
||||
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_add_members("test_group", vec!["test"])
|
||||
.idm_group_add_members("test_group", &["test"])
|
||||
.unwrap();
|
||||
assert!(is_attr_writable(&rsclient, "test_group", "description").unwrap());
|
||||
});
|
||||
|
@ -588,7 +586,7 @@ fn test_default_entries_rbac_anonymous_entry() {
|
|||
.unwrap();
|
||||
create_user_with_all_attrs(&mut rsclient, "test", Some("test_group"));
|
||||
rsclient
|
||||
.idm_group_add_members("test_group", vec!["anonymous"])
|
||||
.idm_group_add_members("test_group", &["anonymous"])
|
||||
.unwrap();
|
||||
add_all_attrs(&mut rsclient, "anonymous", "test_group");
|
||||
|
||||
|
|
|
@ -251,14 +251,14 @@ fn test_server_rest_group_lifecycle() {
|
|||
|
||||
// Add a member.
|
||||
rsclient
|
||||
.idm_group_add_members("demo_group", vec!["admin"])
|
||||
.idm_group_add_members("demo_group", &["admin"])
|
||||
.unwrap();
|
||||
let members = rsclient.idm_group_get_members("demo_group").unwrap();
|
||||
assert!(members == Some(vec!["admin@example.com".to_string()]));
|
||||
|
||||
// Set the list of members
|
||||
rsclient
|
||||
.idm_group_set_members("demo_group", vec!["admin", "demo_group"])
|
||||
.idm_group_set_members("demo_group", &["admin", "demo_group"])
|
||||
.unwrap();
|
||||
let members = rsclient.idm_group_get_members("demo_group").unwrap();
|
||||
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 make them a people admin. NOT recommended in production!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_account_write_priv", vec!["admin"])
|
||||
.idm_group_add_members("idm_account_write_priv", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Create a new account
|
||||
|
@ -499,7 +499,7 @@ fn test_server_rest_posix_lifecycle() {
|
|||
assert!(res.is_ok());
|
||||
// Not recommended in production!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_admins", vec!["admin"])
|
||||
.idm_group_add_members("idm_admins", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Create a new account
|
||||
|
@ -517,7 +517,7 @@ fn test_server_rest_posix_lifecycle() {
|
|||
// Extend the group with posix attrs
|
||||
rsclient.idm_group_create("posix_group").unwrap();
|
||||
rsclient
|
||||
.idm_group_add_members("posix_group", vec!["posix_account"])
|
||||
.idm_group_add_members("posix_group", &["posix_account"])
|
||||
.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!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_admins", vec!["admin"])
|
||||
.idm_group_add_members("idm_admins", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Setup a unix user
|
||||
|
@ -634,7 +634,7 @@ fn test_server_rest_recycle_lifecycle() {
|
|||
|
||||
// Not recommended in production!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_admins", vec!["admin"])
|
||||
.idm_group_add_members("idm_admins", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// 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 make them a password import admin. NOT recommended in production!
|
||||
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();
|
||||
rsclient
|
||||
.idm_group_add_members("idm_people_extend_priv", vec!["admin"])
|
||||
.idm_group_add_members("idm_people_extend_priv", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Create a new account
|
||||
|
@ -718,7 +718,7 @@ fn test_server_rest_totp_auth_lifecycle() {
|
|||
|
||||
// Not recommended in production!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_admins", vec!["admin"])
|
||||
.idm_group_add_members("idm_admins", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Create a new account
|
||||
|
|
|
@ -171,70 +171,82 @@ impl AccountOpt {
|
|||
}
|
||||
};
|
||||
|
||||
client
|
||||
.idm_account_primary_credential_set_password(
|
||||
acsopt.aopts.account_id.as_str(),
|
||||
password.as_str(),
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_primary_credential_set_password(
|
||||
acsopt.aopts.account_id.as_str(),
|
||||
password.as_str(),
|
||||
) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
AccountCredential::GeneratePassword(acsopt) => {
|
||||
let client = acsopt.copt.to_client();
|
||||
|
||||
let npw = client
|
||||
.idm_account_primary_credential_set_generated(
|
||||
acsopt.aopts.account_id.as_str(),
|
||||
)
|
||||
.unwrap();
|
||||
println!(
|
||||
"Generated password for {}: {}",
|
||||
acsopt.aopts.account_id, npw
|
||||
);
|
||||
match client.idm_account_primary_credential_set_generated(
|
||||
acsopt.aopts.account_id.as_str(),
|
||||
) {
|
||||
Ok(npw) => {
|
||||
println!(
|
||||
"Generated password for {}: {}",
|
||||
acsopt.aopts.account_id, npw
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, // end AccountOpt::Credential
|
||||
AccountOpt::Radius(aropt) => match aropt {
|
||||
AccountRadius::Show(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
|
||||
let rcred = client
|
||||
.idm_account_radius_credential_get(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
let rcred =
|
||||
client.idm_account_radius_credential_get(aopt.aopts.account_id.as_str());
|
||||
|
||||
match rcred {
|
||||
Some(s) => println!("Radius secret: {}", s),
|
||||
None => println!("NO Radius secret"),
|
||||
Ok(Some(s)) => println!("Radius secret: {}", s),
|
||||
Ok(None) => println!("NO Radius secret"),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
AccountRadius::Generate(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
client
|
||||
if let Err(e) = client
|
||||
.idm_account_radius_credential_regenerate(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
{
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
AccountRadius::Delete(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
client
|
||||
.idm_account_radius_credential_delete(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
if let Err(e) =
|
||||
client.idm_account_radius_credential_delete(aopt.aopts.account_id.as_str())
|
||||
{
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}, // end AccountOpt::Radius
|
||||
AccountOpt::Posix(apopt) => match apopt {
|
||||
AccountPosix::Show(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
let token = client
|
||||
.idm_account_unix_token_get(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
println!("{}", token);
|
||||
match client.idm_account_unix_token_get(aopt.aopts.account_id.as_str()) {
|
||||
Ok(token) => println!("{}", token),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
AccountPosix::Set(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
client
|
||||
.idm_account_unix_extend(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.gidnumber,
|
||||
aopt.shell.as_deref(),
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_unix_extend(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.gidnumber,
|
||||
aopt.shell.as_deref(),
|
||||
) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
AccountPosix::SetPassword(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
|
@ -246,77 +258,74 @@ impl AccountOpt {
|
|||
}
|
||||
};
|
||||
|
||||
client
|
||||
.idm_account_unix_cred_put(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
password.as_str(),
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_unix_cred_put(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
password.as_str(),
|
||||
) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}, // end AccountOpt::Posix
|
||||
AccountOpt::Ssh(asopt) => match asopt {
|
||||
AccountSsh::List(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
|
||||
let pkeys = client
|
||||
.idm_account_get_ssh_pubkeys(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
|
||||
for pkey in pkeys {
|
||||
println!("{}", pkey)
|
||||
match client.idm_account_get_ssh_pubkeys(aopt.aopts.account_id.as_str()) {
|
||||
Ok(pkeys) => pkeys.iter().for_each(|pkey| println!("{}", pkey)),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
AccountSsh::Add(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
client
|
||||
.idm_account_post_ssh_pubkey(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.tag.as_str(),
|
||||
aopt.pubkey.as_str(),
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_post_ssh_pubkey(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.tag.as_str(),
|
||||
aopt.pubkey.as_str(),
|
||||
) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
AccountSsh::Delete(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
client
|
||||
.idm_account_delete_ssh_pubkey(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.tag.as_str(),
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_delete_ssh_pubkey(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.tag.as_str(),
|
||||
) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}, // end AccountOpt::Ssh
|
||||
AccountOpt::List(copt) => {
|
||||
let client = copt.to_client();
|
||||
let r = client.idm_account_list().unwrap();
|
||||
for e in r {
|
||||
println!("{}", e);
|
||||
match client.idm_account_list() {
|
||||
Ok(r) => r.iter().for_each(|ent| println!("{}", ent)),
|
||||
Err(e) => eprintln!("Error -> {:?}", e),
|
||||
}
|
||||
}
|
||||
AccountOpt::Get(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
let e = client
|
||||
.idm_account_get(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
match e {
|
||||
Some(e) => println!("{}", e),
|
||||
None => println!("No matching entries"),
|
||||
match client.idm_account_get(aopt.aopts.account_id.as_str()) {
|
||||
Ok(Some(e)) => println!("{}", e),
|
||||
Ok(None) => println!("No matching entries"),
|
||||
Err(e) => eprintln!("Error -> {:?}", e),
|
||||
}
|
||||
}
|
||||
AccountOpt::Delete(aopt) => {
|
||||
let client = aopt.copt.to_client();
|
||||
client
|
||||
.idm_account_delete(aopt.aopts.account_id.as_str())
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_delete(aopt.aopts.account_id.as_str()) {
|
||||
eprintln!("Error -> {:?}", e)
|
||||
}
|
||||
}
|
||||
AccountOpt::Create(acopt) => {
|
||||
let client = acopt.copt.to_client();
|
||||
client
|
||||
.idm_account_create(
|
||||
acopt.aopts.account_id.as_str(),
|
||||
acopt.display_name.as_str(),
|
||||
)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_account_create(
|
||||
acopt.aopts.account_id.as_str(),
|
||||
acopt.display_name.as_str(),
|
||||
) {
|
||||
eprintln!("Error -> {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,35 +27,54 @@ impl CommonOpt {
|
|||
let config_path: String = shellexpand::tilde("~/.config/kanidm").into_owned();
|
||||
|
||||
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")
|
||||
.and_then(|cb| {
|
||||
debug!("Attempting to use 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 {
|
||||
Some(a) => client_builder.address(a.to_string()),
|
||||
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 {
|
||||
Some(p) => client_builder
|
||||
.add_root_certificate_filepath(p)
|
||||
.expect("Failed to access CA file"),
|
||||
Some(p) => match client_builder.add_root_certificate_filepath(p) {
|
||||
Ok(cb) => cb,
|
||||
Err(e) => {
|
||||
error!("Failed to add ca certificate -- {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
},
|
||||
None => client_builder,
|
||||
};
|
||||
|
||||
let client = client_builder
|
||||
.build()
|
||||
.expect("Failed to build client instance");
|
||||
let client = match client_builder.build() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
error!("Failed to build client instance -- {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let r = if self.username == "anonymous" {
|
||||
client.auth_anonymous()
|
||||
} 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())
|
||||
};
|
||||
|
||||
|
|
|
@ -70,29 +70,38 @@ impl GroupOpt {
|
|||
match self {
|
||||
GroupOpt::List(copt) => {
|
||||
let client = copt.to_client();
|
||||
let r = client.idm_group_list().unwrap();
|
||||
for e in r {
|
||||
println!("{}", e);
|
||||
match client.idm_group_list() {
|
||||
Ok(r) => r.iter().for_each(|ent| println!("{}", ent)),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupOpt::Create(gcopt) => {
|
||||
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) => {
|
||||
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) => {
|
||||
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) => {
|
||||
let client = gcopt.copt.to_client();
|
||||
let members = client.idm_group_get_members(gcopt.name.as_str()).unwrap();
|
||||
if let Some(groups) = members {
|
||||
for m in groups {
|
||||
println!("{:?}", m);
|
||||
match client.idm_group_get_members(gcopt.name.as_str()) {
|
||||
Ok(Some(groups)) => groups.iter().for_each(|m| println!("{:?}", m)),
|
||||
Ok(None) => {}
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,31 +109,33 @@ impl GroupOpt {
|
|||
let client = gcopt.copt.to_client();
|
||||
let new_members: Vec<&str> = gcopt.members.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
client
|
||||
.idm_group_add_members(gcopt.name.as_str(), new_members)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_group_add_members(gcopt.name.as_str(), &new_members) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
GroupOpt::SetMembers(gcopt) => {
|
||||
let client = gcopt.copt.to_client();
|
||||
let new_members: Vec<&str> = gcopt.members.iter().map(|s| s.as_str()).collect();
|
||||
|
||||
client
|
||||
.idm_group_set_members(gcopt.name.as_str(), new_members)
|
||||
.unwrap();
|
||||
if let Err(e) = client.idm_group_set_members(gcopt.name.as_str(), &new_members) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
GroupOpt::Posix(gpopt) => match gpopt {
|
||||
GroupPosix::Show(gcopt) => {
|
||||
let client = gcopt.copt.to_client();
|
||||
let token = client
|
||||
.idm_group_unix_token_get(gcopt.name.as_str())
|
||||
.unwrap();
|
||||
println!("{}", token);
|
||||
match client.idm_group_unix_token_get(gcopt.name.as_str()) {
|
||||
Ok(token) => println!("{}", token),
|
||||
Err(e) => eprintln!("Error -> {:?}", e),
|
||||
}
|
||||
}
|
||||
GroupPosix::Set(gcopt) => {
|
||||
let client = gcopt.copt.to_client();
|
||||
client
|
||||
.idm_group_unix_extend(gcopt.name.as_str(), gcopt.gidnumber)
|
||||
.unwrap();
|
||||
if let Err(e) =
|
||||
client.idm_group_unix_extend(gcopt.name.as_str(), gcopt.gidnumber)
|
||||
{
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
} // end match
|
||||
|
|
|
@ -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]
|
||||
extern crate log;
|
||||
use structopt::StructOpt;
|
||||
|
@ -52,9 +62,17 @@ impl SelfOpt {
|
|||
SelfOpt::SetPassword(copt) => {
|
||||
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> {
|
||||
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 =
|
||||
rpassword::prompt_password_stderr("Retype the new password to confirm: ").unwrap();
|
||||
let password_confirm =
|
||||
match rpassword::prompt_password_stderr("Retype the new password to confirm: ") {
|
||||
Ok(p) => p,
|
||||
Err(_e) => return None,
|
||||
};
|
||||
|
||||
if password == password_confirm {
|
||||
Some(password)
|
||||
} else {
|
||||
None
|
||||
if password == password_confirm {
|
||||
return Some(password);
|
||||
} else {
|
||||
eprintln!("Passwords do not match");
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -11,14 +11,6 @@ use std::path::PathBuf;
|
|||
|
||||
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)]
|
||||
pub struct FilterOpt {
|
||||
#[structopt()]
|
||||
|
@ -30,7 +22,7 @@ pub struct FilterOpt {
|
|||
#[derive(Debug, StructOpt)]
|
||||
pub struct CreateOpt {
|
||||
#[structopt(parse(from_os_str))]
|
||||
file: Option<PathBuf>,
|
||||
file: PathBuf,
|
||||
#[structopt(flatten)]
|
||||
commonopts: CommonOpt,
|
||||
}
|
||||
|
@ -42,7 +34,7 @@ pub struct ModifyOpt {
|
|||
#[structopt()]
|
||||
filter: String,
|
||||
#[structopt(parse(from_os_str))]
|
||||
file: Option<PathBuf>,
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
|
@ -57,6 +49,14 @@ pub enum RawOpt {
|
|||
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 {
|
||||
pub fn debug(&self) -> bool {
|
||||
match self {
|
||||
|
@ -72,46 +72,75 @@ impl RawOpt {
|
|||
RawOpt::Search(sopt) => {
|
||||
let client = sopt.commonopts.to_client();
|
||||
|
||||
let filter: Filter = serde_json::from_str(sopt.filter.as_str()).unwrap();
|
||||
let rset = client.search(filter).unwrap();
|
||||
let filter: Filter = match serde_json::from_str(sopt.filter.as_str()) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
rset.iter().for_each(|e| {
|
||||
println!("{}", e);
|
||||
});
|
||||
match client.search(filter) {
|
||||
Ok(rset) => rset.iter().for_each(|e| println!("{}", e)),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
RawOpt::Create(copt) => {
|
||||
let client = copt.commonopts.to_client();
|
||||
// Read the file?
|
||||
match &copt.file {
|
||||
Some(p) => {
|
||||
let r_entries: Vec<BTreeMap<String, Vec<String>>> = read_file(p).unwrap();
|
||||
let entries = r_entries.into_iter().map(|b| Entry { attrs: b }).collect();
|
||||
client.create(entries).unwrap();
|
||||
}
|
||||
None => {
|
||||
println!("Must provide a file");
|
||||
let r_entries: Vec<BTreeMap<String, Vec<String>>> = match read_file(&copt.file) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let entries = r_entries.into_iter().map(|b| Entry { attrs: b }).collect();
|
||||
|
||||
if let Err(e) = client.create(entries) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
RawOpt::Modify(mopt) => {
|
||||
let client = mopt.commonopts.to_client();
|
||||
// Read the file?
|
||||
match &mopt.file {
|
||||
Some(p) => {
|
||||
let filter: Filter = serde_json::from_str(mopt.filter.as_str()).unwrap();
|
||||
let r_list: Vec<Modify> = read_file(p).unwrap();
|
||||
let modlist = ModifyList::new_list(r_list);
|
||||
client.modify(filter, modlist).unwrap();
|
||||
let filter: Filter = match serde_json::from_str(mopt.filter.as_str()) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
println!("Must provide a file");
|
||||
};
|
||||
|
||||
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);
|
||||
if let Err(e) = client.modify(filter, modlist) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
RawOpt::Delete(dopt) => {
|
||||
let client = dopt.commonopts.to_client();
|
||||
let filter: Filter = serde_json::from_str(dopt.filter.as_str()).unwrap();
|
||||
client.delete(filter).unwrap();
|
||||
let filter: Filter = match serde_json::from_str(dopt.filter.as_str()) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = client.delete(filter) {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,22 +27,28 @@ impl RecycleOpt {
|
|||
match self {
|
||||
RecycleOpt::List(copt) => {
|
||||
let client = copt.to_client();
|
||||
let r = client.recycle_bin_list().unwrap();
|
||||
for e in r {
|
||||
println!("{}", e);
|
||||
match client.recycle_bin_list() {
|
||||
Ok(r) => r.iter().for_each(|e| println!("{}", e)),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
RecycleOpt::Get(nopt) => {
|
||||
let client = nopt.copt.to_client();
|
||||
let e = client.recycle_bin_get(nopt.name.as_str()).unwrap();
|
||||
match e {
|
||||
Some(e) => println!("{}", e),
|
||||
None => println!("No matching entries"),
|
||||
match client.recycle_bin_get(nopt.name.as_str()) {
|
||||
Ok(Some(e)) => println!("{}", e),
|
||||
Ok(None) => println!("No matching entries"),
|
||||
Err(e) => {
|
||||
eprintln!("Error -> {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
RecycleOpt::Revive(nopt) => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +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]
|
||||
extern crate libnss;
|
||||
#[macro_use]
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
#![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;
|
||||
use crate::pam::constants::*;
|
||||
|
|
|
@ -271,8 +271,12 @@ impl CacheLayer {
|
|||
ClientError::Http(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
Some(OperationError::NotAuthenticated),
|
||||
opid,
|
||||
) => {
|
||||
error!("transport unauthenticated, moving to offline");
|
||||
error!(
|
||||
"transport unauthenticated, moving to offline - eventid {}",
|
||||
opid
|
||||
);
|
||||
// Something went wrong, mark offline.
|
||||
let time = SystemTime::now().add(Duration::from_secs(15));
|
||||
self.set_cachestate(CacheState::OfflineNextCheck(time))
|
||||
|
@ -282,14 +286,16 @@ impl CacheLayer {
|
|||
ClientError::Http(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(OperationError::NoMatchingEntries),
|
||||
opid,
|
||||
)
|
||||
| ClientError::Http(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(OperationError::InvalidAccountState(_)),
|
||||
opid,
|
||||
) => {
|
||||
// We wele able to contact the server but the entry has been removed, or
|
||||
// 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
|
||||
.map(|tok| self.delete_cache_usertoken(&tok.uuid))
|
||||
// Now an option<result<t, _>>
|
||||
|
@ -335,8 +341,12 @@ impl CacheLayer {
|
|||
ClientError::Http(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
Some(OperationError::NotAuthenticated),
|
||||
opid,
|
||||
) => {
|
||||
error!("transport unauthenticated, moving to offline");
|
||||
error!(
|
||||
"transport unauthenticated, moving to offline - eventid {}",
|
||||
opid
|
||||
);
|
||||
// Something went wrong, mark offline.
|
||||
let time = SystemTime::now().add(Duration::from_secs(15));
|
||||
self.set_cachestate(CacheState::OfflineNextCheck(time))
|
||||
|
@ -346,12 +356,14 @@ impl CacheLayer {
|
|||
ClientError::Http(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(OperationError::NoMatchingEntries),
|
||||
opid,
|
||||
)
|
||||
| ClientError::Http(
|
||||
StatusCode::BAD_REQUEST,
|
||||
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
|
||||
.map(|tok| self.delete_cache_grouptoken(&tok.uuid))
|
||||
// Now an option<result<t, _>>
|
||||
|
@ -620,8 +632,12 @@ impl CacheLayer {
|
|||
ClientError::Http(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
Some(OperationError::NotAuthenticated),
|
||||
opid,
|
||||
) => {
|
||||
error!("transport unauthenticated, moving to offline");
|
||||
error!(
|
||||
"transport unauthenticated, moving to offline - eventid {}",
|
||||
opid
|
||||
);
|
||||
// Something went wrong, mark offline.
|
||||
let time = SystemTime::now().add(Duration::from_secs(15));
|
||||
self.set_cachestate(CacheState::OfflineNextCheck(time))
|
||||
|
@ -634,12 +650,17 @@ impl CacheLayer {
|
|||
ClientError::Http(
|
||||
StatusCode::BAD_REQUEST,
|
||||
Some(OperationError::NoMatchingEntries),
|
||||
opid,
|
||||
)
|
||||
| ClientError::Http(
|
||||
StatusCode::BAD_REQUEST,
|
||||
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)
|
||||
}
|
||||
er => {
|
||||
|
|
|
@ -1,4 +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]
|
||||
extern crate log;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::convert::TryFrom;
|
|||
use std::fmt;
|
||||
|
||||
use crate::cache::Id;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
use tokio::sync::{Mutex, MutexGuard};
|
||||
|
||||
use kanidm::be::dbvalue::DbPasswordV1;
|
||||
use kanidm::credential::Password;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#![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]
|
||||
extern crate serde_derive;
|
||||
|
|
|
@ -101,7 +101,7 @@ fn test_fixture(rsclient: &KanidmClient) -> () {
|
|||
assert!(res.is_ok());
|
||||
// Not recommended in production!
|
||||
rsclient
|
||||
.idm_group_add_members("idm_admins", vec!["admin"])
|
||||
.idm_group_add_members("idm_admins", &["admin"])
|
||||
.unwrap();
|
||||
|
||||
// Create a new account
|
||||
|
@ -126,7 +126,7 @@ fn test_fixture(rsclient: &KanidmClient) -> () {
|
|||
// Setup a group
|
||||
rsclient.idm_group_create("testgroup1").unwrap();
|
||||
rsclient
|
||||
.idm_group_add_members("testgroup1", vec!["testaccount1"])
|
||||
.idm_group_add_members("testgroup1", &["testaccount1"])
|
||||
.unwrap();
|
||||
rsclient
|
||||
.idm_group_unix_extend("testgroup1", Some(20001))
|
||||
|
|
|
@ -63,12 +63,12 @@ macro_rules! try_from_entry {
|
|||
let uuid = $value.get_uuid().clone();
|
||||
|
||||
Ok(Account {
|
||||
uuid: uuid,
|
||||
name: name,
|
||||
displayname: displayname,
|
||||
groups: groups,
|
||||
primary: primary,
|
||||
spn: spn,
|
||||
uuid,
|
||||
name,
|
||||
displayname,
|
||||
groups,
|
||||
primary,
|
||||
spn,
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#![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]
|
||||
extern crate log;
|
||||
|
|
Loading…
Reference in a new issue