diff --git a/Cargo.lock b/Cargo.lock index 85ad6bd25..ef1cdd85f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1010,6 +1010,7 @@ dependencies = [ "clap 3.2.6", "clap_complete", "kanidm", + "kanidm_proto", "profiles", "score", "serde", diff --git a/kanidm_proto/src/lib.rs b/kanidm_proto/src/lib.rs index 8bd4269dd..00bebbaf5 100644 --- a/kanidm_proto/src/lib.rs +++ b/kanidm_proto/src/lib.rs @@ -8,5 +8,6 @@ #![deny(clippy::needless_pass_by_value)] #![deny(clippy::trivially_copy_pass_by_ref)] +pub mod messages; pub mod oauth2; pub mod v1; diff --git a/kanidm_proto/src/messages.rs b/kanidm_proto/src/messages.rs new file mode 100644 index 000000000..abb6d31f3 --- /dev/null +++ b/kanidm_proto/src/messages.rs @@ -0,0 +1,129 @@ +// User-facing output things + +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::str::FromStr; + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum ConsoleOutputMode { + Text, + JSON, +} +impl Default for ConsoleOutputMode { + fn default() -> Self { + ConsoleOutputMode::Text + } +} + +impl FromStr for ConsoleOutputMode { + type Err = &'static str; + /// This can be safely unwrap'd because it'll always return a default + fn from_str(s: &str) -> Result { + match s { + "json" => Ok(ConsoleOutputMode::JSON), + "text" => Ok(ConsoleOutputMode::Text), + _ => { + eprintln!( + "Supplied output mode ({:?}) was invalid, defaulting to text", + s + ); + Ok(ConsoleOutputMode::Text) + } + } + } +} + +/// This will take any string, if it's 'text' or 'json' then you'll get +/// what you asked for, else you'll get a text version. +/// +/// ``` +/// use kanidm_proto::messages::ConsoleOutputMode; +/// let bork = "text"; +/// let com: ConsoleOutputMode = bork.into(); +/// matches!(ConsoleOutputMode::Text, com); +/// ``` +impl From<&str> for ConsoleOutputMode { + fn from(input: &str) -> Self { + match ConsoleOutputMode::from_str(input) { + Ok(val) => val, + Err(_) => Self::Text, + } + } +} + +/// This will take any string, if it's 'text' or 'json' then you'll get +/// what you asked for, else you'll get a text version. +/// +/// ``` +/// use kanidm_proto::messages::ConsoleOutputMode; +/// let bork = String::from("cr4bz"); +/// let com: ConsoleOutputMode = bork.into(); +/// matches!(ConsoleOutputMode::Text, com); +/// ``` +impl From for ConsoleOutputMode { + fn from(input: String) -> Self { + match ConsoleOutputMode::from_str(input.as_str()) { + Ok(val) => val, + Err(_) => Self::Text, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum MessageStatus { + Failure, + Success, +} + +impl fmt::Display for MessageStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> { + match *self { + MessageStatus::Failure => f.write_str("failure"), + MessageStatus::Success => f.write_str("success"), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct AccountChangeMessage { + #[serde(skip_serializing)] + pub output_mode: ConsoleOutputMode, + pub action: String, + pub result: String, + pub status: MessageStatus, + pub src_user: String, + pub dest_user: String, +} + +impl Default for AccountChangeMessage { + fn default() -> Self { + AccountChangeMessage { + output_mode: ConsoleOutputMode::Text, + action: String::from(""), + result: String::from(""), + status: MessageStatus::Success, + src_user: String::from(""), + dest_user: String::from(""), + } + } +} + +/// This outputs in either JSON or Text depending on the output_mode setting +impl fmt::Display for AccountChangeMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.output_mode { + ConsoleOutputMode::JSON => write!( + f, + "{}", + serde_json::to_string(self).unwrap_or(format!("{:?}", self)) // if it fails to JSON serialize, just debug-dump it + ), + ConsoleOutputMode::Text => write!( + f, + "{} - {} for user {}: {}", + self.status, self.action, self.dest_user, self.result, + ), + } + } +} diff --git a/kanidm_tools/src/cli/account.rs b/kanidm_tools/src/cli/account.rs index f3e6330a2..5c9c185b2 100644 --- a/kanidm_tools/src/cli/account.rs +++ b/kanidm_tools/src/cli/account.rs @@ -3,22 +3,17 @@ use crate::{ AccountCredential, AccountOpt, AccountPerson, AccountPosix, AccountRadius, AccountSsh, AccountValidity, }; -use qrcode::{render::unicode, QrCode}; -// use std::io; -use kanidm_client::KanidmClient; -use time::OffsetDateTime; - use dialoguer::{theme::ColorfulTheme, Select}; use dialoguer::{Confirm, Input, Password}; - -// use webauthn_authenticator_rs::{u2fhid::U2FHid, WebauthnAuthenticator}; - -// use kanidm_client::ClientError; use kanidm_client::ClientError::Http as ClientErrorHttp; -use kanidm_proto::v1::OperationError::PasswordQuality; +use kanidm_client::KanidmClient; +use kanidm_proto::messages::{AccountChangeMessage, MessageStatus}; +use kanidm_proto::v1::OperationError::{InvalidAttribute, PasswordQuality}; use kanidm_proto::v1::{CUIntentToken, CURegState, CUSessionToken, CUStatus}; -use std::fmt; +use qrcode::{render::unicode, QrCode}; +use std::fmt::{self, Debug}; use std::str::FromStr; +use time::OffsetDateTime; use url::Url; impl AccountOpt { @@ -149,10 +144,23 @@ impl AccountOpt { } } }, // end AccountOpt::Posix + AccountOpt::Person { commands } => match commands { AccountPerson::Extend(aopt) => { let client = aopt.copt.to_client().await; - if let Err(e) = client + let mut result_output = kanidm_proto::messages::AccountChangeMessage { + output_mode: aopt.copt.output_mode.to_owned().into(), + action: String::from("account_person_extend"), + result: String::from("This is a filler message"), + src_user: aopt + .copt + .username + .to_owned() + .unwrap_or(format!("{:?}", client.whoami().await)), + dest_user: aopt.aopts.account_id.to_string(), + status: kanidm_proto::messages::MessageStatus::Failure, + }; + match client .idm_account_person_extend( aopt.aopts.account_id.as_str(), aopt.mail.as_deref(), @@ -160,12 +168,71 @@ impl AccountOpt { ) .await { - error!("Error -> {:?}", e); + // TODO: JSON output for account person extend. + Ok(_) => { + result_output.result = format!( + "Successfully extended the user {}.", + aopt.aopts.account_id + ); + match &aopt.legalname { + Some(legalname) => { + result_output.result += + format!(" Set legalname to {}.", legalname).as_str() + } + _ => debug!("Didn't change legalname field."), + }; + match &aopt.mail { + Some(mail) => { + result_output.result += + format!(" Set mail to {:?}.", mail.join(", ")).as_str() + } + _ => debug!("Didn't change mail field."), + }; + println!("{}", result_output); + } + // TODO: consider a macro to unpack the KanidmClient result object + Err(e) => { + match e { + ClientErrorHttp(_, result, _) => { + if let Some(ia_error) = result { + match ia_error { + InvalidAttribute(msg) => { + result_output.result = + format!("Failed to set value: {}", msg) + } + _ => { + result_output.result = + format!("Operation Error - {:?}", ia_error) + } + }; + } else { + result_output.result = + format!("ClientError - {:?}", result); + } + } + _ => result_output.result = format!("Error -> {:?}", e), + }; + eprintln!("{:?}", result_output); + } } } + + // TODO: there should probably be an 'unset' variant of this AccountPerson::Set(aopt) => { let client = aopt.copt.to_client().await; - if let Err(e) = client + let mut result_output = AccountChangeMessage { + output_mode: aopt.copt.output_mode.to_owned().into(), + action: String::from("account_person set"), + result: String::from(""), + src_user: aopt + .copt + .username + .to_owned() + .unwrap_or(format!("{:?}", client.whoami().await)), + dest_user: aopt.aopts.account_id.to_string(), + status: MessageStatus::Failure, + }; + match client .idm_account_person_set( aopt.aopts.account_id.as_str(), aopt.mail.as_deref(), @@ -173,7 +240,16 @@ impl AccountOpt { ) .await { - error!("Error -> {:?}", e); + Ok(_) => { + result_output.status = kanidm_proto::messages::MessageStatus::Success; + result_output.result = "set 'person' status on user".to_string(); + println!("{}", result_output) + } + // TODO: ponder macro'ing handling ClientError + Err(e) => { + result_output.result = format!("Error -> {:?}", e); + eprintln!("{}", result_output) + } } } }, // end AccountOpt::Person @@ -460,13 +536,13 @@ impl AccountCredential { .build(); println!("{}", image); - println!(""); + println!(); println!("link: {}", url.as_str()); println!( "command: kanidm account credential reset {}", cuintent_token.token ); - println!(""); + println!(); } Err(e) => { error!("Error starting credential reset -> {:?}", e); @@ -826,22 +902,20 @@ async fn credential_update_exec( if password_a != password_b { eprintln!("Passwords do not match"); - } else { - if let Err(e) = client - .idm_account_credential_update_set_password(&session_token, &password_a) - .await - { - match e { - ClientErrorHttp(_, Some(PasswordQuality(feedback)), _) => { - for fb_item in feedback.iter() { - eprintln!("{:?}", fb_item) - } + } else if let Err(e) = client + .idm_account_credential_update_set_password(&session_token, &password_a) + .await + { + match e { + ClientErrorHttp(_, Some(PasswordQuality(feedback)), _) => { + for fb_item in feedback.iter() { + eprintln!("{:?}", fb_item) } - _ => eprintln!("An error occured -> {:?}", e), } - } else { - println!("success"); + _ => eprintln!("An error occured -> {:?}", e), } + } else { + println!("Successfully reset password."); } } CUAction::Totp => totp_enroll_prompt(&session_token, &client).await, diff --git a/kanidm_tools/src/cli/common.rs b/kanidm_tools/src/cli/common.rs index 04495b5a6..84c844c68 100644 --- a/kanidm_tools/src/cli/common.rs +++ b/kanidm_tools/src/cli/common.rs @@ -155,7 +155,7 @@ pub fn prompt_for_username_get_values() -> Result<(String, String), String> { options.push(String::from(option.0)); } let user_select = Select::with_theme(&ColorfulTheme::default()) - .with_prompt("Authentication tokens exist. Please select one") + .with_prompt("Multiple authentication tokens exist. Please select one") .default(0) .items(&options) .interact(); diff --git a/kanidm_tools/src/cli/main.rs b/kanidm_tools/src/cli/main.rs index db643ac54..399711a76 100644 --- a/kanidm_tools/src/cli/main.rs +++ b/kanidm_tools/src/cli/main.rs @@ -12,9 +12,7 @@ use clap::Parser; use kanidm_cli::KanidmClientParser; - -use tracing_subscriber::prelude::*; -use tracing_subscriber::{fmt, EnvFilter}; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; #[tokio::main(flavor = "current_thread")] async fn main() { diff --git a/kanidm_tools/src/opt/kanidm.rs b/kanidm_tools/src/opt/kanidm.rs index 088ae92e8..47a88efd7 100644 --- a/kanidm_tools/src/opt/kanidm.rs +++ b/kanidm_tools/src/opt/kanidm.rs @@ -15,14 +15,20 @@ pub struct DebugOpt { #[derive(Debug, Args)] pub struct CommonOpt { + // TODO: this should probably be a flag, or renamed to log level if it's a level #[clap(short, long, env = "KANIDM_DEBUG")] pub debug: bool, #[clap(short = 'H', long = "url", env = "KANIDM_URL")] pub addr: Option, + /// User which will initiate requests #[clap(short = 'D', long = "name", env = "KANIDM_NAME")] pub username: Option, + /// Path to a CA certificate file #[clap(parse(from_os_str), short = 'C', long = "ca", env = "KANIDM_CA_PATH")] pub ca_path: Option, + /// Log format (still in very early development) + #[clap(short, long = "output", env = "KANIDM_OUTPUT", default_value="text")] + pub output_mode: String, } #[derive(Debug, Args)] @@ -183,9 +189,9 @@ pub enum AccountRadius { pub struct AccountPosixOpt { #[clap(flatten)] aopts: AccountCommonOpt, - #[clap(long = "gidnumber")] + #[clap(long)] gidnumber: Option, - #[clap(long = "shell")] + #[clap(long)] shell: Option, #[clap(flatten)] copt: CommonOpt, @@ -205,9 +211,9 @@ pub enum AccountPosix { pub struct AccountPersonOpt { #[clap(flatten)] aopts: AccountCommonOpt, - #[clap(long = "mail")] + #[clap(long, short, help="Set the mail address, can be set multiple times for multiple addresses.")] mail: Option>, - #[clap(long = "legalname")] + #[clap(long, short, help="Set the legal name for the person.")] legalname: Option, #[clap(flatten)] copt: CommonOpt, diff --git a/kanidmd/daemon/Cargo.toml b/kanidmd/daemon/Cargo.toml index 70751a5f1..16e5dfb2a 100644 --- a/kanidmd/daemon/Cargo.toml +++ b/kanidmd/daemon/Cargo.toml @@ -18,6 +18,7 @@ path = "src/main.rs" [dependencies] kanidm = { path = "../idm" } +kanidm_proto = { path = "../../kanidm_proto" } score = { path = "../score" } clap = { version = "^3.2", features = ["derive", "env"] } users = "^0.11.0" diff --git a/kanidmd/daemon/src/main.rs b/kanidmd/daemon/src/main.rs index 7c8baa8fb..167c1d42c 100644 --- a/kanidmd/daemon/src/main.rs +++ b/kanidmd/daemon/src/main.rs @@ -28,7 +28,7 @@ use std::path::PathBuf; use std::str::FromStr; use kanidm::audit::LogLevel; -use kanidm::config::{Configuration, ConsoleOutputMode, OnlineBackup, ServerRole}; +use kanidm::config::{Configuration, OnlineBackup, ServerRole}; use kanidm::tracing_tree; use kanidm::utils::file_permissions_readonly; use score::{ @@ -221,9 +221,7 @@ async fn main() { config.update_domain(&sconfig.domain.as_str()); config.update_db_arc_size(sconfig.db_arc_size); config.update_role(sconfig.role); - config.update_output_mode( - ConsoleOutputMode::from_str(opt.commands.commonopt().output_mode.as_str()).unwrap(), - ); + config.update_output_mode(opt.commands.commonopt().output_mode.to_owned().into()); // Apply any cli overrides, normally debug level. if let Some(dll) = opt.commands.commonopt().debug.as_ref() { diff --git a/kanidmd/daemon/src/opt.rs b/kanidmd/daemon/src/opt.rs index ed53d9eba..46bf28949 100644 --- a/kanidmd/daemon/src/opt.rs +++ b/kanidmd/daemon/src/opt.rs @@ -6,7 +6,6 @@ struct CommonOpt { #[clap(parse(from_os_str), short, long = "config", env = "KANIDM_CONFIG")] /// Path to the server's configuration file. If it does not exist, it will be created. config_path: PathBuf, - //TODO: remove this once we work out the format /// Log format (still in very early development) #[clap(short, long = "output", env = "KANIDM_OUTPUT", default_value="text")] output_mode: String, diff --git a/kanidmd/idm/Cargo.toml b/kanidmd/idm/Cargo.toml index bb202d6cc..8749f075c 100644 --- a/kanidmd/idm/Cargo.toml +++ b/kanidmd/idm/Cargo.toml @@ -15,74 +15,54 @@ name = "kanidm" path = "src/lib.rs" [dependencies] -kanidm_proto = { path = "../../kanidm_proto" } -tracing = { version = "^0.1.35", features = ["attributes"] } -tracing-subscriber = { version = "^0.3.11", features = ["env-filter"] } -tracing-serde = "^0.1.3" - -dyn-clone = "^1.0.6" - -url = { version = "^2.2.2", features = ["serde"] } -tide = "^0.16.0" -async-trait = "^0.1.53" -fernet = { version = "^0.1.4", features = ["fernet_danger_timestamps"] } -compact_jwt = "^0.2.1" - async-std = { version = "^1.12.0", features = ["tokio1"] } - -rand = "^0.8.5" -toml = "^0.5.9" - +async-trait = "^0.1.53" +base64 = "^0.13.0" chrono = "^0.4.19" -saffron = "^0.1.0" -regex = "^1.5.6" -lazy_static = "^1.4.0" - +compact_jwt = "^0.2.1" +compiled-uuid = "0.1.2" +concread = "^0.3.4" +dyn-clone = "^1.0.6" +fernet = { version = "^0.1.4", features = ["fernet_danger_timestamps"] } +filetime = "^0.2.16" futures = "^0.3.21" futures-util = "^0.3.21" -tokio = { version = "^1.19.1", features = ["net", "sync", "time"] } -tokio-util = { version = "^0.7.3", features = ["codec"] } +hashbrown = { version = "0.12.0", features = ["serde", "inline-more", "ahash"] } +idlset = { version = "^0.2.3" } +kanidm_proto = { path = "../../kanidm_proto" } +lazy_static = "^1.4.0" +ldap3_proto = "^0.2.3" +libc = "^0.2.126" +libsqlite3-sys = "0.24.2" +num_enum = "^0.5.7" openssl = "^0.10.38" - -uuid = { version = "^1.1.2", features = ["serde", "v4" ] } -compiled-uuid = "0.1.2" +r2d2 = "^0.8.9" +r2d2_sqlite = "^0.20.0" +rand = "^0.8.5" +regex = "^1.5.6" +rusqlite = "^0.27.0" +saffron = "^0.1.0" serde = { version = "^1.0.137", features = ["derive"] } serde_cbor = "^0.11.2" serde_json = "^1.0.81" - -libsqlite3-sys = "0.24.2" -rusqlite = "^0.27.0" -r2d2 = "^0.8.10" -r2d2_sqlite = "^0.20.0" - -time = { version = "=0.2.27", features = ["serde", "std"] } - -hashbrown = { version = "0.12.0", features = ["serde", "inline-more", "ahash"] } -concread = "^0.3.4" -smolset = "^1.3.1" - -sshkeys = "^0.3.1" - -zxcvbn = "^2.2.1" -base64 = "^0.13.0" - -idlset = { version = "^0.2.3" } - -ldap3_proto = "^0.2.3" - -webauthn-rs = "^0.3.2" - -libc = "^0.2.126" -users = "^0.11.0" - smartstring = { version = "^1.0.1", features = ["serde"] } - -validator = { version = "^0.15.0", features = ["phone"] } - +smolset = "^1.3.1" +sshkeys = "^0.3.1" +tide = "^0.16.0" +time = { version = "=0.2.27", features = ["serde", "std"] } +tokio = { version = "^1.19.1", features = ["net", "sync", "time"] } +tokio-util = { version = "^0.7.3", features = ["codec"] } +toml = "^0.5.9" touch = "^0.0.1" -filetime = "^0.2.16" - -num_enum = "^0.5.7" +tracing = { version = "^0.1.35", features = ["attributes"] } +tracing-serde = "^0.1.3" +tracing-subscriber = { version = "^0.3.11", features = ["env-filter"] } +url = { version = "^2.2.2", features = ["serde"] } +users = "^0.11.0" +uuid = { version = "^1.1.2", features = ["serde", "v4" ] } +validator = { version = "^0.15.0", features = ["phone"] } +webauthn-rs = "^0.3.2" +zxcvbn = "^2.2.1" [features] # default = [ "libsqlite3-sys/bundled", "openssl/vendored" ] diff --git a/kanidmd/idm/src/config.rs b/kanidmd/idm/src/config.rs index b97e50e57..30517721e 100644 --- a/kanidmd/idm/src/config.rs +++ b/kanidmd/idm/src/config.rs @@ -4,6 +4,7 @@ //! These components should be "per server". Any "per domain" config should be in the system //! or domain entries that are able to be replicated. +use kanidm_proto::messages::ConsoleOutputMode; use rand::prelude::*; use serde::{Deserialize, Serialize}; use std::fmt; @@ -74,31 +75,6 @@ impl FromStr for ServerRole { } } -// TODO: this should probably be in the kanidm crate -#[derive(Debug, Serialize, Deserialize, Clone, Copy)] -#[serde(rename_all = "lowercase")] -pub enum ConsoleOutputMode { - Text, - JSON, -} -impl Default for ConsoleOutputMode { - fn default() -> Self { - ConsoleOutputMode::Text - } -} - -impl FromStr for ConsoleOutputMode { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s { - "json" => Ok(ConsoleOutputMode::JSON), - "text" => Ok(ConsoleOutputMode::Text), - _ => Err("Must be one of json, text"), - } - } -} - #[derive(Serialize, Deserialize, Debug, Default)] pub struct Configuration { pub address: String, diff --git a/kanidmd/idm/src/idm/server.rs b/kanidmd/idm/src/idm/server.rs index 8cc107ee6..602601201 100644 --- a/kanidmd/idm/src/idm/server.rs +++ b/kanidmd/idm/src/idm/server.rs @@ -203,7 +203,7 @@ impl IdmServer { let valid = url.domain().map(|effective_domain| { // We need to prepend the '.' here to ensure that myexample.com != example.com, // rather than just ends with. - effective_domain.ends_with(&format!(".{}", rp_id)) + effective_domain.ends_with(&format!(".{}", rp_id)) || effective_domain == rp_id }).unwrap_or(false); @@ -370,7 +370,7 @@ impl IdmServer { } impl IdmServerDelayed { - pub(crate) fn is_empty_or_panic(&mut self) { + pub(crate) fn check_is_empty_or_panic(&mut self) { let waker = futures_task::noop_waker(); let mut cx = Context::from_waker(&waker); match self.async_rx.poll_recv(&mut cx) { @@ -3107,7 +3107,7 @@ mod tests { run_idm_test!( |qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| { // Assert the delayed action queue is empty - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); // Setup the admin w_ an imported password. { let qs_write = qs.write(duration_from_epoch_now()); @@ -3126,7 +3126,7 @@ mod tests { qs_write.commit().expect("failed to commit"); } // Still empty - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); // Do an auth, this will trigger the action to send. check_admin_password(idms, "password"); // process it. @@ -3136,7 +3136,7 @@ mod tests { // Check the admin pw still matches check_admin_password(idms, "password"); // No delayed action was queued. - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); } ) } @@ -3146,7 +3146,7 @@ mod tests { run_idm_test!( |_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| { // Assert the delayed action queue is empty - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); // Setup the admin with an imported unix pw. let idms_prox_write = idms.proxy_write(duration_from_epoch_now()); @@ -3170,7 +3170,7 @@ mod tests { }; assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok()); assert!(idms_prox_write.commit().is_ok()); - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); // Get the auth ready. let uuae = UnixUserAuthEvent::new_internal(&UUID_ADMIN, "password"); let mut idms_auth = idms.auth(); @@ -3197,7 +3197,7 @@ mod tests { }; idms_auth.commit().expect("Must not fail"); // No delayed action was queued. - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); } ) } @@ -3749,7 +3749,7 @@ mod tests { // Assert we can increment the counter if needed. // Assert the delayed action queue is empty - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); // Generate a fake counter increment let da = DelayedAction::WebauthnCounterIncrement(WebauthnCounterIncrement { @@ -3841,7 +3841,7 @@ mod tests { assert!(idms_prox_write.commit().is_ok()); // Assert the delayed action queue is empty - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); // Generate a fake action to remove one backup code let da = DelayedAction::BackupCodeRemoval(BackupCodeRemoval { diff --git a/kanidmd/idm/src/macros.rs b/kanidmd/idm/src/macros.rs index c49438961..37549567f 100644 --- a/kanidmd/idm/src/macros.rs +++ b/kanidmd/idm/src/macros.rs @@ -191,7 +191,7 @@ macro_rules! run_idm_test_inner { // Any needed teardown? // Make sure there are no errors. assert!(test_server.verify().len() == 0); - idms_delayed.is_empty_or_panic(); + idms_delayed.check_is_empty_or_panic(); }}; } diff --git a/kanidmd/idm/src/server.rs b/kanidmd/idm/src/server.rs index 1ddf2a75f..5c692f138 100644 --- a/kanidmd/idm/src/server.rs +++ b/kanidmd/idm/src/server.rs @@ -1579,7 +1579,7 @@ impl<'a> QueryServerWriteTransaction<'a> { // Validate input. // Is the modlist non zero? - if me.modlist.len() == 0 { + if me.modlist.is_empty() { request_error!("modify: empty modify request"); return Err(OperationError::EmptyRequest); } diff --git a/kanidmd/idm/src/tracing_tree/subscriber.rs b/kanidmd/idm/src/tracing_tree/subscriber.rs index a674ba2e4..fe47cfe03 100644 --- a/kanidmd/idm/src/tracing_tree/subscriber.rs +++ b/kanidmd/idm/src/tracing_tree/subscriber.rs @@ -336,7 +336,8 @@ impl TreeEvent { fn record_u64(&mut self, field: &Field, value: u64) { if field.name() == "event_tag_id" { let tag = EventTag::try_from(value).unwrap_or_else(|_| { - panic!("Invalid `event_tag_id`: {}, this is a bug", value) + error!("Invalid `event_tag_id`: {}, this is a bug", value); + std::process::exit(1) }); self.tag = Some(tag); } else { diff --git a/kanidmd/score/Cargo.toml b/kanidmd/score/Cargo.toml index 56e36fc2d..0deb35b9c 100644 --- a/kanidmd/score/Cargo.toml +++ b/kanidmd/score/Cargo.toml @@ -13,29 +13,25 @@ repository = "https://github.com/kanidm/kanidm/" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -kanidm = { path = "../idm" } -kanidm_proto = { path = "../../kanidm_proto" } -libc = "^0.2.126" - -uuid = { version = "^1.1.2", features = ["serde", "v4" ] } - -tide = "^0.16.0" -tide-openssl = "^0.1.1" - +async-std = { version = "^1.12.0", features = ["tokio1"] } +async-trait = "^0.1.53" +compact_jwt = "^0.2.1" futures-util = "^0.3.21" -tokio = { version = "^1.19.1", features = ["net", "sync", "io-util", "macros"] } -tokio-util = { version = "^0.7.3", features = ["codec"] } -tokio-openssl = "^0.6.3" -openssl = "^0.10.38" +kanidm = { path = "../idm" } +kanidm_client = { path = "../../kanidm_client" } +kanidm_proto = { path = "../../kanidm_proto" } ldap3_proto = "^0.2.3" - -tracing = { version = "^0.1.35", features = ["attributes"] } +libc = "^0.2.126" +openssl = "^0.10.38" serde = { version = "^1.0.137", features = ["derive"] } serde_json = "^1.0.81" - -async-trait = "^0.1.53" -async-std = { version = "^1.12.0", features = ["tokio1"] } -compact_jwt = "^0.2.1" +tide = "^0.16.0" +tide-openssl = "^0.1.1" +tokio = { version = "^1.19.1", features = ["net", "sync", "io-util", "macros"] } +tokio-openssl = "^0.6.3" +tokio-util = { version = "^0.7.3", features = ["codec"] } +tracing = { version = "^0.1.35", features = ["attributes"] } +uuid = { version = "^1.1.2", features = ["serde", "v4" ] } [build-dependencies] profiles = { path = "../../profiles" } @@ -52,6 +48,5 @@ webauthn-authenticator-rs = "^0.3.2" oauth2_ext = { package = "oauth2", version = "^4.1.0", default-features = false } base64 = "^0.13.0" -kanidm_client = { path = "../../kanidm_client" } url = { version = "^2.2.2", features = ["serde"] } reqwest = { version = "0.11.11", features=["cookies", "json", "native-tls"] } diff --git a/kanidmd/score/src/lib.rs b/kanidmd/score/src/lib.rs index ee59b1def..61944340f 100644 --- a/kanidmd/score/src/lib.rs +++ b/kanidmd/score/src/lib.rs @@ -37,7 +37,7 @@ use libc::umask; use kanidm::actors::v1_read::QueryServerReadV1; use kanidm::actors::v1_write::QueryServerWriteV1; use kanidm::be::{Backend, BackendConfig, BackendTransaction, FsType}; -use kanidm::config::{Configuration, ConsoleOutputMode}; +use kanidm::config::Configuration; use kanidm::crypto::setup_tls; use kanidm::idm::server::{IdmServer, IdmServerDelayed}; use kanidm::interval::IntervalActor; @@ -45,11 +45,9 @@ use kanidm::ldap::LdapServer; use kanidm::schema::Schema; use kanidm::status::StatusActor; use kanidm::utils::{duration_from_epoch_now, touch_file_or_quit}; +use kanidm_proto::messages::{AccountChangeMessage, MessageStatus}; use kanidm_proto::v1::OperationError; -use serde::{Deserialize, Serialize}; -use serde_json; -use std::fmt; use std::sync::Arc; // === internal setup helpers @@ -483,42 +481,6 @@ pub fn verify_server_core(config: &Configuration) { // Now add IDM server verifications? } -// TODO: should this go somewhere else -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -enum MessageStatus { - Failure, - Success, -} - -impl fmt::Display for MessageStatus { - fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> { - match *self { - MessageStatus::Failure => f.write_str("failure"), - MessageStatus::Success => f.write_str("status"), - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -struct AccountChangeMessage { - action: String, - result: String, - status: MessageStatus, - src_user: String, - dest_user: String, -} - -impl fmt::Display for AccountChangeMessage { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - serde_json::to_string(self).unwrap_or(format!("{:?}", self)) - ) - } -} - pub fn recover_account_core(config: &Configuration, name: &str) { let schema = match Schema::new() { Ok(s) => s, @@ -562,26 +524,17 @@ pub fn recover_account_core(config: &Configuration, name: &str) { std::process::exit(1); } }; - match config.output_mode { - ConsoleOutputMode::JSON => { - println!( - "{}", - AccountChangeMessage { - status: MessageStatus::Success, - src_user: String::from("command-line invocation"), - dest_user: name.to_string(), - result: new_pw, - action: String::from("recover_account"), - } - ); + println!( + "{}", + AccountChangeMessage { + output_mode: config.output_mode, + status: MessageStatus::Success, + src_user: String::from("command-line invocation"), + dest_user: name.to_string(), + result: new_pw, + action: String::from("recover_account"), } - ConsoleOutputMode::Text => { - println!( - "Successfully recovered account '{}' - password reset to -> {}", - name, new_pw - ); - } - } + ); } pub async fn create_server_core(config: Configuration, config_test: bool) -> Result<(), ()> { diff --git a/kanidmd_web_ui/src/credential/pwmodal.rs b/kanidmd_web_ui/src/credential/pwmodal.rs index 7ce038952..34d141712 100644 --- a/kanidmd_web_ui/src/credential/pwmodal.rs +++ b/kanidmd_web_ui/src/credential/pwmodal.rs @@ -113,7 +113,7 @@ impl Component for PwModalApp { type Message = Msg; type Properties = ModalProps; - fn create(ctx: &Context) -> Self { + fn create(_ctx: &Context) -> Self { console::log!("pw modal create"); PwModalApp { diff --git a/kanidmd_web_ui/src/credential/reset.rs b/kanidmd_web_ui/src/credential/reset.rs index 6ab888cce..fcb54bcfb 100644 --- a/kanidmd_web_ui/src/credential/reset.rs +++ b/kanidmd_web_ui/src/credential/reset.rs @@ -339,10 +339,11 @@ impl CredentialResetApp { uuid: _, claims: _, type_: + // TODO: review this and find out why we aren't using these variables CredentialDetailType::PasswordMfa( - totp_set, - security_key_labels, - backup_codes_remaining, + _totp_set, + _security_key_labels, + _backup_codes_remaining, ), }) => { html! { diff --git a/kanidmd_web_ui/src/oauth2.rs b/kanidmd_web_ui/src/oauth2.rs index aae6bc300..9eb0dea67 100644 --- a/kanidmd_web_ui/src/oauth2.rs +++ b/kanidmd_web_ui/src/oauth2.rs @@ -28,6 +28,7 @@ enum State { Consent { token: String, client_name: String, + #[allow(dead_code)] scopes: Vec, pii_scopes: Vec, consent_token: String, diff --git a/kanidmd_web_ui/src/utils.rs b/kanidmd_web_ui/src/utils.rs index 8efd0761f..72541793c 100644 --- a/kanidmd_web_ui/src/utils.rs +++ b/kanidmd_web_ui/src/utils.rs @@ -2,7 +2,7 @@ use gloo::console; use wasm_bindgen::prelude::*; use wasm_bindgen::{JsCast, UnwrapThrowExt}; pub use web_sys::InputEvent; -use web_sys::{Document, Event, HtmlButtonElement, HtmlElement, HtmlInputElement, Window}; +use web_sys::{Document, Event, /*HtmlButtonElement,*/ HtmlElement, HtmlInputElement, Window}; pub fn window() -> Window { web_sys::window().expect_throw("Unable to retrieve window") @@ -37,23 +37,23 @@ pub fn get_value_from_input_event(e: InputEvent) -> String { target.value() } -pub fn get_element_by_id(id: &str) -> Option { - document() - .get_element_by_id(id) - .and_then(|element| element.dyn_into::().ok()) -} +// pub fn get_element_by_id(id: &str) -> Option { +// document() +// .get_element_by_id(id) +// .and_then(|element| element.dyn_into::().ok()) +// } -pub fn get_buttonelement_by_id(id: &str) -> Option { - document() - .get_element_by_id(id) - .and_then(|element| element.dyn_into::().ok()) -} +// pub fn get_buttonelement_by_id(id: &str) -> Option { +// document() +// .get_element_by_id(id) +// .and_then(|element| element.dyn_into::().ok()) +// } -pub fn get_inputelement_by_id(id: &str) -> Option { - document() - .get_element_by_id(id) - .and_then(|element| element.dyn_into::().ok()) -} +// pub fn get_inputelement_by_id(id: &str) -> Option { +// document() +// .get_element_by_id(id) +// .and_then(|element| element.dyn_into::().ok()) +// } pub fn get_value_from_element_id(id: &str) -> Option { document() diff --git a/kanidmd_web_ui/src/views/security.rs b/kanidmd_web_ui/src/views/security.rs index e7a1e0a3b..0efc97678 100644 --- a/kanidmd_web_ui/src/views/security.rs +++ b/kanidmd_web_ui/src/views/security.rs @@ -147,7 +147,8 @@ impl Component for SecurityApp {