diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 86c92e3e6..26f1b8c30 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -70,7 +70,7 @@ tools to interact with Kanidm. - Replication for two node environments is now supported - Account policy supports password minimum length - Improve performance of webui -- Add transitional compatability with SSSD +- Add transitional compatibility with SSSD - Improve TPM interfaces in unix clients - Allow importing more weak password schemes from FreeIPA - Support Attestation of Passkeys/Webauthn - this makes us the first IDM to support this! @@ -227,7 +227,7 @@ for a future supported release. The project is shaping up very nicely, and a beta will be coming soon! -### Upgrade Note! +### Upgrade Note This version will _require_ TLS on all servers, even if behind a load balancer or TLS terminating proxy. You should be ready for this change when you upgrade to the latest version. diff --git a/server/core/src/config.rs b/server/core/src/config.rs index c302996f2..c01613f85 100644 --- a/server/core/src/config.rs +++ b/server/core/src/config.rs @@ -4,7 +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 std::fmt; +use std::fmt::{self, Display}; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; @@ -431,12 +431,12 @@ pub enum ServerRole { ReadOnlyReplica, } -impl ToString for ServerRole { - fn to_string(&self) -> String { +impl Display for ServerRole { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - ServerRole::WriteReplica => "write replica".to_string(), - ServerRole::WriteReplicaNoUI => "write replica (no ui)".to_string(), - ServerRole::ReadOnlyReplica => "read only replica".to_string(), + ServerRole::WriteReplica => f.write_str("write replica"), + ServerRole::WriteReplicaNoUI => f.write_str("write replica (no ui)"), + ServerRole::ReadOnlyReplica => f.write_str("read only replica"), } } } @@ -537,8 +537,8 @@ impl fmt::Display for Configuration { self.integration_test_config.is_some() )?; write!(f, "console output format: {:?} ", self.output_mode)?; - write!(f, "log_level: {}", self.log_level.clone().to_string())?; - write!(f, "role: {}, ", self.role.to_string())?; + write!(f, "log_level: {}", self.log_level)?; + write!(f, "role: {}, ", self.role)?; match &self.repl_config { Some(repl) => { write!(f, "replication: enabled")?; @@ -662,7 +662,7 @@ impl Configuration { } pub fn update_db_fs_type(&mut self, p: &Option) { - self.db_fs_type = p.to_owned(); + p.clone_into(&mut self.db_fs_type); } pub fn update_bind(&mut self, b: &Option) { @@ -673,12 +673,12 @@ impl Configuration { } pub fn update_ldapbind(&mut self, l: &Option) { - self.ldapaddress = l.clone(); + self.ldapaddress.clone_from(l); } pub fn update_admin_bind_path(&mut self, p: &Option) { if let Some(p) = p { - self.adminbindpath = p.clone(); + self.adminbindpath.clone_from(p); } } diff --git a/server/core/src/https/extractors/mod.rs b/server/core/src/https/extractors/mod.rs index 802dd70fa..853173256 100644 --- a/server/core/src/https/extractors/mod.rs +++ b/server/core/src/https/extractors/mod.rs @@ -148,7 +148,7 @@ impl FromRequestParts for VerifiedClientInformation { if authz_type == "basic" { (Some(authz_data.to_string()), None) } else if authz_type == "bearer" { - if let Some(jwsc) = JwsCompact::from_str(authz_data).ok() { + if let Ok(jwsc) = JwsCompact::from_str(authz_data) { (None, Some(jwsc)) } else { warn!("bearer jws invalid"); diff --git a/server/core/src/https/mod.rs b/server/core/src/https/mod.rs index 12be6c30c..2d2c575f8 100644 --- a/server/core/src/https/mod.rs +++ b/server/core/src/https/mod.rs @@ -46,6 +46,7 @@ use kanidm_lib_crypto::x509_cert::{der::Decode, x509_public_key_s256, Certificat use serde::de::DeserializeOwned; use sketching::*; +use std::fmt::Write; use tokio::{ net::{TcpListener, TcpStream}, sync::broadcast, @@ -227,8 +228,10 @@ pub async fn create_https_server( let js_checksums: String = js_directives .iter() - .map(|value| format!(" 'sha384-{}'", value)) - .collect(); + .fold(String::new(), |mut output, value| { + let _ = write!(output, " 'sha384-{}'", value); + output + }); let csp_header = format!( concat!( diff --git a/server/core/src/https/v1.rs b/server/core/src/https/v1.rs index 3d3145650..8aba83bb2 100644 --- a/server/core/src/https/v1.rs +++ b/server/core/src/https/v1.rs @@ -422,10 +422,7 @@ pub async fn json_rest_event_delete_attr( kopid: KOpId, client_auth_info: ClientAuthInfo, ) -> Result, WebError> { - let values = match values { - Some(val) => val, - None => vec![], - }; + let values = values.unwrap_or_default(); if values.is_empty() { state @@ -1993,7 +1990,6 @@ pub async fn person_id_unix_post( security(("token_jwt" = [])), tag = "v1/service_account", )] -/// #[instrument(, level = "INFO", skip(id, state, kopid))] pub async fn service_account_id_unix_post( State(state): State, diff --git a/server/core/src/https/views/errors.rs b/server/core/src/https/views/errors.rs index 251fd8344..bffe86ac8 100644 --- a/server/core/src/https/views/errors.rs +++ b/server/core/src/https/views/errors.rs @@ -38,7 +38,7 @@ impl IntoResponse for HtmxError { // } HtmxError::OperationError(_kopid, inner) => { let body = serde_json::to_string(&inner).unwrap_or(inner.to_string()); - let response = match &inner { + match &inner { OperationError::NotAuthenticated | OperationError::SessionExpired => { Redirect::to("/ui").into_response() } @@ -55,8 +55,7 @@ impl IntoResponse for HtmxError { (StatusCode::BAD_REQUEST, body).into_response() } _ => (StatusCode::INTERNAL_SERVER_ERROR, body).into_response(), - }; - response + } } } } diff --git a/server/core/src/https/views/login.rs b/server/core/src/https/views/login.rs index 57500d770..ec520ddf7 100644 --- a/server/core/src/https/views/login.rs +++ b/server/core/src/https/views/login.rs @@ -335,7 +335,7 @@ pub async fn view_login_totp_post( Form(login_totp_form): Form, ) -> Response { // trim leading and trailing white space. - let Ok(totp) = u32::from_str(&login_totp_form.totp.trim()) else { + let Ok(totp) = u32::from_str(login_totp_form.totp.trim()) else { // If not an int, we need to re-render with an error return HtmlTemplate(LoginTotpView { totp: String::default(), @@ -591,7 +591,8 @@ async fn view_login_step( HtmlTemplate(LoginBackupCodeView {}).into_response() } AuthAllowed::SecurityKey(chal) => { - let chal_json = serde_json::to_string(&chal).unwrap(); + let chal_json = serde_json::to_string(&chal) + .map_err(|_| OperationError::SerdeJsonError)?; HtmlTemplate(LoginWebauthnView { passkey: false, chal: chal_json, @@ -599,7 +600,8 @@ async fn view_login_step( .into_response() } AuthAllowed::Passkey(chal) => { - let chal_json = serde_json::to_string(&chal).unwrap(); + let chal_json = serde_json::to_string(&chal) + .map_err(|_| OperationError::SerdeJsonError)?; HtmlTemplate(LoginWebauthnView { passkey: true, chal: chal_json, diff --git a/server/core/src/https/views/oauth2.rs b/server/core/src/https/views/oauth2.rs index 4b7ad4f4d..e131b1d11 100644 --- a/server/core/src/https/views/oauth2.rs +++ b/server/core/src/https/views/oauth2.rs @@ -137,7 +137,7 @@ async fn oauth2_auth_req( // We store the auth_req into the cookie. let kref = &state.jws_signer; - let token = match Jws::into_json(&auth_req) + let token = Jws::into_json(&auth_req) .map_err(|err| { error!(?err, "Failed to serialise AuthorisationRequest"); OperationError::InvalidSessionState @@ -148,8 +148,9 @@ async fn oauth2_auth_req( OperationError::InvalidSessionState }) }) - .map(|jwss| jwss.to_string()) - { + .map(|jwss| jwss.to_string()); + + let token = match token { Ok(jws) => jws, Err(err_code) => { return HtmlTemplate(UnrecoverableErrorView { diff --git a/server/core/src/repl/mod.rs b/server/core/src/repl/mod.rs index d6ff6be18..ad2f70bef 100644 --- a/server/core/src/repl/mod.rs +++ b/server/core/src/repl/mod.rs @@ -242,12 +242,9 @@ async fn repl_run_consumer( idms: &IdmServer, consumer_conn_settings: &ConsumerConnSettings, ) -> Option { - let Some((socket_addr, mut supplier_conn)) = + let (socket_addr, mut supplier_conn) = repl_consumer_connect_supplier(domain, sock_addrs, tls_connector, consumer_conn_settings) - .await - else { - return None; - }; + .await?; // Perform incremental. let consumer_ruv_range = { diff --git a/server/lib/src/be/mod.rs b/server/lib/src/be/mod.rs index bfcb556b7..42ce02304 100644 --- a/server/lib/src/be/mod.rs +++ b/server/lib/src/be/mod.rs @@ -582,7 +582,7 @@ pub trait BackendTransaction { Some(idx_key) => { match self .get_idlayer() - .get_idl(attr, IndexType::SubString, &idx_key)? + .get_idl(attr, IndexType::SubString, idx_key)? { Some(idl) => idl, None => return Ok((IdList::AllIds, FilterPlan::SubCorrupt(attr.clone()))), diff --git a/server/lib/src/idm/authsession.rs b/server/lib/src/idm/authsession.rs index 546eb6b66..37c69fdfe 100644 --- a/server/lib/src/idm/authsession.rs +++ b/server/lib/src/idm/authsession.rs @@ -1496,7 +1496,7 @@ impl AuthSession { ( Some(AuthSessionState::Success), - Ok(AuthState::Success(token, self.issue)), + Ok(AuthState::Success(Box::new(token), self.issue)), ) } CredState::Continue(allowed) => { @@ -1858,7 +1858,7 @@ mod tests { let jws_verifier = JwsDangerReleaseWithoutVerify::default(); jws_verifier - .verify(&jwsc) + .verify(&*jwsc) .unwrap() .from_json::() .unwrap() diff --git a/server/lib/src/idm/credupdatesession.rs b/server/lib/src/idm/credupdatesession.rs index ac41a9fe7..7b7a71fd0 100644 --- a/server/lib/src/idm/credupdatesession.rs +++ b/server/lib/src/idm/credupdatesession.rs @@ -2603,7 +2603,7 @@ mod tests { let da = idms_delayed.try_recv().expect("invalid"); assert!(matches!(da, DelayedAction::AuthSessionRecord(_))); - Some(token) + Some(*token) } _ => None, } @@ -2669,7 +2669,7 @@ mod tests { // Process the auth session let da = idms_delayed.try_recv().expect("invalid"); assert!(matches!(da, DelayedAction::AuthSessionRecord(_))); - Some(token) + Some(*token) } _ => None, } @@ -2737,7 +2737,7 @@ mod tests { // Process the auth session let da = idms_delayed.try_recv().expect("invalid"); assert!(matches!(da, DelayedAction::AuthSessionRecord(_))); - Some(token) + Some(*token) } _ => None, } @@ -2812,7 +2812,7 @@ mod tests { let da = idms_delayed.try_recv().expect("invalid"); assert!(matches!(da, DelayedAction::AuthSessionRecord(_))); - Some(token) + Some(*token) } _ => None, } diff --git a/server/lib/src/idm/mod.rs b/server/lib/src/idm/mod.rs index 5c3a0bc8b..ac67d6570 100644 --- a/server/lib/src/idm/mod.rs +++ b/server/lib/src/idm/mod.rs @@ -32,7 +32,7 @@ pub enum AuthState { Choose(Vec), Continue(Vec), Denied(String), - Success(JwsCompact, AuthIssueSession), + Success(Box, AuthIssueSession), } impl fmt::Debug for AuthState { diff --git a/server/lib/src/idm/reauth.rs b/server/lib/src/idm/reauth.rs index 1407b18c0..85b65e6dc 100644 --- a/server/lib/src/idm/reauth.rs +++ b/server/lib/src/idm/reauth.rs @@ -396,7 +396,7 @@ mod tests { let r = idms.delayed_action(ct, da).await; assert!(r.is_ok()); - Some(token) + Some(*token) } _ => None, } @@ -467,7 +467,7 @@ mod tests { let r = idms.delayed_action(ct, da).await; assert!(r.is_ok()); - Some(token) + Some(*token) } _ => None, } @@ -545,7 +545,7 @@ mod tests { // NOTE: Unlike initial auth we don't need to check the auth session in the queue // since we don't re-issue it. - Some(token) + Some(*token) } _ => unreachable!(), } @@ -615,7 +615,7 @@ mod tests { // Process the auth session let da = idms_delayed.try_recv().expect("invalid"); assert!(matches!(da, DelayedAction::AuthSessionRecord(_))); - Some(token) + Some(*token) } _ => None, } diff --git a/server/lib/src/idm/server.rs b/server/lib/src/idm/server.rs index 710e795ff..ce90e6eae 100644 --- a/server/lib/src/idm/server.rs +++ b/server/lib/src/idm/server.rs @@ -2367,7 +2367,7 @@ mod tests { idms_auth.commit().expect("Must not fail"); - token + *token } #[idm_test] diff --git a/server/lib/src/utils.rs b/server/lib/src/utils.rs index 521e5e800..e1d4878cf 100644 --- a/server/lib/src/utils.rs +++ b/server/lib/src/utils.rs @@ -110,7 +110,7 @@ impl<'a> GraphemeClusterIter<'a> { char_bounds }; - let window_max = char_bounds.len().checked_sub(window).unwrap_or(0); + let window_max = char_bounds.len().saturating_sub(window); let range = 0..window_max; GraphemeClusterIter { @@ -134,7 +134,7 @@ impl<'a> Iterator for GraphemeClusterIter<'a> { } fn size_hint(&self) -> (usize, Option) { - let clusters = self.char_bounds.len().checked_sub(1).unwrap_or(0); + let clusters = self.char_bounds.len().saturating_sub(1); (clusters, Some(clusters)) } } diff --git a/server/lib/src/valueset/mod.rs b/server/lib/src/valueset/mod.rs index d53b7abff..c66a125a3 100644 --- a/server/lib/src/valueset/mod.rs +++ b/server/lib/src/valueset/mod.rs @@ -840,7 +840,7 @@ pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result ValueSetEmailAddress::from_dbvs2(primary, set), DbValueSetV2::Passkey(set) => ValueSetPasskey::from_dbvs2(set), DbValueSetV2::AttestedPasskey(set) => ValueSetAttestedPasskey::from_dbvs2(set), - DbValueSetV2::Session(set) => ValueSetSession::from_dbvs2(set), + DbValueSetV2::Session(set) => ValueSetSession::from_dbvs2(&set), DbValueSetV2::ApiToken(set) => ValueSetApiToken::from_dbvs2(set), DbValueSetV2::Oauth2Session(set) => ValueSetOauth2Session::from_dbvs2(set), DbValueSetV2::JwsKeyEs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set), diff --git a/server/lib/src/valueset/session.rs b/server/lib/src/valueset/session.rs index f04a7b2bd..6acc581d9 100644 --- a/server/lib/src/valueset/session.rs +++ b/server/lib/src/valueset/session.rs @@ -191,7 +191,7 @@ impl ValueSetSession { Ok(Box::new(ValueSetSession { map })) } - pub fn from_dbvs2(data: Vec) -> Result { + pub fn from_dbvs2(data: &[DbValueSession]) -> Result { Self::from_dbv_iter(data.iter()) } diff --git a/server/testkit/src/lib.rs b/server/testkit/src/lib.rs index d3633e70f..03e7d1240 100644 --- a/server/testkit/src/lib.rs +++ b/server/testkit/src/lib.rs @@ -72,7 +72,7 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH config.address = format!("127.0.0.1:{}", port); config.integration_test_config = Some(int_config); config.domain = "localhost".to_string(); - config.origin = addr.clone(); + config.origin.clone_from(&addr); let core_handle = match create_server_core(config, false).await { Ok(val) => val, @@ -320,7 +320,7 @@ pub async fn test_read_attrs( .await .unwrap() .is_some(), - _ => e.attrs.get(attr.as_ref()).is_some(), + _ => e.attrs.contains_key(attr.as_ref()), }; trace!("is_ok: {}, is_readable: {}", is_ok, is_readable); assert!(is_ok == is_readable) diff --git a/tools/iam_migrations/ldap/src/main.rs b/tools/iam_migrations/ldap/src/main.rs index e0ca53e27..ad6810e85 100644 --- a/tools/iam_migrations/ldap/src/main.rs +++ b/tools/iam_migrations/ldap/src/main.rs @@ -539,7 +539,7 @@ fn ldap_to_scim_entry( entry .get_ava_single(&sync_config.person_attr_gidnumber) .map(|gid| { - u32::from_str(&gid).map_err(|_| { + u32::from_str(gid).map_err(|_| { error!( "Invalid gidnumber - {} is not a u32 (person_attr_gidnumber)", sync_config.person_attr_gidnumber @@ -664,7 +664,7 @@ fn ldap_to_scim_entry( let gidnumber = entry .get_ava_single(&sync_config.group_attr_gidnumber) .map(|gid| { - u32::from_str(&gid).map_err(|_| { + u32::from_str(gid).map_err(|_| { error!( "Invalid gidnumber - {} is not a u32 (group_attr_gidnumber)", sync_config.group_attr_gidnumber diff --git a/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs b/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs index 4f783ce06..b0f546347 100644 --- a/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs +++ b/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs @@ -104,7 +104,7 @@ fn create_home_directory( .map_err(|e| format!("{:?}", e))?; let home_mount_prefix_path = home_mount_prefix_path - .unwrap_or_else(|| &home_prefix_path) + .unwrap_or(&home_prefix_path) .canonicalize() .map_err(|e| format!("{:?}", e))?;