From b6813a11d341caaa288c2b76a354074ef95cac49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 01:31:20 +0000 Subject: [PATCH 01/10] Bump openssl from 0.10.71 to 0.10.72 in the cargo group (#3544) Bumps the cargo group with 1 update: [openssl](https://github.com/sfackler/rust-openssl). Updates `openssl` from 0.10.71 to 0.10.72 - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.71...openssl-v0.10.72) --- updated-dependencies: - dependency-name: openssl dependency-version: 0.10.72 dependency-type: direct:production dependency-group: cargo ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe306e47e..473f65a64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3955,9 +3955,9 @@ checksum = "c2806eaa3524762875e21c3dcd057bc4b7bfa01ce4da8d46be1cd43649e1cc6b" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ "bitflags 2.9.0", "cfg-if", @@ -3987,9 +3987,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 400184969..8777db081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -210,7 +210,7 @@ notify-debouncer-full = { version = "0.5" } num_enum = "^0.5.11" oauth2_ext = { version = "^4.4.2", package = "oauth2", default-features = false } openssl-sys = "^0.9" -openssl = "^0.10.70" +openssl = "^0.10.72" opentelemetry = { version = "0.27.0" } opentelemetry_api = { version = "0.27.0", features = ["logs", "metrics"] } From 94b6287e2782235375b6a9a3380b2d8f141b75a9 Mon Sep 17 00:00:00 2001 From: Firstyear <william@blackhats.net.au> Date: Tue, 8 Apr 2025 14:21:26 +1000 Subject: [PATCH 02/10] Unify unix config parser (#3533) * Unify unix config parser * Document the various structs * Compiler Update --- Cargo.lock | 2 + libs/crypto/src/crypt_md5.rs | 2 +- server/lib/src/repl/proto.rs | 12 +- tools/orca/src/models/read.rs | 2 +- unix_integration/common/Cargo.toml | 7 + unix_integration/common/src/lib.rs | 3 + .../{resolver => common}/src/selinux_util.rs | 0 unix_integration/common/src/unix_config.rs | 556 +++++++++++++++++- unix_integration/nss_kanidm/src/core.rs | 4 +- unix_integration/pam_kanidm/src/core.rs | 4 +- unix_integration/pam_kanidm/src/pam/mod.rs | 6 +- unix_integration/resolver/Cargo.toml | 4 +- .../resolver/src/bin/kanidm-unix.rs | 5 +- .../src/bin/kanidm_ssh_authorizedkeys.rs | 5 +- .../resolver/src/bin/kanidm_unixd.rs | 2 +- .../resolver/src/bin/kanidm_unixd_tasks.rs | 4 +- .../resolver/src/idprovider/kanidm.rs | 28 +- unix_integration/resolver/src/lib.rs | 4 - unix_integration/resolver/src/resolver.rs | 28 +- unix_integration/resolver/src/unix_config.rs | 538 ----------------- .../resolver/tests/cache_layer_test.rs | 2 +- 21 files changed, 605 insertions(+), 613 deletions(-) rename unix_integration/{resolver => common}/src/selinux_util.rs (100%) delete mode 100644 unix_integration/resolver/src/unix_config.rs diff --git a/Cargo.lock b/Cargo.lock index 473f65a64..0ba0a6ab6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3064,6 +3064,8 @@ dependencies = [ "futures", "kanidm_build_profiles", "kanidm_proto", + "kanidm_utils_users", + "selinux", "serde", "serde_json", "serde_with", diff --git a/libs/crypto/src/crypt_md5.rs b/libs/crypto/src/crypt_md5.rs index 9a5120048..2a81438a3 100644 --- a/libs/crypto/src/crypt_md5.rs +++ b/libs/crypto/src/crypt_md5.rs @@ -8,7 +8,7 @@ const MD5_TRANSPOSE: &[u8] = b"\x0c\x06\x00\x0d\x07\x01\x0e\x08\x02\x0f\x09\x03\ const CRYPT_HASH64: &[u8] = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; pub fn md5_sha2_hash64_encode(bs: &[u8]) -> String { - let ngroups = (bs.len() + 2) / 3; + let ngroups = bs.len().div_ceil(3); let mut out = String::with_capacity(ngroups * 4); for g in 0..ngroups { let mut g_idx = g * 3; diff --git a/server/lib/src/repl/proto.rs b/server/lib/src/repl/proto.rs index 5f8ca839e..7403ec9ae 100644 --- a/server/lib/src/repl/proto.rs +++ b/server/lib/src/repl/proto.rs @@ -165,10 +165,10 @@ impl ReplEntryV1 { // but for now, if it's an empty set in any capacity, we map // to None and just send the Cid since they have the same result // on how the entry/attr state looks at each end. - if maybe.len() > 0 { - Some(maybe.to_db_valueset_v2()) - } else { + if maybe.is_empty() { None + } else { + Some(maybe.to_db_valueset_v2()) } ); @@ -298,10 +298,10 @@ impl ReplIncrementalEntryV1 { let live_attr = live_attrs.get(attr_name); let cid = cid.into(); let attr = live_attr.and_then(|maybe| { - if maybe.len() > 0 { - Some(maybe.to_db_valueset_v2()) - } else { + if maybe.is_empty() { None + } else { + Some(maybe.to_db_valueset_v2()) } }); diff --git a/tools/orca/src/models/read.rs b/tools/orca/src/models/read.rs index 2f1cfc601..f11eb9984 100644 --- a/tools/orca/src/models/read.rs +++ b/tools/orca/src/models/read.rs @@ -83,7 +83,7 @@ impl ActorReader { // Is this a design flaw? We probably need to know what the state was that we // requested to move to? match (&self.state, action, result) { - (State::Unauthenticated { .. }, TransitionAction::Login, TransitionResult::Ok) => { + (State::Unauthenticated, TransitionAction::Login, TransitionResult::Ok) => { self.state = State::Authenticated; } (State::Authenticated, TransitionAction::ReadSelfMemberOf, TransitionResult::Ok) => { diff --git a/unix_integration/common/Cargo.toml b/unix_integration/common/Cargo.toml index f25ca7a43..4690ef8a1 100644 --- a/unix_integration/common/Cargo.toml +++ b/unix_integration/common/Cargo.toml @@ -14,6 +14,8 @@ repository = { workspace = true } [features] default = ["unix"] unix = [] +selinux = ["dep:selinux"] +tpm = [] [lib] name = "kanidm_unix_common" @@ -35,6 +37,11 @@ tokio-util = { workspace = true, features = ["codec"] } toml = { workspace = true } tracing = { workspace = true } +selinux = { workspace = true, optional = true } + +[target.'cfg(not(target_family = "windows"))'.dependencies] +kanidm_utils_users = { workspace = true } + [build-dependencies] kanidm_build_profiles = { workspace = true } diff --git a/unix_integration/common/src/lib.rs b/unix_integration/common/src/lib.rs index ee8f849de..94a261d4e 100644 --- a/unix_integration/common/src/lib.rs +++ b/unix_integration/common/src/lib.rs @@ -26,3 +26,6 @@ pub mod unix_config; pub mod unix_passwd; #[cfg(target_family = "unix")] pub mod unix_proto; + +#[cfg(all(target_family = "unix", feature = "selinux"))] +pub mod selinux_util; diff --git a/unix_integration/resolver/src/selinux_util.rs b/unix_integration/common/src/selinux_util.rs similarity index 100% rename from unix_integration/resolver/src/selinux_util.rs rename to unix_integration/common/src/selinux_util.rs diff --git a/unix_integration/common/src/unix_config.rs b/unix_integration/common/src/unix_config.rs index 02a9b43b1..e47224635 100644 --- a/unix_integration/common/src/unix_config.rs +++ b/unix_integration/common/src/unix_config.rs @@ -1,13 +1,24 @@ +//! This is configuration definitions and parser for the various unix integration +//! tools and services. This needs to support a number of use cases like pam/nss +//! modules parsing the config quickly and the unix daemon which has to connect to +//! various backend sources. +//! +//! To achieve this the configuration has two main sections - the configuration +//! specification which will be parsed by the tools, then the configuration as +//! relevant to that tool. + +use std::env; use std::fmt::{Display, Formatter}; use std::fs::File; use std::io::{ErrorKind, Read}; -use std::path::Path; +use std::path::{Path, PathBuf}; +#[cfg(all(target_family = "unix", feature = "selinux"))] +use crate::selinux_util; use crate::unix_passwd::UnixIntegrationError; -use serde::Deserialize; - use crate::constants::*; +use serde::Deserialize; #[derive(Debug, Copy, Clone)] pub enum HomeAttr { @@ -49,35 +60,526 @@ impl Display for UidAttr { } } +#[derive(Debug, Clone, Default)] +pub enum HsmType { + #[cfg_attr(not(feature = "tpm"), default)] + Soft, + #[cfg_attr(feature = "tpm", default)] + TpmIfPossible, + Tpm, +} + +impl Display for HsmType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + HsmType::Soft => write!(f, "Soft"), + HsmType::TpmIfPossible => write!(f, "Tpm if possible"), + HsmType::Tpm => write!(f, "Tpm"), + } + } +} + +// Allowed as the large enum is only short lived at startup to the true config +#[allow(clippy::large_enum_variant)] +// This bit of magic lets us deserialise the old config and the new versions. #[derive(Debug, Deserialize)] -struct ConfigInt { +#[serde(untagged)] +enum ConfigUntagged { + Versioned(ConfigVersion), + Legacy(ConfigInt), +} + +#[derive(Debug, Deserialize)] +#[serde(tag = "version")] +enum ConfigVersion { + #[serde(rename = "2")] + V2 { + #[serde(flatten)] + values: ConfigV2, + }, +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +/// This is the version 2 of the JSON configuration specification for the unixd suite. +struct ConfigV2 { + cache_db_path: Option<String>, sock_path: Option<String>, + task_sock_path: Option<String>, + + cache_timeout: Option<u64>, + + default_shell: Option<String>, + home_prefix: Option<String>, + home_mount_prefix: Option<String>, + home_attr: Option<String>, + home_alias: Option<String>, + use_etc_skel: Option<bool>, + uid_attr_map: Option<String>, + gid_attr_map: Option<String>, + selinux: Option<bool>, + + hsm_pin_path: Option<String>, + hsm_type: Option<String>, + tpm_tcti_name: Option<String>, + + kanidm: Option<KanidmConfigV2>, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct GroupMap { + pub local: String, + pub with: String, +} + +#[derive(Debug, Deserialize)] +struct KanidmConfigV2 { conn_timeout: Option<u64>, + request_timeout: Option<u64>, + pam_allowed_login_groups: Option<Vec<String>>, + #[serde(default)] + map_group: Vec<GroupMap>, +} + +#[derive(Debug, Deserialize)] +/// This is the version 1 of the JSON configuration specification for the unixd suite. +struct ConfigInt { + db_path: Option<String>, + sock_path: Option<String>, + task_sock_path: Option<String>, + conn_timeout: Option<u64>, + request_timeout: Option<u64>, + cache_timeout: Option<u64>, + pam_allowed_login_groups: Option<Vec<String>>, + default_shell: Option<String>, + home_prefix: Option<String>, + home_mount_prefix: Option<String>, + home_attr: Option<String>, + home_alias: Option<String>, + use_etc_skel: Option<bool>, + uid_attr_map: Option<String>, + gid_attr_map: Option<String>, + selinux: Option<bool>, + #[serde(default)] + allow_local_account_override: Vec<String>, + + hsm_pin_path: Option<String>, + hsm_type: Option<String>, + tpm_tcti_name: Option<String>, + + // Detect and warn on values in these places - this is to catch + // when someone is using a v2 value on a v1 config. + #[serde(default)] + cache_db_path: Option<toml::value::Value>, + #[serde(default)] + kanidm: Option<toml::value::Value>, +} + +// ======================================================================== + +#[derive(Debug)] +/// This is the parsed Kanidm provider configuration that the Unixd resolver +/// will use to connect to Kanidm. +pub struct KanidmConfig { + pub conn_timeout: u64, + pub request_timeout: u64, + pub pam_allowed_login_groups: Vec<String>, + pub map_group: Vec<GroupMap>, } #[derive(Debug)] -pub struct KanidmUnixdConfig { +/// This is the parsed configuration for the Unixd resolver. +pub struct UnixdConfig { + pub cache_db_path: String, + pub sock_path: String, + pub task_sock_path: String, + pub cache_timeout: u64, + pub unix_sock_timeout: u64, + pub default_shell: String, + pub home_prefix: PathBuf, + pub home_mount_prefix: Option<PathBuf>, + pub home_attr: HomeAttr, + pub home_alias: Option<HomeAttr>, + pub use_etc_skel: bool, + pub uid_attr_map: UidAttr, + pub gid_attr_map: UidAttr, + pub selinux: bool, + pub hsm_type: HsmType, + pub hsm_pin_path: String, + pub tpm_tcti_name: String, + pub kanidm_config: Option<KanidmConfig>, +} + +impl Default for UnixdConfig { + fn default() -> Self { + UnixdConfig::new() + } +} + +impl Display for UnixdConfig { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, "cache_db_path: {}", &self.cache_db_path)?; + writeln!(f, "sock_path: {}", self.sock_path)?; + writeln!(f, "task_sock_path: {}", self.task_sock_path)?; + writeln!(f, "unix_sock_timeout: {}", self.unix_sock_timeout)?; + writeln!(f, "cache_timeout: {}", self.cache_timeout)?; + writeln!(f, "default_shell: {}", self.default_shell)?; + writeln!(f, "home_prefix: {:?}", self.home_prefix)?; + match self.home_mount_prefix.as_deref() { + Some(val) => writeln!(f, "home_mount_prefix: {:?}", val)?, + None => writeln!(f, "home_mount_prefix: unset")?, + } + writeln!(f, "home_attr: {}", self.home_attr)?; + match self.home_alias { + Some(val) => writeln!(f, "home_alias: {}", val)?, + None => writeln!(f, "home_alias: unset")?, + } + + writeln!(f, "uid_attr_map: {}", self.uid_attr_map)?; + writeln!(f, "gid_attr_map: {}", self.gid_attr_map)?; + + writeln!(f, "hsm_type: {}", self.hsm_type)?; + writeln!(f, "tpm_tcti_name: {}", self.tpm_tcti_name)?; + + writeln!(f, "selinux: {}", self.selinux)?; + + if let Some(kconfig) = &self.kanidm_config { + writeln!(f, "kanidm: enabled")?; + writeln!( + f, + "kanidm pam_allowed_login_groups: {:#?}", + kconfig.pam_allowed_login_groups + )?; + writeln!(f, "kanidm conn_timeout: {}", kconfig.conn_timeout)?; + writeln!(f, "kanidm request_timeout: {}", kconfig.request_timeout)?; + } else { + writeln!(f, "kanidm: disabled")?; + }; + + Ok(()) + } +} + +impl UnixdConfig { + pub fn new() -> Self { + let cache_db_path = match env::var("KANIDM_CACHE_DB_PATH") { + Ok(val) => val, + Err(_) => DEFAULT_CACHE_DB_PATH.into(), + }; + let hsm_pin_path = match env::var("KANIDM_HSM_PIN_PATH") { + Ok(val) => val, + Err(_) => DEFAULT_HSM_PIN_PATH.into(), + }; + + UnixdConfig { + cache_db_path, + sock_path: DEFAULT_SOCK_PATH.to_string(), + task_sock_path: DEFAULT_TASK_SOCK_PATH.to_string(), + unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, + cache_timeout: DEFAULT_CACHE_TIMEOUT, + default_shell: DEFAULT_SHELL.to_string(), + home_prefix: DEFAULT_HOME_PREFIX.into(), + home_mount_prefix: None, + home_attr: DEFAULT_HOME_ATTR, + home_alias: DEFAULT_HOME_ALIAS, + use_etc_skel: DEFAULT_USE_ETC_SKEL, + uid_attr_map: DEFAULT_UID_ATTR_MAP, + gid_attr_map: DEFAULT_GID_ATTR_MAP, + selinux: DEFAULT_SELINUX, + hsm_pin_path, + hsm_type: HsmType::default(), + tpm_tcti_name: DEFAULT_TPM_TCTI_NAME.to_string(), + + kanidm_config: None, + } + } + + pub fn read_options_from_optional_config<P: AsRef<Path> + std::fmt::Debug>( + self, + config_path: P, + ) -> Result<Self, UnixIntegrationError> { + debug!("Attempting to load configuration from {:#?}", &config_path); + let mut f = match File::open(&config_path) { + Ok(f) => { + debug!("Successfully opened configuration file {:#?}", &config_path); + f + } + Err(e) => { + match e.kind() { + ErrorKind::NotFound => { + debug!( + "Configuration file {:#?} not found, skipping.", + &config_path + ); + } + ErrorKind::PermissionDenied => { + warn!( + "Permission denied loading configuration file {:#?}, skipping.", + &config_path + ); + } + _ => { + debug!( + "Unable to open config file {:#?} [{:?}], skipping ...", + &config_path, e + ); + } + }; + return Ok(self); + } + }; + + let mut contents = String::new(); + f.read_to_string(&mut contents).map_err(|e| { + error!("{:?}", e); + UnixIntegrationError + })?; + + let config: ConfigUntagged = toml::from_str(contents.as_str()).map_err(|e| { + error!("{:?}", e); + UnixIntegrationError + })?; + + match config { + ConfigUntagged::Legacy(config) => self.apply_from_config_legacy(config), + ConfigUntagged::Versioned(ConfigVersion::V2 { values }) => { + self.apply_from_config_v2(values) + } + } + } + + fn apply_from_config_legacy(self, config: ConfigInt) -> Result<Self, UnixIntegrationError> { + if config.kanidm.is_some() || config.cache_db_path.is_some() { + error!("You are using version=\"2\" options in a legacy config. THESE WILL NOT WORK."); + return Err(UnixIntegrationError); + } + + let map_group = config + .allow_local_account_override + .iter() + .map(|name| GroupMap { + local: name.clone(), + with: name.clone(), + }) + .collect(); + + let kanidm_config = Some(KanidmConfig { + conn_timeout: config.conn_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT), + request_timeout: config.request_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT * 2), + pam_allowed_login_groups: config.pam_allowed_login_groups.unwrap_or_default(), + map_group, + }); + + // Now map the values into our config. + Ok(UnixdConfig { + cache_db_path: config.db_path.unwrap_or(self.cache_db_path), + sock_path: config.sock_path.unwrap_or(self.sock_path), + task_sock_path: config.task_sock_path.unwrap_or(self.task_sock_path), + unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, + cache_timeout: config.cache_timeout.unwrap_or(self.cache_timeout), + default_shell: config.default_shell.unwrap_or(self.default_shell), + home_prefix: config + .home_prefix + .map(|p| p.into()) + .unwrap_or(self.home_prefix.clone()), + home_mount_prefix: config.home_mount_prefix.map(|p| p.into()), + home_attr: config + .home_attr + .and_then(|v| match v.as_str() { + "uuid" => Some(HomeAttr::Uuid), + "spn" => Some(HomeAttr::Spn), + "name" => Some(HomeAttr::Name), + _ => { + warn!("Invalid home_attr configured, using default ..."); + None + } + }) + .unwrap_or(self.home_attr), + home_alias: config + .home_alias + .and_then(|v| match v.as_str() { + "none" => Some(None), + "uuid" => Some(Some(HomeAttr::Uuid)), + "spn" => Some(Some(HomeAttr::Spn)), + "name" => Some(Some(HomeAttr::Name)), + _ => { + warn!("Invalid home_alias configured, using default ..."); + None + } + }) + .unwrap_or(self.home_alias), + use_etc_skel: config.use_etc_skel.unwrap_or(self.use_etc_skel), + uid_attr_map: config + .uid_attr_map + .and_then(|v| match v.as_str() { + "spn" => Some(UidAttr::Spn), + "name" => Some(UidAttr::Name), + _ => { + warn!("Invalid uid_attr_map configured, using default ..."); + None + } + }) + .unwrap_or(self.uid_attr_map), + gid_attr_map: config + .gid_attr_map + .and_then(|v| match v.as_str() { + "spn" => Some(UidAttr::Spn), + "name" => Some(UidAttr::Name), + _ => { + warn!("Invalid gid_attr_map configured, using default ..."); + None + } + }) + .unwrap_or(self.gid_attr_map), + selinux: match config.selinux.unwrap_or(self.selinux) { + #[cfg(all(target_family = "unix", feature = "selinux"))] + true => selinux_util::supported(), + _ => false, + }, + hsm_pin_path: config.hsm_pin_path.unwrap_or(self.hsm_pin_path), + hsm_type: config + .hsm_type + .and_then(|v| match v.as_str() { + "soft" => Some(HsmType::Soft), + "tpm_if_possible" => Some(HsmType::TpmIfPossible), + "tpm" => Some(HsmType::Tpm), + _ => { + warn!("Invalid hsm_type configured, using default ..."); + None + } + }) + .unwrap_or(self.hsm_type), + tpm_tcti_name: config + .tpm_tcti_name + .unwrap_or(DEFAULT_TPM_TCTI_NAME.to_string()), + kanidm_config, + }) + } + + fn apply_from_config_v2(self, config: ConfigV2) -> Result<Self, UnixIntegrationError> { + let kanidm_config = if let Some(kconfig) = config.kanidm { + Some(KanidmConfig { + conn_timeout: kconfig.conn_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT), + request_timeout: kconfig.request_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT * 2), + pam_allowed_login_groups: kconfig.pam_allowed_login_groups.unwrap_or_default(), + map_group: kconfig.map_group, + }) + } else { + None + }; + + // Now map the values into our config. + Ok(UnixdConfig { + cache_db_path: config.cache_db_path.unwrap_or(self.cache_db_path), + sock_path: config.sock_path.unwrap_or(self.sock_path), + task_sock_path: config.task_sock_path.unwrap_or(self.task_sock_path), + unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, + cache_timeout: config.cache_timeout.unwrap_or(self.cache_timeout), + default_shell: config.default_shell.unwrap_or(self.default_shell), + home_prefix: config + .home_prefix + .map(|p| p.into()) + .unwrap_or(self.home_prefix.clone()), + home_mount_prefix: config.home_mount_prefix.map(|p| p.into()), + home_attr: config + .home_attr + .and_then(|v| match v.as_str() { + "uuid" => Some(HomeAttr::Uuid), + "spn" => Some(HomeAttr::Spn), + "name" => Some(HomeAttr::Name), + _ => { + warn!("Invalid home_attr configured, using default ..."); + None + } + }) + .unwrap_or(self.home_attr), + home_alias: config + .home_alias + .and_then(|v| match v.as_str() { + "none" => Some(None), + "uuid" => Some(Some(HomeAttr::Uuid)), + "spn" => Some(Some(HomeAttr::Spn)), + "name" => Some(Some(HomeAttr::Name)), + _ => { + warn!("Invalid home_alias configured, using default ..."); + None + } + }) + .unwrap_or(self.home_alias), + use_etc_skel: config.use_etc_skel.unwrap_or(self.use_etc_skel), + uid_attr_map: config + .uid_attr_map + .and_then(|v| match v.as_str() { + "spn" => Some(UidAttr::Spn), + "name" => Some(UidAttr::Name), + _ => { + warn!("Invalid uid_attr_map configured, using default ..."); + None + } + }) + .unwrap_or(self.uid_attr_map), + gid_attr_map: config + .gid_attr_map + .and_then(|v| match v.as_str() { + "spn" => Some(UidAttr::Spn), + "name" => Some(UidAttr::Name), + _ => { + warn!("Invalid gid_attr_map configured, using default ..."); + None + } + }) + .unwrap_or(self.gid_attr_map), + selinux: match config.selinux.unwrap_or(self.selinux) { + #[cfg(all(target_family = "unix", feature = "selinux"))] + true => selinux_util::supported(), + _ => false, + }, + hsm_pin_path: config.hsm_pin_path.unwrap_or(self.hsm_pin_path), + hsm_type: config + .hsm_type + .and_then(|v| match v.as_str() { + "soft" => Some(HsmType::Soft), + "tpm_if_possible" => Some(HsmType::TpmIfPossible), + "tpm" => Some(HsmType::Tpm), + _ => { + warn!("Invalid hsm_type configured, using default ..."); + None + } + }) + .unwrap_or(self.hsm_type), + tpm_tcti_name: config + .tpm_tcti_name + .unwrap_or(DEFAULT_TPM_TCTI_NAME.to_string()), + kanidm_config, + }) + } +} + +#[derive(Debug)] +/// This is the parsed configuration that will be used by pam/nss tools that need fast access to +/// only the socket and timeout information related to the resolver. +pub struct PamNssConfig { pub sock_path: String, // pub conn_timeout: u64, pub unix_sock_timeout: u64, } -impl Default for KanidmUnixdConfig { +impl Default for PamNssConfig { fn default() -> Self { - KanidmUnixdConfig::new() + PamNssConfig::new() } } -impl Display for KanidmUnixdConfig { +impl Display for PamNssConfig { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { writeln!(f, "sock_path: {}", self.sock_path)?; writeln!(f, "unix_sock_timeout: {}", self.unix_sock_timeout) } } -impl KanidmUnixdConfig { +impl PamNssConfig { pub fn new() -> Self { - KanidmUnixdConfig { + PamNssConfig { sock_path: DEFAULT_SOCK_PATH.to_string(), unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, } @@ -124,22 +626,45 @@ impl KanidmUnixdConfig { UnixIntegrationError })?; - let config: ConfigInt = toml::from_str(contents.as_str()).map_err(|e| { + let config: ConfigUntagged = toml::from_str(contents.as_str()).map_err(|e| { error!("{:?}", e); UnixIntegrationError })?; + match config { + ConfigUntagged::Legacy(config) => self.apply_from_config_legacy(config), + ConfigUntagged::Versioned(ConfigVersion::V2 { values }) => { + self.apply_from_config_v2(values) + } + } + } + + fn apply_from_config_legacy(self, config: ConfigInt) -> Result<Self, UnixIntegrationError> { let unix_sock_timeout = config .conn_timeout .map(|v| v * 2) .unwrap_or(self.unix_sock_timeout); // Now map the values into our config. - Ok(KanidmUnixdConfig { + Ok(PamNssConfig { sock_path: config.sock_path.unwrap_or(self.sock_path), unix_sock_timeout, }) } + + fn apply_from_config_v2(self, config: ConfigV2) -> Result<Self, UnixIntegrationError> { + let kanidm_conn_timeout = config + .kanidm + .as_ref() + .and_then(|k_config| k_config.conn_timeout) + .map(|timeout| timeout * 2); + + // Now map the values into our config. + Ok(PamNssConfig { + sock_path: config.sock_path.unwrap_or(self.sock_path), + unix_sock_timeout: kanidm_conn_timeout.unwrap_or(self.unix_sock_timeout), + }) + } } #[cfg(test)] @@ -165,9 +690,12 @@ mod tests { if filename.starts_with("unixd") { print!("Checking that {} parses as a valid config...", filename); - KanidmUnixdConfig::new() + UnixdConfig::new() .read_options_from_optional_config(file.path()) - .expect("Failed to parse"); + .inspect_err(|e| { + println!("Failed to parse: {:?}", e); + }) + .expect("Failed to parse!"); println!("OK"); } } diff --git a/unix_integration/nss_kanidm/src/core.rs b/unix_integration/nss_kanidm/src/core.rs index d60ba9839..a59c58581 100644 --- a/unix_integration/nss_kanidm/src/core.rs +++ b/unix_integration/nss_kanidm/src/core.rs @@ -1,5 +1,5 @@ use kanidm_unix_common::client_sync::DaemonClientBlocking; -use kanidm_unix_common::unix_config::KanidmUnixdConfig; +use kanidm_unix_common::unix_config::PamNssConfig; use kanidm_unix_common::unix_passwd::{ read_etc_group_file, read_etc_passwd_file, EtcGroup, EtcUser, }; @@ -36,7 +36,7 @@ impl RequestOptions { fn connect_to_daemon(self) -> Source { match self { RequestOptions::Main { config_path } => { - let maybe_client = KanidmUnixdConfig::new() + let maybe_client = PamNssConfig::new() .read_options_from_optional_config(config_path) .ok() .and_then(|cfg| { diff --git a/unix_integration/pam_kanidm/src/core.rs b/unix_integration/pam_kanidm/src/core.rs index 79d3ea960..dd1ecf8ae 100644 --- a/unix_integration/pam_kanidm/src/core.rs +++ b/unix_integration/pam_kanidm/src/core.rs @@ -2,7 +2,7 @@ use crate::constants::PamResultCode; use crate::module::PamResult; use crate::pam::ModuleOptions; use kanidm_unix_common::client_sync::DaemonClientBlocking; -use kanidm_unix_common::unix_config::KanidmUnixdConfig; +use kanidm_unix_common::unix_config::PamNssConfig; use kanidm_unix_common::unix_passwd::{ read_etc_passwd_file, read_etc_shadow_file, EtcShadow, EtcUser, }; @@ -44,7 +44,7 @@ impl RequestOptions { fn connect_to_daemon(self) -> Source { match self { RequestOptions::Main { config_path } => { - let maybe_client = KanidmUnixdConfig::new() + let maybe_client = PamNssConfig::new() .read_options_from_optional_config(config_path) .ok() .and_then(|cfg| { diff --git a/unix_integration/pam_kanidm/src/pam/mod.rs b/unix_integration/pam_kanidm/src/pam/mod.rs index 0a40b1c25..6fb79a762 100755 --- a/unix_integration/pam_kanidm/src/pam/mod.rs +++ b/unix_integration/pam_kanidm/src/pam/mod.rs @@ -36,7 +36,7 @@ use std::convert::TryFrom; use std::ffi::CStr; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; -use kanidm_unix_common::unix_config::KanidmUnixdConfig; +use kanidm_unix_common::unix_config::PamNssConfig; use crate::core::{self, RequestOptions}; use crate::pam::constants::*; @@ -50,8 +50,8 @@ use tracing_subscriber::filter::LevelFilter; use tracing_subscriber::fmt; use tracing_subscriber::prelude::*; -pub fn get_cfg() -> Result<KanidmUnixdConfig, PamResultCode> { - KanidmUnixdConfig::new() +pub fn get_cfg() -> Result<PamNssConfig, PamResultCode> { + PamNssConfig::new() .read_options_from_optional_config(DEFAULT_CONFIG_PATH) .map_err(|_| PamResultCode::PAM_SERVICE_ERR) } diff --git a/unix_integration/resolver/Cargo.toml b/unix_integration/resolver/Cargo.toml index 96e09bbee..3c6d86e18 100644 --- a/unix_integration/resolver/Cargo.toml +++ b/unix_integration/resolver/Cargo.toml @@ -14,8 +14,8 @@ repository = { workspace = true } [features] default = ["unix"] unix = [] -selinux = ["dep:selinux"] -tpm = ["kanidm-hsm-crypto/tpm"] +selinux = ["dep:selinux", "kanidm_unix_common/selinux"] +tpm = ["kanidm-hsm-crypto/tpm", "kanidm_unix_common/tpm"] [[bin]] name = "kanidm_unixd" diff --git a/unix_integration/resolver/src/bin/kanidm-unix.rs b/unix_integration/resolver/src/bin/kanidm-unix.rs index b27424769..67c07ece1 100644 --- a/unix_integration/resolver/src/bin/kanidm-unix.rs +++ b/unix_integration/resolver/src/bin/kanidm-unix.rs @@ -18,7 +18,7 @@ use std::process::ExitCode; use clap::Parser; use kanidm_unix_common::client::DaemonClient; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; -use kanidm_unix_common::unix_config::KanidmUnixdConfig; +use kanidm_unix_common::unix_config::PamNssConfig; use kanidm_unix_common::unix_proto::{ ClientRequest, ClientResponse, PamAuthRequest, PamAuthResponse, PamServiceInfo, }; @@ -28,8 +28,7 @@ include!("../opt/tool.rs"); macro_rules! setup_client { () => {{ - let Ok(cfg) = - KanidmUnixdConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH) + let Ok(cfg) = PamNssConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH) else { error!("Failed to parse {}", DEFAULT_CONFIG_PATH); return ExitCode::FAILURE; diff --git a/unix_integration/resolver/src/bin/kanidm_ssh_authorizedkeys.rs b/unix_integration/resolver/src/bin/kanidm_ssh_authorizedkeys.rs index e20ff3178..4878b7b37 100644 --- a/unix_integration/resolver/src/bin/kanidm_ssh_authorizedkeys.rs +++ b/unix_integration/resolver/src/bin/kanidm_ssh_authorizedkeys.rs @@ -19,7 +19,7 @@ use std::process::ExitCode; use clap::Parser; use kanidm_unix_common::client::DaemonClient; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; -use kanidm_unix_common::unix_config::KanidmUnixdConfig; +use kanidm_unix_common::unix_config::PamNssConfig; use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse}; include!("../opt/ssh_authorizedkeys.rs"); @@ -44,8 +44,7 @@ async fn main() -> ExitCode { debug!("Starting authorized keys tool ..."); - let cfg = match KanidmUnixdConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH) - { + let cfg = match PamNssConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH) { Ok(c) => c, Err(e) => { error!("Failed to parse {}: {:?}", DEFAULT_CONFIG_PATH, e); diff --git a/unix_integration/resolver/src/bin/kanidm_unixd.rs b/unix_integration/resolver/src/bin/kanidm_unixd.rs index c89fc30d4..1a8e89382 100644 --- a/unix_integration/resolver/src/bin/kanidm_unixd.rs +++ b/unix_integration/resolver/src/bin/kanidm_unixd.rs @@ -18,6 +18,7 @@ use kanidm_hsm_crypto::{soft::SoftTpm, AuthValue, BoxedDynTpm, Tpm}; use kanidm_proto::constants::DEFAULT_CLIENT_CONFIG_PATH; use kanidm_proto::internal::OperationError; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; +use kanidm_unix_common::unix_config::{HsmType, UnixdConfig}; use kanidm_unix_common::unix_passwd::EtcDb; use kanidm_unix_common::unix_proto::{ ClientRequest, ClientResponse, TaskRequest, TaskRequestFrame, TaskResponse, @@ -27,7 +28,6 @@ use kanidm_unix_resolver::idprovider::interface::IdProvider; use kanidm_unix_resolver::idprovider::kanidm::KanidmProvider; use kanidm_unix_resolver::idprovider::system::SystemProvider; use kanidm_unix_resolver::resolver::Resolver; -use kanidm_unix_resolver::unix_config::{HsmType, UnixdConfig}; use kanidm_utils_users::{get_current_gid, get_current_uid, get_effective_gid, get_effective_uid}; use libc::umask; use sketching::tracing::span; diff --git a/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs b/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs index ccaddc8d2..cfbf03d67 100644 --- a/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs +++ b/unix_integration/resolver/src/bin/kanidm_unixd_tasks.rs @@ -13,11 +13,11 @@ use bytes::{BufMut, BytesMut}; use futures::{SinkExt, StreamExt}; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; +use kanidm_unix_common::unix_config::UnixdConfig; use kanidm_unix_common::unix_passwd::{parse_etc_group, parse_etc_passwd, parse_etc_shadow, EtcDb}; use kanidm_unix_common::unix_proto::{ HomeDirectoryInfo, TaskRequest, TaskRequestFrame, TaskResponse, }; -use kanidm_unix_resolver::unix_config::UnixdConfig; use kanidm_utils_users::{get_effective_gid, get_effective_uid}; use libc::{lchown, umask}; use notify_debouncer_full::notify::RecommendedWatcher; @@ -43,7 +43,7 @@ use tokio_util::codec::{Decoder, Encoder, Framed}; use walkdir::WalkDir; #[cfg(all(target_family = "unix", feature = "selinux"))] -use kanidm_unix_resolver::selinux_util; +use kanidm_unix_common::selinux_util; struct TaskCodec; diff --git a/unix_integration/resolver/src/idprovider/kanidm.rs b/unix_integration/resolver/src/idprovider/kanidm.rs index d0a6a8159..9665cd48b 100644 --- a/unix_integration/resolver/src/idprovider/kanidm.rs +++ b/unix_integration/resolver/src/idprovider/kanidm.rs @@ -1,24 +1,22 @@ -use crate::db::KeyStoreTxn; -use crate::unix_config::{GroupMap, KanidmConfig}; -use async_trait::async_trait; -use hashbrown::HashMap; -use kanidm_client::{ClientError, KanidmClient, StatusCode}; -use kanidm_proto::internal::OperationError; -use kanidm_proto::v1::{UnixGroupToken, UnixUserToken}; -use std::collections::BTreeSet; -use std::time::{Duration, SystemTime}; -use tokio::sync::{broadcast, Mutex}; - -use kanidm_lib_crypto::CryptoPolicy; -use kanidm_lib_crypto::DbPasswordV1; -use kanidm_lib_crypto::Password; - use super::interface::{ tpm::{self, HmacKey, Tpm}, AuthCredHandler, AuthRequest, AuthResult, GroupToken, GroupTokenState, Id, IdProvider, IdpError, ProviderOrigin, UserToken, UserTokenState, }; +use crate::db::KeyStoreTxn; +use async_trait::async_trait; +use hashbrown::HashMap; +use kanidm_client::{ClientError, KanidmClient, StatusCode}; +use kanidm_lib_crypto::CryptoPolicy; +use kanidm_lib_crypto::DbPasswordV1; +use kanidm_lib_crypto::Password; +use kanidm_proto::internal::OperationError; +use kanidm_proto::v1::{UnixGroupToken, UnixUserToken}; +use kanidm_unix_common::unix_config::{GroupMap, KanidmConfig}; use kanidm_unix_common::unix_proto::PamAuthRequest; +use std::collections::BTreeSet; +use std::time::{Duration, SystemTime}; +use tokio::sync::{broadcast, Mutex}; const KANIDM_HMAC_KEY: &str = "kanidm-hmac-key"; const KANIDM_PWV1_KEY: &str = "kanidm-pw-v1"; diff --git a/unix_integration/resolver/src/lib.rs b/unix_integration/resolver/src/lib.rs index 96b49d026..cbb1c1ee3 100644 --- a/unix_integration/resolver/src/lib.rs +++ b/unix_integration/resolver/src/lib.rs @@ -23,7 +23,3 @@ pub mod db; pub mod idprovider; #[cfg(target_family = "unix")] pub mod resolver; -#[cfg(all(target_family = "unix", feature = "selinux"))] -pub mod selinux_util; -#[cfg(target_family = "unix")] -pub mod unix_config; diff --git a/unix_integration/resolver/src/resolver.rs b/unix_integration/resolver/src/resolver.rs index 6bef8dbb9..a824fd9d1 100644 --- a/unix_integration/resolver/src/resolver.rs +++ b/unix_integration/resolver/src/resolver.rs @@ -1,18 +1,4 @@ // use async_trait::async_trait; -use hashbrown::HashMap; -use std::fmt::Display; -use std::num::NonZeroUsize; -use std::ops::DerefMut; -use std::path::{Path, PathBuf}; -use std::string::ToString; -use std::sync::Arc; -use std::time::{Duration, SystemTime}; - -use lru::LruCache; -use time::OffsetDateTime; -use tokio::sync::Mutex; -use uuid::Uuid; - use crate::db::{Cache, Db}; use crate::idprovider::interface::{ AuthCredHandler, @@ -30,13 +16,25 @@ use crate::idprovider::interface::{ use crate::idprovider::system::{ Shadow, SystemAuthResult, SystemProvider, SystemProviderAuthInit, SystemProviderSession, }; -use crate::unix_config::{HomeAttr, UidAttr}; +use hashbrown::HashMap; use kanidm_unix_common::constants::DEFAULT_SHELL_SEARCH_PATHS; +use kanidm_unix_common::unix_config::{HomeAttr, UidAttr}; use kanidm_unix_common::unix_passwd::{EtcGroup, EtcShadow, EtcUser}; use kanidm_unix_common::unix_proto::{ HomeDirectoryInfo, NssGroup, NssUser, PamAuthRequest, PamAuthResponse, PamServiceInfo, ProviderStatus, }; +use lru::LruCache; +use std::fmt::Display; +use std::num::NonZeroUsize; +use std::ops::DerefMut; +use std::path::{Path, PathBuf}; +use std::string::ToString; +use std::sync::Arc; +use std::time::{Duration, SystemTime}; +use time::OffsetDateTime; +use tokio::sync::Mutex; +use uuid::Uuid; use kanidm_hsm_crypto::BoxedDynTpm; diff --git a/unix_integration/resolver/src/unix_config.rs b/unix_integration/resolver/src/unix_config.rs deleted file mode 100644 index e8a739401..000000000 --- a/unix_integration/resolver/src/unix_config.rs +++ /dev/null @@ -1,538 +0,0 @@ -use std::env; -use std::fmt::{Display, Formatter}; -use std::fs::File; -use std::io::{ErrorKind, Read}; -use std::path::{Path, PathBuf}; - -#[cfg(all(target_family = "unix", feature = "selinux"))] -use crate::selinux_util; -use kanidm_unix_common::unix_passwd::UnixIntegrationError; - -pub(crate) use kanidm_unix_common::unix_config::{HomeAttr, UidAttr}; - -use serde::Deserialize; - -use kanidm_unix_common::constants::*; - -// Allowed as the large enum is only short lived at startup to the true config -#[allow(clippy::large_enum_variant)] -// This bit of magic lets us deserialise the old config and the new versions. -#[derive(Debug, Deserialize)] -#[serde(untagged)] -enum ConfigUntagged { - Versioned(ConfigVersion), - Legacy(ConfigInt), -} - -#[derive(Debug, Deserialize)] -#[serde(tag = "version")] -enum ConfigVersion { - #[serde(rename = "2")] - V2 { - #[serde(flatten)] - values: ConfigV2, - }, -} - -#[derive(Debug, Deserialize)] -#[serde(deny_unknown_fields)] -struct ConfigV2 { - cache_db_path: Option<String>, - sock_path: Option<String>, - task_sock_path: Option<String>, - - cache_timeout: Option<u64>, - - default_shell: Option<String>, - home_prefix: Option<String>, - home_mount_prefix: Option<String>, - home_attr: Option<String>, - home_alias: Option<String>, - use_etc_skel: Option<bool>, - uid_attr_map: Option<String>, - gid_attr_map: Option<String>, - selinux: Option<bool>, - - hsm_pin_path: Option<String>, - hsm_type: Option<String>, - tpm_tcti_name: Option<String>, - - kanidm: Option<KanidmConfigV2>, -} - -#[derive(Clone, Debug, Deserialize)] -pub struct GroupMap { - pub local: String, - pub with: String, -} - -#[derive(Debug, Deserialize)] -struct KanidmConfigV2 { - conn_timeout: Option<u64>, - request_timeout: Option<u64>, - pam_allowed_login_groups: Option<Vec<String>>, - #[serde(default)] - map_group: Vec<GroupMap>, -} - -#[derive(Debug, Deserialize)] -struct ConfigInt { - db_path: Option<String>, - sock_path: Option<String>, - task_sock_path: Option<String>, - conn_timeout: Option<u64>, - request_timeout: Option<u64>, - cache_timeout: Option<u64>, - pam_allowed_login_groups: Option<Vec<String>>, - default_shell: Option<String>, - home_prefix: Option<String>, - home_mount_prefix: Option<String>, - home_attr: Option<String>, - home_alias: Option<String>, - use_etc_skel: Option<bool>, - uid_attr_map: Option<String>, - gid_attr_map: Option<String>, - selinux: Option<bool>, - #[serde(default)] - allow_local_account_override: Vec<String>, - - hsm_pin_path: Option<String>, - hsm_type: Option<String>, - tpm_tcti_name: Option<String>, - - // Detect and warn on values in these places. - #[serde(default)] - cache_db_path: Option<toml::value::Value>, - #[serde(default)] - kanidm: Option<toml::value::Value>, -} - -#[derive(Debug, Clone, Default)] -pub enum HsmType { - #[cfg_attr(not(feature = "tpm"), default)] - Soft, - #[cfg_attr(feature = "tpm", default)] - TpmIfPossible, - Tpm, -} - -impl Display for HsmType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - HsmType::Soft => write!(f, "Soft"), - HsmType::TpmIfPossible => write!(f, "Tpm if possible"), - HsmType::Tpm => write!(f, "Tpm"), - } - } -} - -#[derive(Debug)] -pub struct UnixdConfig { - pub cache_db_path: String, - pub sock_path: String, - pub task_sock_path: String, - pub cache_timeout: u64, - pub unix_sock_timeout: u64, - pub default_shell: String, - pub home_prefix: PathBuf, - pub home_mount_prefix: Option<PathBuf>, - pub home_attr: HomeAttr, - pub home_alias: Option<HomeAttr>, - pub use_etc_skel: bool, - pub uid_attr_map: UidAttr, - pub gid_attr_map: UidAttr, - pub selinux: bool, - pub hsm_type: HsmType, - pub hsm_pin_path: String, - pub tpm_tcti_name: String, - - pub kanidm_config: Option<KanidmConfig>, -} - -#[derive(Debug)] -pub struct KanidmConfig { - pub conn_timeout: u64, - pub request_timeout: u64, - pub pam_allowed_login_groups: Vec<String>, - pub map_group: Vec<GroupMap>, -} - -impl Default for UnixdConfig { - fn default() -> Self { - UnixdConfig::new() - } -} - -impl Display for UnixdConfig { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, "cache_db_path: {}", &self.cache_db_path)?; - writeln!(f, "sock_path: {}", self.sock_path)?; - writeln!(f, "task_sock_path: {}", self.task_sock_path)?; - writeln!(f, "unix_sock_timeout: {}", self.unix_sock_timeout)?; - writeln!(f, "cache_timeout: {}", self.cache_timeout)?; - writeln!(f, "default_shell: {}", self.default_shell)?; - writeln!(f, "home_prefix: {:?}", self.home_prefix)?; - match self.home_mount_prefix.as_deref() { - Some(val) => writeln!(f, "home_mount_prefix: {:?}", val)?, - None => writeln!(f, "home_mount_prefix: unset")?, - } - writeln!(f, "home_attr: {}", self.home_attr)?; - match self.home_alias { - Some(val) => writeln!(f, "home_alias: {}", val)?, - None => writeln!(f, "home_alias: unset")?, - } - - writeln!(f, "uid_attr_map: {}", self.uid_attr_map)?; - writeln!(f, "gid_attr_map: {}", self.gid_attr_map)?; - - writeln!(f, "hsm_type: {}", self.hsm_type)?; - writeln!(f, "tpm_tcti_name: {}", self.tpm_tcti_name)?; - - writeln!(f, "selinux: {}", self.selinux)?; - - if let Some(kconfig) = &self.kanidm_config { - writeln!(f, "kanidm: enabled")?; - writeln!( - f, - "kanidm pam_allowed_login_groups: {:#?}", - kconfig.pam_allowed_login_groups - )?; - writeln!(f, "kanidm conn_timeout: {}", kconfig.conn_timeout)?; - writeln!(f, "kanidm request_timeout: {}", kconfig.request_timeout)?; - } else { - writeln!(f, "kanidm: disabled")?; - }; - - Ok(()) - } -} - -impl UnixdConfig { - pub fn new() -> Self { - let cache_db_path = match env::var("KANIDM_CACHE_DB_PATH") { - Ok(val) => val, - Err(_) => DEFAULT_CACHE_DB_PATH.into(), - }; - let hsm_pin_path = match env::var("KANIDM_HSM_PIN_PATH") { - Ok(val) => val, - Err(_) => DEFAULT_HSM_PIN_PATH.into(), - }; - - UnixdConfig { - cache_db_path, - sock_path: DEFAULT_SOCK_PATH.to_string(), - task_sock_path: DEFAULT_TASK_SOCK_PATH.to_string(), - unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, - cache_timeout: DEFAULT_CACHE_TIMEOUT, - default_shell: DEFAULT_SHELL.to_string(), - home_prefix: DEFAULT_HOME_PREFIX.into(), - home_mount_prefix: None, - home_attr: DEFAULT_HOME_ATTR, - home_alias: DEFAULT_HOME_ALIAS, - use_etc_skel: DEFAULT_USE_ETC_SKEL, - uid_attr_map: DEFAULT_UID_ATTR_MAP, - gid_attr_map: DEFAULT_GID_ATTR_MAP, - selinux: DEFAULT_SELINUX, - hsm_pin_path, - hsm_type: HsmType::default(), - tpm_tcti_name: DEFAULT_TPM_TCTI_NAME.to_string(), - - kanidm_config: None, - } - } - - pub fn read_options_from_optional_config<P: AsRef<Path> + std::fmt::Debug>( - self, - config_path: P, - ) -> Result<Self, UnixIntegrationError> { - debug!("Attempting to load configuration from {:#?}", &config_path); - let mut f = match File::open(&config_path) { - Ok(f) => { - debug!("Successfully opened configuration file {:#?}", &config_path); - f - } - Err(e) => { - match e.kind() { - ErrorKind::NotFound => { - debug!( - "Configuration file {:#?} not found, skipping.", - &config_path - ); - } - ErrorKind::PermissionDenied => { - warn!( - "Permission denied loading configuration file {:#?}, skipping.", - &config_path - ); - } - _ => { - debug!( - "Unable to open config file {:#?} [{:?}], skipping ...", - &config_path, e - ); - } - }; - return Ok(self); - } - }; - - let mut contents = String::new(); - f.read_to_string(&mut contents).map_err(|e| { - error!("{:?}", e); - UnixIntegrationError - })?; - - let config: ConfigUntagged = toml::from_str(contents.as_str()).map_err(|e| { - error!("{:?}", e); - UnixIntegrationError - })?; - - match config { - ConfigUntagged::Legacy(config) => self.apply_from_config_legacy(config), - ConfigUntagged::Versioned(ConfigVersion::V2 { values }) => { - self.apply_from_config_v2(values) - } - } - } - - fn apply_from_config_legacy(self, config: ConfigInt) -> Result<Self, UnixIntegrationError> { - if config.kanidm.is_some() || config.cache_db_path.is_some() { - error!("You are using version=\"2\" options in a legacy config. THESE WILL NOT WORK."); - return Err(UnixIntegrationError); - } - - let map_group = config - .allow_local_account_override - .iter() - .map(|name| GroupMap { - local: name.clone(), - with: name.clone(), - }) - .collect(); - - let kanidm_config = Some(KanidmConfig { - conn_timeout: config.conn_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT), - request_timeout: config.request_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT * 2), - pam_allowed_login_groups: config.pam_allowed_login_groups.unwrap_or_default(), - map_group, - }); - - // Now map the values into our config. - Ok(UnixdConfig { - cache_db_path: config.db_path.unwrap_or(self.cache_db_path), - sock_path: config.sock_path.unwrap_or(self.sock_path), - task_sock_path: config.task_sock_path.unwrap_or(self.task_sock_path), - unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, - cache_timeout: config.cache_timeout.unwrap_or(self.cache_timeout), - default_shell: config.default_shell.unwrap_or(self.default_shell), - home_prefix: config - .home_prefix - .map(|p| p.into()) - .unwrap_or(self.home_prefix.clone()), - home_mount_prefix: config.home_mount_prefix.map(|p| p.into()), - home_attr: config - .home_attr - .and_then(|v| match v.as_str() { - "uuid" => Some(HomeAttr::Uuid), - "spn" => Some(HomeAttr::Spn), - "name" => Some(HomeAttr::Name), - _ => { - warn!("Invalid home_attr configured, using default ..."); - None - } - }) - .unwrap_or(self.home_attr), - home_alias: config - .home_alias - .and_then(|v| match v.as_str() { - "none" => Some(None), - "uuid" => Some(Some(HomeAttr::Uuid)), - "spn" => Some(Some(HomeAttr::Spn)), - "name" => Some(Some(HomeAttr::Name)), - _ => { - warn!("Invalid home_alias configured, using default ..."); - None - } - }) - .unwrap_or(self.home_alias), - use_etc_skel: config.use_etc_skel.unwrap_or(self.use_etc_skel), - uid_attr_map: config - .uid_attr_map - .and_then(|v| match v.as_str() { - "spn" => Some(UidAttr::Spn), - "name" => Some(UidAttr::Name), - _ => { - warn!("Invalid uid_attr_map configured, using default ..."); - None - } - }) - .unwrap_or(self.uid_attr_map), - gid_attr_map: config - .gid_attr_map - .and_then(|v| match v.as_str() { - "spn" => Some(UidAttr::Spn), - "name" => Some(UidAttr::Name), - _ => { - warn!("Invalid gid_attr_map configured, using default ..."); - None - } - }) - .unwrap_or(self.gid_attr_map), - selinux: match config.selinux.unwrap_or(self.selinux) { - #[cfg(all(target_family = "unix", feature = "selinux"))] - true => selinux_util::supported(), - _ => false, - }, - hsm_pin_path: config.hsm_pin_path.unwrap_or(self.hsm_pin_path), - hsm_type: config - .hsm_type - .and_then(|v| match v.as_str() { - "soft" => Some(HsmType::Soft), - "tpm_if_possible" => Some(HsmType::TpmIfPossible), - "tpm" => Some(HsmType::Tpm), - _ => { - warn!("Invalid hsm_type configured, using default ..."); - None - } - }) - .unwrap_or(self.hsm_type), - tpm_tcti_name: config - .tpm_tcti_name - .unwrap_or(DEFAULT_TPM_TCTI_NAME.to_string()), - kanidm_config, - }) - } - - fn apply_from_config_v2(self, config: ConfigV2) -> Result<Self, UnixIntegrationError> { - let kanidm_config = if let Some(kconfig) = config.kanidm { - Some(KanidmConfig { - conn_timeout: kconfig.conn_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT), - request_timeout: kconfig.request_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT * 2), - pam_allowed_login_groups: kconfig.pam_allowed_login_groups.unwrap_or_default(), - map_group: kconfig.map_group, - }) - } else { - None - }; - - // Now map the values into our config. - Ok(UnixdConfig { - cache_db_path: config.cache_db_path.unwrap_or(self.cache_db_path), - sock_path: config.sock_path.unwrap_or(self.sock_path), - task_sock_path: config.task_sock_path.unwrap_or(self.task_sock_path), - unix_sock_timeout: DEFAULT_CONN_TIMEOUT * 2, - cache_timeout: config.cache_timeout.unwrap_or(self.cache_timeout), - default_shell: config.default_shell.unwrap_or(self.default_shell), - home_prefix: config - .home_prefix - .map(|p| p.into()) - .unwrap_or(self.home_prefix.clone()), - home_mount_prefix: config.home_mount_prefix.map(|p| p.into()), - home_attr: config - .home_attr - .and_then(|v| match v.as_str() { - "uuid" => Some(HomeAttr::Uuid), - "spn" => Some(HomeAttr::Spn), - "name" => Some(HomeAttr::Name), - _ => { - warn!("Invalid home_attr configured, using default ..."); - None - } - }) - .unwrap_or(self.home_attr), - home_alias: config - .home_alias - .and_then(|v| match v.as_str() { - "none" => Some(None), - "uuid" => Some(Some(HomeAttr::Uuid)), - "spn" => Some(Some(HomeAttr::Spn)), - "name" => Some(Some(HomeAttr::Name)), - _ => { - warn!("Invalid home_alias configured, using default ..."); - None - } - }) - .unwrap_or(self.home_alias), - use_etc_skel: config.use_etc_skel.unwrap_or(self.use_etc_skel), - uid_attr_map: config - .uid_attr_map - .and_then(|v| match v.as_str() { - "spn" => Some(UidAttr::Spn), - "name" => Some(UidAttr::Name), - _ => { - warn!("Invalid uid_attr_map configured, using default ..."); - None - } - }) - .unwrap_or(self.uid_attr_map), - gid_attr_map: config - .gid_attr_map - .and_then(|v| match v.as_str() { - "spn" => Some(UidAttr::Spn), - "name" => Some(UidAttr::Name), - _ => { - warn!("Invalid gid_attr_map configured, using default ..."); - None - } - }) - .unwrap_or(self.gid_attr_map), - selinux: match config.selinux.unwrap_or(self.selinux) { - #[cfg(all(target_family = "unix", feature = "selinux"))] - true => selinux_util::supported(), - _ => false, - }, - hsm_pin_path: config.hsm_pin_path.unwrap_or(self.hsm_pin_path), - hsm_type: config - .hsm_type - .and_then(|v| match v.as_str() { - "soft" => Some(HsmType::Soft), - "tpm_if_possible" => Some(HsmType::TpmIfPossible), - "tpm" => Some(HsmType::Tpm), - _ => { - warn!("Invalid hsm_type configured, using default ..."); - None - } - }) - .unwrap_or(self.hsm_type), - tpm_tcti_name: config - .tpm_tcti_name - .unwrap_or(DEFAULT_TPM_TCTI_NAME.to_string()), - kanidm_config, - }) - } -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use super::*; - - #[test] - fn test_load_example_configs() { - // Test the various included configs - - let examples_dir = env!("CARGO_MANIFEST_DIR").to_string() + "/../../examples/"; - - for file in PathBuf::from(&examples_dir) - .canonicalize() - .expect(&format!("Can't find examples dir at {}", examples_dir)) - .read_dir() - .expect("Can't read examples dir!") - { - let file = file.unwrap(); - let filename = file.file_name().into_string().unwrap(); - if filename.starts_with("unixd") { - print!("Checking that {} parses as a valid config...", filename); - - UnixdConfig::new() - .read_options_from_optional_config(file.path()) - .inspect_err(|e| { - println!("Failed to parse: {:?}", e); - }) - .expect("Failed to parse!"); - println!("OK"); - } - } - } -} diff --git a/unix_integration/resolver/tests/cache_layer_test.rs b/unix_integration/resolver/tests/cache_layer_test.rs index 84c31a09a..ad85f48ec 100644 --- a/unix_integration/resolver/tests/cache_layer_test.rs +++ b/unix_integration/resolver/tests/cache_layer_test.rs @@ -12,13 +12,13 @@ use kanidm_unix_common::constants::{ DEFAULT_GID_ATTR_MAP, DEFAULT_HOME_ALIAS, DEFAULT_HOME_ATTR, DEFAULT_HOME_PREFIX, DEFAULT_SHELL, DEFAULT_UID_ATTR_MAP, }; +use kanidm_unix_common::unix_config::{GroupMap, KanidmConfig}; use kanidm_unix_common::unix_passwd::{CryptPw, EtcGroup, EtcShadow, EtcUser}; use kanidm_unix_resolver::db::{Cache, Db}; use kanidm_unix_resolver::idprovider::interface::Id; use kanidm_unix_resolver::idprovider::kanidm::KanidmProvider; use kanidm_unix_resolver::idprovider::system::SystemProvider; use kanidm_unix_resolver::resolver::Resolver; -use kanidm_unix_resolver::unix_config::{GroupMap, KanidmConfig}; use kanidmd_core::config::{Configuration, IntegrationTestConfig, ServerRole}; use kanidmd_core::create_server_core; use kanidmd_testkit::{is_free_port, PORT_ALLOC}; From 5458b133981d7f2d1ab36f7b4d284f9b5ff8d235 Mon Sep 17 00:00:00 2001 From: James Hodgkinson <james@terminaloutcomes.com> Date: Tue, 8 Apr 2025 14:48:53 +1000 Subject: [PATCH 03/10] Less footguns (#3552) --- scripts/install_ubuntu_dependencies.sh | 6 ++---- unix_integration/common/src/unix_config.rs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/scripts/install_ubuntu_dependencies.sh b/scripts/install_ubuntu_dependencies.sh index 61833e3c2..fdfa6e2c8 100755 --- a/scripts/install_ubuntu_dependencies.sh +++ b/scripts/install_ubuntu_dependencies.sh @@ -21,6 +21,8 @@ ${SUDOCMD} apt-get update && cmake \ build-essential \ jq \ + lld \ + clang \ tpm-udev if [ -z "${PACKAGING}" ]; then @@ -73,10 +75,6 @@ if [ -z "$(which cargo)" ]; then ERROR=1 fi -if [ $ERROR -eq 0 ] && [ -z "$(which cross)" ]; then - echo "You don't have cross installed! Installing it now..." - cargo install -f cross -fi if [ $ERROR -eq 0 ] && [ -z "$(which cargo-deb)" ]; then echo "You don't have cargo-deb installed! Installing it now..." cargo install -f cargo-deb diff --git a/unix_integration/common/src/unix_config.rs b/unix_integration/common/src/unix_config.rs index e47224635..09dd7d069 100644 --- a/unix_integration/common/src/unix_config.rs +++ b/unix_integration/common/src/unix_config.rs @@ -458,6 +458,16 @@ impl UnixdConfig { fn apply_from_config_v2(self, config: ConfigV2) -> Result<Self, UnixIntegrationError> { let kanidm_config = if let Some(kconfig) = config.kanidm { + match &kconfig.pam_allowed_login_groups { + None => { + error!("You have a 'kanidm' section in the config but an empty pam_allowed_login_groups set. USERS CANNOT AUTH.") + } + Some(groups) => { + if groups.is_empty() { + error!("You have a 'kanidm' section in the config but an empty pam_allowed_login_groups set. USERS CANNOT AUTH."); + } + } + } Some(KanidmConfig { conn_timeout: kconfig.conn_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT), request_timeout: kconfig.request_timeout.unwrap_or(DEFAULT_CONN_TIMEOUT * 2), @@ -465,6 +475,9 @@ impl UnixdConfig { map_group: kconfig.map_group, }) } else { + error!( + "You are using a version 2 config without a 'kanidm' section. USERS CANNOT AUTH." + ); None }; From aee9ed05f3e03b827bb38bc7e62a262b99ad3717 Mon Sep 17 00:00:00 2001 From: Firstyear <william@blackhats.net.au> Date: Tue, 8 Apr 2025 15:04:26 +1000 Subject: [PATCH 04/10] Update fs4 and improve klock handling (#3551) --- Cargo.lock | 8 +++---- Cargo.toml | 2 +- server/daemon/src/main.rs | 45 ++++++++++++++++++++++++++++++++------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ba0a6ab6..41de134b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,12 +1600,12 @@ dependencies = [ [[package]] name = "fs4" -version = "0.12.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c29c30684418547d476f0b48e84f4821639119c483b1eccd566c8cd0cd05f521" +checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4" dependencies = [ - "rustix 0.38.44", - "windows-sys 0.52.0", + "rustix 1.0.3", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8777db081..cd104992b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -173,7 +173,7 @@ dhat = "0.3.3" dyn-clone = "^1.0.17" fernet = "^0.2.1" filetime = "^0.2.24" -fs4 = "^0.12.0" +fs4 = "^0.13.0" futures = "^0.3.31" futures-util = { version = "^0.3.30", features = ["sink"] } gix = { version = "0.64.0", default-features = false } diff --git a/server/daemon/src/main.rs b/server/daemon/src/main.rs index 8f00daecd..c3b40faa0 100644 --- a/server/daemon/src/main.rs +++ b/server/daemon/src/main.rs @@ -465,13 +465,13 @@ async fn start_daemon(opt: KanidmdParser, config: Configuration) -> ExitCode { return ExitCode::FAILURE; } - match &opt.commands { + let lock_was_setup = match &opt.commands { // we aren't going to touch the DB so we can carry on KanidmdOpt::ShowReplicationCertificate { .. } | KanidmdOpt::RenewReplicationCertificate { .. } | KanidmdOpt::RefreshReplicationConsumer { .. } | KanidmdOpt::RecoverAccount { .. } - | KanidmdOpt::HealthCheck(_) => (), + | KanidmdOpt::HealthCheck(_) => None, _ => { // Okay - Lets now create our lock and go. #[allow(clippy::expect_used)] @@ -482,24 +482,53 @@ async fn start_daemon(opt: KanidmdParser, config: Configuration) -> ExitCode { let flock = match File::create(&klock_path) { Ok(flock) => flock, - Err(e) => { - error!("ERROR: Refusing to start - unable to create kanidmd exclusive lock at {} - {:?}", klock_path.display(), e); + Err(err) => { + error!( + "ERROR: Refusing to start - unable to create kanidmd exclusive lock at {}", + klock_path.display() + ); + error!(?err); return ExitCode::FAILURE; } }; match flock.try_lock_exclusive() { - Ok(()) => debug!("Acquired kanidm exclusive lock"), - Err(e) => { - error!("ERROR: Refusing to start - unable to lock kanidmd exclusive lock at {} - {:?}", klock_path.display(), e); + Ok(true) => debug!("Acquired kanidm exclusive lock"), + Ok(false) => { + error!( + "ERROR: Refusing to start - unable to lock kanidmd exclusive lock at {}", + klock_path.display() + ); error!("Is another kanidmd process running?"); return ExitCode::FAILURE; } + Err(err) => { + error!( + "ERROR: Refusing to start - unable to lock kanidmd exclusive lock at {}", + klock_path.display() + ); + error!(?err); + return ExitCode::FAILURE; + } }; + + Some(klock_path) + } + }; + + let result_code = kanidm_main(config, opt).await; + + if let Some(klock_path) = lock_was_setup { + if let Err(reason) = std::fs::remove_file(&klock_path) { + warn!( + ?reason, + "WARNING: Unable to clean up kanidmd exclusive lock at {}", + klock_path.display() + ); } } - kanidm_main(config, opt).await + result_code } fn main() -> ExitCode { From d025e8fff045e7445f2a09755b82965d7e0a8858 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 09:39:19 +1000 Subject: [PATCH 05/10] Bump tokio from 1.44.1 to 1.44.2 in the cargo group (#3549) Bumps the cargo group with 1 update: [tokio](https://github.com/tokio-rs/tokio). Updates `tokio` from 1.44.1 to 1.44.2 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.44.1...tokio-1.44.2) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.44.2 dependency-type: direct:production dependency-group: cargo ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41de134b4..0d89d50a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5658,9 +5658,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", diff --git a/Cargo.toml b/Cargo.toml index cd104992b..2503267d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -268,7 +268,7 @@ tempfile = "3.15.0" testkit-macros = { path = "./server/testkit-macros" } time = { version = "^0.3.36", features = ["formatting", "local-offset"] } -tokio = "^1.43.0" +tokio = "^1.44.2" tokio-openssl = "^0.6.5" tokio-util = "^0.7.13" From b113262357e7c4bdadcc6fc48c5cc8e672001b5e Mon Sep 17 00:00:00 2001 From: Firstyear <william@blackhats.net.au> Date: Wed, 9 Apr 2025 14:49:06 +1000 Subject: [PATCH 06/10] Improve token handling (#3553) It was possible that a token could be updated in a way that caused existing cached information to be lost if an event was delayed in it's write to the user token. To prevent this, the writes to user tokens now require the HsmLock to be held, and refresh the token just ahead of writing to ensure that these data can't be lost. The benefit to this approach is that readers remain unblocked by a writer. --- .../resolver/src/idprovider/interface.rs | 7 +- .../resolver/src/idprovider/kanidm.rs | 46 +++++++--- unix_integration/resolver/src/resolver.rs | 89 ++++++++++++++----- 3 files changed, 107 insertions(+), 35 deletions(-) diff --git a/unix_integration/resolver/src/idprovider/interface.rs b/unix_integration/resolver/src/idprovider/interface.rs index 808386332..bc7edec86 100644 --- a/unix_integration/resolver/src/idprovider/interface.rs +++ b/unix_integration/resolver/src/idprovider/interface.rs @@ -194,7 +194,8 @@ impl Into<PamAuthResponse> for AuthRequest { } pub enum AuthResult { - Success { token: UserToken }, + Success, + SuccessUpdate { new_token: UserToken }, Denied, Next(AuthRequest), } @@ -251,6 +252,7 @@ pub trait IdProvider { async fn unix_user_online_auth_step( &self, _account_id: &str, + _current_token: Option<&UserToken>, _cred_handler: &mut AuthCredHandler, _pam_next_req: PamAuthRequest, _tpm: &mut tpm::BoxedDynTpm, @@ -290,7 +292,8 @@ pub trait IdProvider { // TPM key. async fn unix_user_offline_auth_step( &self, - _token: &UserToken, + _current_token: Option<&UserToken>, + _session_token: &UserToken, _cred_handler: &mut AuthCredHandler, _pam_next_req: PamAuthRequest, _tpm: &mut tpm::BoxedDynTpm, diff --git a/unix_integration/resolver/src/idprovider/kanidm.rs b/unix_integration/resolver/src/idprovider/kanidm.rs index 9665cd48b..815c5113b 100644 --- a/unix_integration/resolver/src/idprovider/kanidm.rs +++ b/unix_integration/resolver/src/idprovider/kanidm.rs @@ -55,8 +55,6 @@ impl KanidmProvider { tpm: &mut tpm::BoxedDynTpm, machine_key: &tpm::MachineKey, ) -> Result<Self, IdpError> { - // FUTURE: Randomised jitter on next check at startup. - // Initially retrieve our HMAC key. let loadable_hmac_key: Option<tpm::LoadableHmacKey> = keystore .get_tagged_hsm_key(KANIDM_HMAC_KEY) @@ -248,13 +246,25 @@ impl KanidmProviderInternal { // Proceed CacheState::Online => true, CacheState::OfflineNextCheck(at_time) if now >= at_time => { - // Attempt online. If fails, return token. self.attempt_online(tpm, now).await } CacheState::OfflineNextCheck(_) | CacheState::Offline => false, } } + #[instrument(level = "debug", skip_all)] + async fn check_online_right_meow( + &mut self, + tpm: &mut tpm::BoxedDynTpm, + now: SystemTime, + ) -> bool { + match self.state { + CacheState::Online => true, + CacheState::OfflineNextCheck(_) => self.attempt_online(tpm, now).await, + CacheState::Offline => false, + } + } + #[instrument(level = "debug", skip_all)] async fn attempt_online(&mut self, _tpm: &mut tpm::BoxedDynTpm, now: SystemTime) -> bool { let mut max_attempts = 3; @@ -295,7 +305,7 @@ impl IdProvider for KanidmProvider { async fn attempt_online(&self, tpm: &mut tpm::BoxedDynTpm, now: SystemTime) -> bool { let mut inner = self.inner.lock().await; - inner.check_online(tpm, now).await + inner.check_online_right_meow(tpm, now).await } async fn mark_next_check(&self, now: SystemTime) { @@ -431,6 +441,7 @@ impl IdProvider for KanidmProvider { async fn unix_user_online_auth_step( &self, account_id: &str, + current_token: Option<&UserToken>, cred_handler: &mut AuthCredHandler, pam_next_req: PamAuthRequest, tpm: &mut tpm::BoxedDynTpm, @@ -449,15 +460,23 @@ impl IdProvider for KanidmProvider { match auth_result { Ok(Some(n_tok)) => { - let mut token = UserToken::from(n_tok); - token.kanidm_update_cached_password( + let mut new_token = UserToken::from(n_tok); + + // Update any keys that may have been in the db in the current + // token. + if let Some(previous_token) = current_token { + new_token.extra_keys = previous_token.extra_keys.clone(); + } + + // Set any new keys that are relevant from this authentication + new_token.kanidm_update_cached_password( &inner.crypto_policy, cred.as_str(), tpm, &inner.hmac_key, ); - Ok(AuthResult::Success { token }) + Ok(AuthResult::SuccessUpdate { new_token }) } Ok(None) => { // TODO: i'm not a huge fan of this rn, but currently the way we handle @@ -552,7 +571,8 @@ impl IdProvider for KanidmProvider { async fn unix_user_offline_auth_step( &self, - token: &UserToken, + current_token: Option<&UserToken>, + session_token: &UserToken, cred_handler: &mut AuthCredHandler, pam_next_req: PamAuthRequest, tpm: &mut tpm::BoxedDynTpm, @@ -561,11 +581,13 @@ impl IdProvider for KanidmProvider { (AuthCredHandler::Password, PamAuthRequest::Password { cred }) => { let inner = self.inner.lock().await; - if token.kanidm_check_cached_password(cred.as_str(), tpm, &inner.hmac_key) { + if session_token.kanidm_check_cached_password(cred.as_str(), tpm, &inner.hmac_key) { + // Ensure we have either the latest token, or if none, at least the session token. + let new_token = current_token.unwrap_or(session_token).clone(); + // TODO: We can update the token here and then do lockouts. - Ok(AuthResult::Success { - token: token.clone(), - }) + + Ok(AuthResult::SuccessUpdate { new_token }) } else { Ok(AuthResult::Denied) } diff --git a/unix_integration/resolver/src/resolver.rs b/unix_integration/resolver/src/resolver.rs index a824fd9d1..6b20c1038 100644 --- a/unix_integration/resolver/src/resolver.rs +++ b/unix_integration/resolver/src/resolver.rs @@ -47,7 +47,6 @@ pub enum AuthSession { client: Arc<dyn IdProvider + Sync + Send>, account_id: String, id: Id, - token: Option<Box<UserToken>>, cred_handler: AuthCredHandler, /// Some authentication operations may need to spawn background tasks. These tasks need /// to know when to stop as the caller has disconnected. This receiver allows that, so @@ -59,7 +58,7 @@ pub enum AuthSession { account_id: String, id: Id, client: Arc<dyn IdProvider + Sync + Send>, - token: Box<UserToken>, + session_token: Box<UserToken>, cred_handler: AuthCredHandler, }, System { @@ -225,7 +224,7 @@ impl Resolver { // Attempt to search these in the db. let mut dbtxn = self.db.write().await; let r = dbtxn.get_account(account_id).map_err(|err| { - debug!("get_cached_usertoken {:?}", err); + debug!(?err, "get_cached_usertoken"); })?; drop(dbtxn); @@ -318,7 +317,12 @@ impl Resolver { } } - async fn set_cache_usertoken(&self, token: &mut UserToken) -> Result<(), ()> { + async fn set_cache_usertoken( + &self, + token: &mut UserToken, + // This is just for proof that only one write can occur at a time. + _tpm: &mut BoxedDynTpm, + ) -> Result<(), ()> { // Set an expiry let ex_time = SystemTime::now() + Duration::from_secs(self.timeout_seconds); let offset = ex_time @@ -451,6 +455,22 @@ impl Resolver { let mut hsm_lock = self.hsm.lock().await; + // We need to re-acquire the token now behind the hsmlock - this is so that + // we know that as we write the updated token, we know that no one else has + // written to this token, since we are now the only task that is allowed + // to be in a write phase. + let token = if token.is_some() { + self.get_cached_usertoken(account_id) + .await + .map(|(_expired, option_token)| option_token) + .map_err(|err| { + debug!(?err, "get_usertoken error"); + })? + } else { + // Was already none, leave it that way. + None + }; + let user_get_result = if let Some(tok) = token.as_ref() { // Re-use the provider that the token is from. match self.client_ids.get(&tok.provider) { @@ -486,12 +506,11 @@ impl Resolver { } }; - drop(hsm_lock); - match user_get_result { Ok(UserTokenState::Update(mut n_tok)) => { // We have the token! - self.set_cache_usertoken(&mut n_tok).await?; + self.set_cache_usertoken(&mut n_tok, hsm_lock.deref_mut()) + .await?; Ok(Some(n_tok)) } Ok(UserTokenState::NotFound) => { @@ -958,7 +977,6 @@ impl Resolver { client, account_id: account_id.to_string(), id, - token: Some(Box::new(token)), cred_handler, shutdown_rx, }; @@ -979,7 +997,7 @@ impl Resolver { account_id: account_id.to_string(), id, client, - token: Box::new(token), + session_token: Box::new(token), cred_handler, }; Ok((auth_session, next_req.into())) @@ -1022,7 +1040,6 @@ impl Resolver { client: client.clone(), account_id: account_id.to_string(), id, - token: None, cred_handler, shutdown_rx, }; @@ -1050,19 +1067,32 @@ impl Resolver { auth_session: &mut AuthSession, pam_next_req: PamAuthRequest, ) -> Result<PamAuthResponse, ()> { + let mut hsm_lock = self.hsm.lock().await; + let maybe_err = match &mut *auth_session { &mut AuthSession::Online { ref client, ref account_id, - id: _, - token: _, + ref id, ref mut cred_handler, ref shutdown_rx, } => { - let mut hsm_lock = self.hsm.lock().await; + // This is not used in the authentication, but is so that any new + // extra keys or data on the token are updated correctly if the authentication + // requests an update. Since we hold the hsm_lock, no other task can + // update this token between now and completion of the fn. + let current_token = self + .get_cached_usertoken(id) + .await + .map(|(_expired, option_token)| option_token) + .map_err(|err| { + debug!(?err, "get_usertoken error"); + })?; + let result = client .unix_user_online_auth_step( account_id, + current_token.as_ref(), cred_handler, pam_next_req, hsm_lock.deref_mut(), @@ -1071,7 +1101,7 @@ impl Resolver { .await; match result { - Ok(AuthResult::Success { .. }) => { + Ok(AuthResult::SuccessUpdate { .. } | AuthResult::Success) => { info!(?account_id, "Authentication Success"); } Ok(AuthResult::Denied) => { @@ -1087,17 +1117,29 @@ impl Resolver { } &mut AuthSession::Offline { ref account_id, - id: _, + ref id, ref client, - ref token, + ref session_token, ref mut cred_handler, } => { + // This is not used in the authentication, but is so that any new + // extra keys or data on the token are updated correctly if the authentication + // requests an update. Since we hold the hsm_lock, no other task can + // update this token between now and completion of the fn. + let current_token = self + .get_cached_usertoken(id) + .await + .map(|(_expired, option_token)| option_token) + .map_err(|err| { + debug!(?err, "get_usertoken error"); + })?; + // We are offline, continue. Remember, authsession should have // *everything you need* to proceed here! - let mut hsm_lock = self.hsm.lock().await; let result = client .unix_user_offline_auth_step( - token, + current_token.as_ref(), + session_token, cred_handler, pam_next_req, hsm_lock.deref_mut(), @@ -1105,7 +1147,7 @@ impl Resolver { .await; match result { - Ok(AuthResult::Success { .. }) => { + Ok(AuthResult::SuccessUpdate { .. } | AuthResult::Success) => { info!(?account_id, "Authentication Success"); } Ok(AuthResult::Denied) => { @@ -1156,8 +1198,13 @@ impl Resolver { match maybe_err { // What did the provider direct us to do next? - Ok(AuthResult::Success { mut token }) => { - self.set_cache_usertoken(&mut token).await?; + Ok(AuthResult::Success) => { + *auth_session = AuthSession::Success; + Ok(PamAuthResponse::Success) + } + Ok(AuthResult::SuccessUpdate { mut new_token }) => { + self.set_cache_usertoken(&mut new_token, hsm_lock.deref_mut()) + .await?; *auth_session = AuthSession::Success; Ok(PamAuthResponse::Success) From d0cfc69a09fc95d6a2f06b872fc5ffc4f70df713 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 10:12:31 +1000 Subject: [PATCH 07/10] Bump crossbeam-channel from 0.5.14 to 0.5.15 in the cargo group (#3560) Bumps the cargo group with 1 update: [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam). Updates `crossbeam-channel` from 0.5.14 to 0.5.15 - [Release notes](https://github.com/crossbeam-rs/crossbeam/releases) - [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md) - [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.14...crossbeam-channel-0.5.15) --- updated-dependencies: - dependency-name: crossbeam-channel dependency-version: 0.5.15 dependency-type: indirect dependency-group: cargo ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d89d50a6..511524075 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -953,9 +953,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] From 9b7c542b0abf6e5d21305f191c23a60c0269f16d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 10:24:43 +1000 Subject: [PATCH 08/10] Bump the all group in /pykanidm with 2 updates (#3564) Bumps the all group in /pykanidm with 2 updates: [pydantic](https://github.com/pydantic/pydantic) and [ruff](https://github.com/astral-sh/ruff). Updates `pydantic` from 2.11.2 to 2.11.3 - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md) - [Commits](https://github.com/pydantic/pydantic/compare/v2.11.2...v2.11.3) Updates `ruff` from 0.11.4 to 0.11.5 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.11.4...0.11.5) --- updated-dependencies: - dependency-name: pydantic dependency-version: 2.11.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: ruff dependency-version: 0.11.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pykanidm/poetry.lock | 46 ++++++++++++++++++++--------------------- pykanidm/pyproject.toml | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/pykanidm/poetry.lock b/pykanidm/poetry.lock index 4c9d703ec..6a7d5104d 100644 --- a/pykanidm/poetry.lock +++ b/pykanidm/poetry.lock @@ -1529,14 +1529,14 @@ files = [ [[package]] name = "pydantic" -version = "2.11.2" +version = "2.11.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "pydantic-2.11.2-py3-none-any.whl", hash = "sha256:7f17d25846bcdf89b670a86cdfe7b29a9f1c9ca23dee154221c9aa81845cfca7"}, - {file = "pydantic-2.11.2.tar.gz", hash = "sha256:2138628e050bd7a1e70b91d4bf4a91167f4ad76fdb83209b107c8d84b854917e"}, + {file = "pydantic-2.11.3-py3-none-any.whl", hash = "sha256:a082753436a07f9ba1289c6ffa01cd93db3548776088aa917cc43b63f68fa60f"}, + {file = "pydantic-2.11.3.tar.gz", hash = "sha256:7471657138c16adad9322fe3070c0116dd6c3ad8d649300e3cbdfe91f4db4ec3"}, ] [package.dependencies] @@ -2083,30 +2083,30 @@ files = [ [[package]] name = "ruff" -version = "0.11.4" +version = "0.11.5" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.11.4-py3-none-linux_armv6l.whl", hash = "sha256:d9f4a761ecbde448a2d3e12fb398647c7f0bf526dbc354a643ec505965824ed2"}, - {file = "ruff-0.11.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8c1747d903447d45ca3d40c794d1a56458c51e5cc1bc77b7b64bd2cf0b1626cc"}, - {file = "ruff-0.11.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:51a6494209cacca79e121e9b244dc30d3414dac8cc5afb93f852173a2ecfc906"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f171605f65f4fc49c87f41b456e882cd0c89e4ac9d58e149a2b07930e1d466f"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebf99ea9af918878e6ce42098981fc8c1db3850fef2f1ada69fb1dcdb0f8e79e"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edad2eac42279df12e176564a23fc6f4aaeeb09abba840627780b1bb11a9d223"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f103a848be9ff379fc19b5d656c1f911d0a0b4e3e0424f9532ececf319a4296e"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:193e6fac6eb60cc97b9f728e953c21cc38a20077ed64f912e9d62b97487f3f2d"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7af4e5f69b7c138be8dcffa5b4a061bf6ba6a3301f632a6bce25d45daff9bc99"}, - {file = "ruff-0.11.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126b1bf13154aa18ae2d6c3c5efe144ec14b97c60844cfa6eb960c2a05188222"}, - {file = "ruff-0.11.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8806daaf9dfa881a0ed603f8a0e364e4f11b6ed461b56cae2b1c0cab0645304"}, - {file = "ruff-0.11.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5d94bb1cc2fc94a769b0eb975344f1b1f3d294da1da9ddbb5a77665feb3a3019"}, - {file = "ruff-0.11.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:995071203d0fe2183fc7a268766fd7603afb9996785f086b0d76edee8755c896"}, - {file = "ruff-0.11.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a37ca937e307ea18156e775a6ac6e02f34b99e8c23fe63c1996185a4efe0751"}, - {file = "ruff-0.11.4-py3-none-win32.whl", hash = "sha256:0e9365a7dff9b93af933dab8aebce53b72d8f815e131796268709890b4a83270"}, - {file = "ruff-0.11.4-py3-none-win_amd64.whl", hash = "sha256:5a9fa1c69c7815e39fcfb3646bbfd7f528fa8e2d4bebdcf4c2bd0fa037a255fb"}, - {file = "ruff-0.11.4-py3-none-win_arm64.whl", hash = "sha256:d435db6b9b93d02934cf61ef332e66af82da6d8c69aefdea5994c89997c7a0fc"}, - {file = "ruff-0.11.4.tar.gz", hash = "sha256:f45bd2fb1a56a5a85fae3b95add03fb185a0b30cf47f5edc92aa0355ca1d7407"}, + {file = "ruff-0.11.5-py3-none-linux_armv6l.whl", hash = "sha256:2561294e108eb648e50f210671cc56aee590fb6167b594144401532138c66c7b"}, + {file = "ruff-0.11.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac12884b9e005c12d0bd121f56ccf8033e1614f736f766c118ad60780882a077"}, + {file = "ruff-0.11.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4bfd80a6ec559a5eeb96c33f832418bf0fb96752de0539905cf7b0cc1d31d779"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0947c0a1afa75dcb5db4b34b070ec2bccee869d40e6cc8ab25aca11a7d527794"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad871ff74b5ec9caa66cb725b85d4ef89b53f8170f47c3406e32ef040400b038"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6cf918390cfe46d240732d4d72fa6e18e528ca1f60e318a10835cf2fa3dc19f"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56145ee1478582f61c08f21076dc59153310d606ad663acc00ea3ab5b2125f82"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5f66f8f1e8c9fc594cbd66fbc5f246a8d91f916cb9667e80208663ec3728304"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80b4df4d335a80315ab9afc81ed1cff62be112bd165e162b5eed8ac55bfc8470"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3068befab73620b8a0cc2431bd46b3cd619bc17d6f7695a3e1bb166b652c382a"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5da2e710a9641828e09aa98b92c9ebbc60518fdf3921241326ca3e8f8e55b8b"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ef39f19cb8ec98cbc762344921e216f3857a06c47412030374fffd413fb8fd3a"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b2a7cedf47244f431fd11aa5a7e2806dda2e0c365873bda7834e8f7d785ae159"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:81be52e7519f3d1a0beadcf8e974715b2dfc808ae8ec729ecfc79bddf8dbb783"}, + {file = "ruff-0.11.5-py3-none-win32.whl", hash = "sha256:e268da7b40f56e3eca571508a7e567e794f9bfcc0f412c4b607931d3af9c4afe"}, + {file = "ruff-0.11.5-py3-none-win_amd64.whl", hash = "sha256:6c6dc38af3cfe2863213ea25b6dc616d679205732dc0fb673356c2d69608f800"}, + {file = "ruff-0.11.5-py3-none-win_arm64.whl", hash = "sha256:67e241b4314f4eacf14a601d586026a962f4002a475aa702c69980a38087aa4e"}, + {file = "ruff-0.11.5.tar.gz", hash = "sha256:cae2e2439cb88853e421901ec040a758960b576126dab520fa08e9de431d1bef"}, ] [[package]] @@ -2406,4 +2406,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.9" -content-hash = "e9b71c7a85a236b7962a6d6d9fc5b0fd15c9a36a3fbeeab7736fe4a8c060d496" +content-hash = "5bff20b92931b8e7af661259f31365c4726b29b0edb315e0de872a04d6546fd9" diff --git a/pykanidm/pyproject.toml b/pykanidm/pyproject.toml index 61ec43a9b..13ee9b021 100644 --- a/pykanidm/pyproject.toml +++ b/pykanidm/pyproject.toml @@ -29,7 +29,7 @@ Authlib = "^1.2.0" [tool.poetry.group.dev.dependencies] -ruff = ">=0.5.1,<0.11.5" +ruff = ">=0.5.1,<0.11.6" pytest = "^8.3.4" mypy = "^1.14.1" types-requests = "^2.32.0.20241016" From 8424863969a894fb5674873c7a6f413bce6f0d47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:16:09 +1000 Subject: [PATCH 09/10] Bump the all group in /pykanidm with 3 updates (#3572) --- updated-dependencies: - dependency-name: aiohttp dependency-version: 3.11.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: ruff dependency-version: 0.11.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all - dependency-name: mkdocs-material dependency-version: 9.6.12 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pykanidm/poetry.lock | 210 ++++++++++++++++++++-------------------- pykanidm/pyproject.toml | 2 +- 2 files changed, 106 insertions(+), 106 deletions(-) diff --git a/pykanidm/poetry.lock b/pykanidm/poetry.lock index 6a7d5104d..d4146417b 100644 --- a/pykanidm/poetry.lock +++ b/pykanidm/poetry.lock @@ -14,93 +14,93 @@ files = [ [[package]] name = "aiohttp" -version = "3.11.16" +version = "3.11.17" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "aiohttp-3.11.16-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa"}, - {file = "aiohttp-3.11.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955"}, - {file = "aiohttp-3.11.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3"}, - {file = "aiohttp-3.11.16-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287"}, - {file = "aiohttp-3.11.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8"}, - {file = "aiohttp-3.11.16-cp310-cp310-win32.whl", hash = "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814"}, - {file = "aiohttp-3.11.16-cp310-cp310-win_amd64.whl", hash = "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534"}, - {file = "aiohttp-3.11.16-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180"}, - {file = "aiohttp-3.11.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed"}, - {file = "aiohttp-3.11.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98"}, - {file = "aiohttp-3.11.16-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049"}, - {file = "aiohttp-3.11.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17"}, - {file = "aiohttp-3.11.16-cp311-cp311-win32.whl", hash = "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86"}, - {file = "aiohttp-3.11.16-cp311-cp311-win_amd64.whl", hash = "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24"}, - {file = "aiohttp-3.11.16-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27"}, - {file = "aiohttp-3.11.16-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713"}, - {file = "aiohttp-3.11.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce"}, - {file = "aiohttp-3.11.16-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c"}, - {file = "aiohttp-3.11.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71"}, - {file = "aiohttp-3.11.16-cp312-cp312-win32.whl", hash = "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2"}, - {file = "aiohttp-3.11.16-cp312-cp312-win_amd64.whl", hash = "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682"}, - {file = "aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489"}, - {file = "aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50"}, - {file = "aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb"}, - {file = "aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34"}, - {file = "aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913"}, - {file = "aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979"}, - {file = "aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802"}, - {file = "aiohttp-3.11.16-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bbcba75fe879ad6fd2e0d6a8d937f34a571f116a0e4db37df8079e738ea95c71"}, - {file = "aiohttp-3.11.16-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:87a6e922b2b2401e0b0cf6b976b97f11ec7f136bfed445e16384fbf6fd5e8602"}, - {file = "aiohttp-3.11.16-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccf10f16ab498d20e28bc2b5c1306e9c1512f2840f7b6a67000a517a4b37d5ee"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb3d0cc5cdb926090748ea60172fa8a213cec728bd6c54eae18b96040fcd6227"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d07502cc14ecd64f52b2a74ebbc106893d9a9717120057ea9ea1fd6568a747e7"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:776c8e959a01e5e8321f1dec77964cb6101020a69d5a94cd3d34db6d555e01f7"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0902e887b0e1d50424112f200eb9ae3dfed6c0d0a19fc60f633ae5a57c809656"}, - {file = "aiohttp-3.11.16-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e87fd812899aa78252866ae03a048e77bd11b80fb4878ce27c23cade239b42b2"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0a950c2eb8ff17361abd8c85987fd6076d9f47d040ebffce67dce4993285e973"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:c10d85e81d0b9ef87970ecbdbfaeec14a361a7fa947118817fcea8e45335fa46"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7951decace76a9271a1ef181b04aa77d3cc309a02a51d73826039003210bdc86"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14461157d8426bcb40bd94deb0450a6fa16f05129f7da546090cebf8f3123b0f"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9756d9b9d4547e091f99d554fbba0d2a920aab98caa82a8fb3d3d9bee3c9ae85"}, - {file = "aiohttp-3.11.16-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:87944bd16b7fe6160607f6a17808abd25f17f61ae1e26c47a491b970fb66d8cb"}, - {file = "aiohttp-3.11.16-cp39-cp39-win32.whl", hash = "sha256:92b7ee222e2b903e0a4b329a9943d432b3767f2d5029dbe4ca59fb75223bbe2e"}, - {file = "aiohttp-3.11.16-cp39-cp39-win_amd64.whl", hash = "sha256:17ae4664031aadfbcb34fd40ffd90976671fa0c0286e6c4113989f78bebab37a"}, - {file = "aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8"}, + {file = "aiohttp-3.11.17-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:67eaabe31454d68503ddc10d805944187787b4351600aedda1724f75f3f20b6c"}, + {file = "aiohttp-3.11.17-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c73371bb91660eb7971336883eb05ebf3e912a0a183f5029fe6200285dd858e"}, + {file = "aiohttp-3.11.17-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:78568d883e7cabf31f110a87bb02cee70e32bbb419eed974027c26ac6be18add"}, + {file = "aiohttp-3.11.17-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d5f480d3e35a139f0bd31d9037047cc18d6f362d1b06243b694a40f1a658ba8"}, + {file = "aiohttp-3.11.17-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:562b47fa14712e47ae7b6cf31998a4c888c35a904845e27f5ec2fc51401304e7"}, + {file = "aiohttp-3.11.17-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3875dd6571d2709697835cf5e4e7e0e1bf1d6e3aeec21b7766bbd50d9a97b8a3"}, + {file = "aiohttp-3.11.17-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d9130c4380bb02a308c79a25d9b82e642e21bea5ad453553f35f2d490ac47bd"}, + {file = "aiohttp-3.11.17-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71ee4844e4680e69d2acb462073b147a4c2dd6813c30c61979399feddc63b322"}, + {file = "aiohttp-3.11.17-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e40eceff6ca85d68d07ebd1533f13727261d17b4bef7a518a6882b8448c83106"}, + {file = "aiohttp-3.11.17-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:fd89c4399ca67c0d2939211ecf8415747f4e2d855580f1efd9598eff433499ac"}, + {file = "aiohttp-3.11.17-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b62134921162627482056379740998c54d51412a7e678a4d84a5510d6f634a7"}, + {file = "aiohttp-3.11.17-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3e27e266396db6d6eee76769f66b356020b22e7ae8d7d4d47c9ced6bc53c62a0"}, + {file = "aiohttp-3.11.17-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0e93c46b7cc7476130bd396d63eafc6c458e74eddd1a1c65a2ac8e4bdb4cf1d1"}, + {file = "aiohttp-3.11.17-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7903749414023ad7d0a46cd4816d9ac99be7552635a0b3deae0b2c9a51d0cfa6"}, + {file = "aiohttp-3.11.17-cp310-cp310-win32.whl", hash = "sha256:de96c4aba1506b225cf1ab750fdd60e1f8d9d23add6431150a43fbef0542fe18"}, + {file = "aiohttp-3.11.17-cp310-cp310-win_amd64.whl", hash = "sha256:c08753a2c4d6f9175b234fd1ee227fc68a3c95ee09d52447af25b1ecb99d5886"}, + {file = "aiohttp-3.11.17-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9c10ede918e0d1edf9ef75cedb9ab303e509d0616020ecea42c427e3694a4d63"}, + {file = "aiohttp-3.11.17-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:127696d62e66badc3b554832343df031fd0012f080002d9074cfb735ce9c677e"}, + {file = "aiohttp-3.11.17-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26ac39d318507a7fb79b4eee31d7f92a7198d22c0d26d2c2dee4c945172ee509"}, + {file = "aiohttp-3.11.17-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8e28f9b3b15ab1d840a7ffe0d7b63ee8bb01ef68c611f2ddbd5f96fa5f0e53"}, + {file = "aiohttp-3.11.17-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01e9d930cea36405ccdcde45921a29c7e22e0b581fc570f630d72a5bcac56c8c"}, + {file = "aiohttp-3.11.17-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dad404c74f4aad90b181db75d79338e87c852e638460003c78bdfd92c07fff3b"}, + {file = "aiohttp-3.11.17-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf30c77f5ddb1ccf568881f9076d0840f0b9a9c94dabe03126474768f951a48a"}, + {file = "aiohttp-3.11.17-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1987db5cb7e2c21693047f8f3c07df7bed3cb13403e5df5f684fe6a8478eff85"}, + {file = "aiohttp-3.11.17-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:612a5bc4e56a52986e89f1439fca86b765682613fdebc71c01de46736b33bd34"}, + {file = "aiohttp-3.11.17-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:398a021a7207a04960a8165f53f59e0c0b7cd54fe69ab7f0895f105e391a7964"}, + {file = "aiohttp-3.11.17-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e70a3672c734e6d792903e7b22d2f514ed8cbfa27c4a8e9171191da5c7d3c3b1"}, + {file = "aiohttp-3.11.17-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b51c9b38d904957ff2df58bf72874634d674b228c03f5d48e143996a8da5c819"}, + {file = "aiohttp-3.11.17-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a689fca65127d7599cfb0123c7dccb32d7eebe009d20bfa69ce93aff143dbbc1"}, + {file = "aiohttp-3.11.17-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23120ea57904cfd920791afe5a780151cd8e99b039c35c38bb8a0d3e35af049b"}, + {file = "aiohttp-3.11.17-cp311-cp311-win32.whl", hash = "sha256:07e2c1c06c15cb95721670a69f3cbb1dae22b0914de6e362dba2228b6dd675e7"}, + {file = "aiohttp-3.11.17-cp311-cp311-win_amd64.whl", hash = "sha256:5e245caba8842f176ecc8ae1fde1ef0c89669614cb379c32e069cd0b96b3547f"}, + {file = "aiohttp-3.11.17-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:03ee8b587cc7bd345552235cd7117097c169f3a531a7239dc9a3c6b6db1cf46a"}, + {file = "aiohttp-3.11.17-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2bd255da118f96446567d9870621a07b8f36b1130826b07f2910ef1aeb4a85c0"}, + {file = "aiohttp-3.11.17-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2620d1cbeb688094045f06000b5b6127df2eb768cae07d95137b0e998cd6ce04"}, + {file = "aiohttp-3.11.17-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eac3842f3258c77d35bfe93356fedbc6e5e943fd056534be71b694289b36973"}, + {file = "aiohttp-3.11.17-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:626dffeeeee34f2b5a327df05d6cb48ecfabcb141d56590d3c779accedc62d88"}, + {file = "aiohttp-3.11.17-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aded01d2bda55b2f62a361a2d55f8c9c04436eff6220e579ca7fb72cfe68b48a"}, + {file = "aiohttp-3.11.17-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b830715cb818efc4fbd7b9631661e3498b068f23680982d7586103333b0d4df"}, + {file = "aiohttp-3.11.17-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ac7ac3d0a7ab5ce1076c788640274f594397603381747b3d4142beec004c44a"}, + {file = "aiohttp-3.11.17-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9dba68088ecdd16b306513463f7e295699bc52bb09573d2bc3ff3d0e7bdc34ff"}, + {file = "aiohttp-3.11.17-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:80ba863e1e1055577f27a484b0f002b31297432016262d5f9d2dab5c6d21c5ad"}, + {file = "aiohttp-3.11.17-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:003c955924fa7d1b100599ce4f5da3ce68bd151b81b5a8c18369ba585766ed31"}, + {file = "aiohttp-3.11.17-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e615b94364f7ea0dc95922c351e106ffb2eded09ffd7a7102ab2e202d17bdaa"}, + {file = "aiohttp-3.11.17-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:05eb25fa6e5495b3866a3b974fe3b214d5a0b6bb862cd54b7ec4d997948aa12c"}, + {file = "aiohttp-3.11.17-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3a3fb727360af3e94667e243cb21cf5069c0df9a70adcc81751136d53f526bc6"}, + {file = "aiohttp-3.11.17-cp312-cp312-win32.whl", hash = "sha256:93a7cfacf28887ddebd9c697d590002e8d52ac51acb4faf0d00abe1bb791339e"}, + {file = "aiohttp-3.11.17-cp312-cp312-win_amd64.whl", hash = "sha256:c43311c94200a63e31b62e82872c6dd43fe904cbb8f161c830bfe65c17583658"}, + {file = "aiohttp-3.11.17-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:57de66477af1176b3d25058594000eb32d21f82039909ef1bf865fe666c8c0ea"}, + {file = "aiohttp-3.11.17-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0d119d1e6d5bf930b285285aec70d66b7a7efa4914231441c7f606e86ca17e2"}, + {file = "aiohttp-3.11.17-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d0966f0c14be863cb51e0aa56366c45a2331f46a64347b49a0e9c687c72d43c1"}, + {file = "aiohttp-3.11.17-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f24d2b1f2516953b001736f82be7cf5d3234fc90e82a2d9a33ad8cdffb28f4c5"}, + {file = "aiohttp-3.11.17-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3197cd39307747127f7a3489b6aca4286c7613e8509e65f46702831136257d12"}, + {file = "aiohttp-3.11.17-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e4d134b96448c955e3e29e4026ee499441182bfd92f293accfa1cf1525a061b"}, + {file = "aiohttp-3.11.17-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20c68e4411440209fd64abfb27ff5e09e5a59a0fab4dbd07808e762e6fada670"}, + {file = "aiohttp-3.11.17-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1131f61afa4a4800fd5770ab13b1587bf4d07a0a561ee6f30f58c2300675ec3b"}, + {file = "aiohttp-3.11.17-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d3d4a383935ed1e39109e43535230b7e61781348fc2cf52c1006ae663dcbbc73"}, + {file = "aiohttp-3.11.17-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ada2a986cdec0caa51ee787b838441eeece50cd1ea075053fef51e0c995114b4"}, + {file = "aiohttp-3.11.17-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a118aae8008e209f100396bbd2d1d798aaa43651202c65cd2664680dd27aa061"}, + {file = "aiohttp-3.11.17-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2bf50db2e855226363aecb78353593987bf9a0b593434814b4a1f09586a116a4"}, + {file = "aiohttp-3.11.17-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4f1c1db9470c9aa1ab45cee80b4b7db51fa4cfc01abc5e648d991266e676ac90"}, + {file = "aiohttp-3.11.17-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c4a92e2a228829c67f3c633a2329a8b85ed6cfe3b25047f48b4d51e92a655a87"}, + {file = "aiohttp-3.11.17-cp313-cp313-win32.whl", hash = "sha256:8962df1a29794f3204863ea6d93001a3d77cb1c4ee87f8c7683fe3fb6ec27373"}, + {file = "aiohttp-3.11.17-cp313-cp313-win_amd64.whl", hash = "sha256:71a1fd6421056980280fe490f211fe0f0c385271b42fb1440c4abcd891b2133a"}, + {file = "aiohttp-3.11.17-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:be033aceea6a8cd03cc2e2b6936beb485bb6b71907ad5a0e78bb942857b4f468"}, + {file = "aiohttp-3.11.17-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7874d1e620159c18c99b87f37c45a8c30abbba2678d31ae3409d7c00c995f62"}, + {file = "aiohttp-3.11.17-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:919b411fae2376d5b78901949e556bd646e5de16e0631aed5a1b00ad55b5ec40"}, + {file = "aiohttp-3.11.17-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dffeb59c7f3414fd4da384cf76428c59b754e80d4b10d8e5d7018bed135d554d"}, + {file = "aiohttp-3.11.17-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ff5a5c9afbdaff09bf7b4a0655f1084d6c9f562fc33df8c0f7a785480405cf8"}, + {file = "aiohttp-3.11.17-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e4122d386a1695aee05f49a8bb4ff69c0e74b2b9db80a4d8157165327d07103"}, + {file = "aiohttp-3.11.17-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcb753ca25397eac1d38c7112c7b910feabef198d4e411aa5957857795681a25"}, + {file = "aiohttp-3.11.17-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29e0f47656b826d74034b612c11709842c20ebe373e398812208b84ec57f79a"}, + {file = "aiohttp-3.11.17-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:56a5acb7a715a1a1ad8ed424f7cbb2dc2950dc8b20ae2d83c2117ba5751223b1"}, + {file = "aiohttp-3.11.17-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:da0bee7635aa12036269ef8a13fd0fa5549ccfe5eb9ef6c3f0ad7cc574f12e5e"}, + {file = "aiohttp-3.11.17-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:adb504bdf0691101c7c4544e25545df467ea7239097ca6c67d01b27e500037b5"}, + {file = "aiohttp-3.11.17-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2e376d7f3fedb770106c40546d5f76a61e5ba3d4dac42cc60a8062022586cc"}, + {file = "aiohttp-3.11.17-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:79ae28f78f0a4a18a308d61647e3ee9cc1e641cb3ad5531db059eff68f3ee63c"}, + {file = "aiohttp-3.11.17-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ac9f6cdb02e7376060c4243f17a402b8d895747d788426ef3b8799e7a28a4ee0"}, + {file = "aiohttp-3.11.17-cp39-cp39-win32.whl", hash = "sha256:e3bddefb2cae68be01186c89d9a41024ae929aaf9e30b65d8977b719185f7e17"}, + {file = "aiohttp-3.11.17-cp39-cp39-win_amd64.whl", hash = "sha256:8e72767d1798770acdf27a20c523b1cd29973e487f6397b181ef0e7c583acb46"}, + {file = "aiohttp-3.11.17.tar.gz", hash = "sha256:2bf3ff374c3abd7a5c6c8de3ad7ed91e0e89a8b53353314c93766c3add5a208a"}, ] [package.dependencies] @@ -1051,14 +1051,14 @@ pyyaml = ">=5.1" [[package]] name = "mkdocs-material" -version = "9.6.11" +version = "9.6.12" description = "Documentation that simply works" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "mkdocs_material-9.6.11-py3-none-any.whl", hash = "sha256:47f21ef9cbf4f0ebdce78a2ceecaa5d413581a55141e4464902224ebbc0b1263"}, - {file = "mkdocs_material-9.6.11.tar.gz", hash = "sha256:0b7f4a0145c5074cdd692e4362d232fb25ef5b23328d0ec1ab287af77cc0deff"}, + {file = "mkdocs_material-9.6.12-py3-none-any.whl", hash = "sha256:92b4fbdc329e4febc267ca6e2c51e8501fa97b2225c5f4deb4d4e43550f8e61e"}, + {file = "mkdocs_material-9.6.12.tar.gz", hash = "sha256:add6a6337b29f9ea7912cb1efc661de2c369060b040eb5119855d794ea85b473"}, ] [package.dependencies] @@ -2083,30 +2083,30 @@ files = [ [[package]] name = "ruff" -version = "0.11.5" +version = "0.11.6" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.11.5-py3-none-linux_armv6l.whl", hash = "sha256:2561294e108eb648e50f210671cc56aee590fb6167b594144401532138c66c7b"}, - {file = "ruff-0.11.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac12884b9e005c12d0bd121f56ccf8033e1614f736f766c118ad60780882a077"}, - {file = "ruff-0.11.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4bfd80a6ec559a5eeb96c33f832418bf0fb96752de0539905cf7b0cc1d31d779"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0947c0a1afa75dcb5db4b34b070ec2bccee869d40e6cc8ab25aca11a7d527794"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad871ff74b5ec9caa66cb725b85d4ef89b53f8170f47c3406e32ef040400b038"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6cf918390cfe46d240732d4d72fa6e18e528ca1f60e318a10835cf2fa3dc19f"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56145ee1478582f61c08f21076dc59153310d606ad663acc00ea3ab5b2125f82"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5f66f8f1e8c9fc594cbd66fbc5f246a8d91f916cb9667e80208663ec3728304"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80b4df4d335a80315ab9afc81ed1cff62be112bd165e162b5eed8ac55bfc8470"}, - {file = "ruff-0.11.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3068befab73620b8a0cc2431bd46b3cd619bc17d6f7695a3e1bb166b652c382a"}, - {file = "ruff-0.11.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5da2e710a9641828e09aa98b92c9ebbc60518fdf3921241326ca3e8f8e55b8b"}, - {file = "ruff-0.11.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ef39f19cb8ec98cbc762344921e216f3857a06c47412030374fffd413fb8fd3a"}, - {file = "ruff-0.11.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b2a7cedf47244f431fd11aa5a7e2806dda2e0c365873bda7834e8f7d785ae159"}, - {file = "ruff-0.11.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:81be52e7519f3d1a0beadcf8e974715b2dfc808ae8ec729ecfc79bddf8dbb783"}, - {file = "ruff-0.11.5-py3-none-win32.whl", hash = "sha256:e268da7b40f56e3eca571508a7e567e794f9bfcc0f412c4b607931d3af9c4afe"}, - {file = "ruff-0.11.5-py3-none-win_amd64.whl", hash = "sha256:6c6dc38af3cfe2863213ea25b6dc616d679205732dc0fb673356c2d69608f800"}, - {file = "ruff-0.11.5-py3-none-win_arm64.whl", hash = "sha256:67e241b4314f4eacf14a601d586026a962f4002a475aa702c69980a38087aa4e"}, - {file = "ruff-0.11.5.tar.gz", hash = "sha256:cae2e2439cb88853e421901ec040a758960b576126dab520fa08e9de431d1bef"}, + {file = "ruff-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:d84dcbe74cf9356d1bdb4a78cf74fd47c740bf7bdeb7529068f69b08272239a1"}, + {file = "ruff-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9bc583628e1096148011a5d51ff3c836f51899e61112e03e5f2b1573a9b726de"}, + {file = "ruff-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2959049faeb5ba5e3b378709e9d1bf0cab06528b306b9dd6ebd2a312127964a"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c5d4e30d9d0de7fedbfb3e9e20d134b73a30c1e74b596f40f0629d5c28a193"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4b9a4e1439f7d0a091c6763a100cef8fbdc10d68593df6f3cfa5abdd9246e"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5edf270223dd622218256569636dc3e708c2cb989242262fe378609eccf1308"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f55844e818206a9dd31ff27f91385afb538067e2dc0beb05f82c293ab84f7d55"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d8f782286c5ff562e4e00344f954b9320026d8e3fae2ba9e6948443fafd9ffc"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01c63ba219514271cee955cd0adc26a4083df1956d57847978383b0e50ffd7d2"}, + {file = "ruff-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15adac20ef2ca296dd3d8e2bedc6202ea6de81c091a74661c3666e5c4c223ff6"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4dd6b09e98144ad7aec026f5588e493c65057d1b387dd937d7787baa531d9bc2"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:45b2e1d6c0eed89c248d024ea95074d0e09988d8e7b1dad8d3ab9a67017a5b03"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bd40de4115b2ec4850302f1a1d8067f42e70b4990b68838ccb9ccd9f110c5e8b"}, + {file = "ruff-0.11.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:77cda2dfbac1ab73aef5e514c4cbfc4ec1fbef4b84a44c736cc26f61b3814cd9"}, + {file = "ruff-0.11.6-py3-none-win32.whl", hash = "sha256:5151a871554be3036cd6e51d0ec6eef56334d74dfe1702de717a995ee3d5b287"}, + {file = "ruff-0.11.6-py3-none-win_amd64.whl", hash = "sha256:cce85721d09c51f3b782c331b0abd07e9d7d5f775840379c640606d3159cae0e"}, + {file = "ruff-0.11.6-py3-none-win_arm64.whl", hash = "sha256:3567ba0d07fb170b1b48d944715e3294b77f5b7679e8ba258199a250383ccb79"}, + {file = "ruff-0.11.6.tar.gz", hash = "sha256:bec8bcc3ac228a45ccc811e45f7eb61b950dbf4cf31a67fa89352574b01c7d79"}, ] [[package]] @@ -2406,4 +2406,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.9" -content-hash = "5bff20b92931b8e7af661259f31365c4726b29b0edb315e0de872a04d6546fd9" +content-hash = "8d570a489cde6b6fe3eace984e3cba246f6f88bb0daba9739e1a61fd155b9091" diff --git a/pykanidm/pyproject.toml b/pykanidm/pyproject.toml index 13ee9b021..5a621e2e7 100644 --- a/pykanidm/pyproject.toml +++ b/pykanidm/pyproject.toml @@ -29,7 +29,7 @@ Authlib = "^1.2.0" [tool.poetry.group.dev.dependencies] -ruff = ">=0.5.1,<0.11.6" +ruff = ">=0.5.1,<0.11.7" pytest = "^8.3.4" mypy = "^1.14.1" types-requests = "^2.32.0.20241016" From 20433f57121e9e8c4e5a164431bd6ce21f327007 Mon Sep 17 00:00:00 2001 From: Keerthi <159991565+Keerthi421@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:28:45 +0530 Subject: [PATCH 10/10] fix(web): Preserve SSH key content on form validation error (#3574) --- server/core/src/https/views/reset.rs | 4 ++++ .../credential_update_add_ssh_publickey_partial.html | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/server/core/src/https/views/reset.rs b/server/core/src/https/views/reset.rs index 195e042a6..c6450ff3a 100644 --- a/server/core/src/https/views/reset.rs +++ b/server/core/src/https/views/reset.rs @@ -121,6 +121,7 @@ struct SetUnixCredPartial { struct AddSshPublicKeyPartial { title_error: Option<String>, key_error: Option<String>, + key_value: Option<String>, } #[derive(Serialize, Deserialize, Debug)] @@ -902,6 +903,7 @@ pub(crate) async fn view_add_ssh_publickey( return Ok((AddSshPublicKeyPartial { title_error: None, key_error: None, + key_value: None, },) .into_response()); } @@ -920,6 +922,7 @@ pub(crate) async fn view_add_ssh_publickey( return Ok((AddSshPublicKeyPartial { title_error: None, key_error: Some("Key cannot be parsed".to_string()), + key_value: Some(new_key.key), },) .into_response()); } @@ -965,6 +968,7 @@ pub(crate) async fn view_add_ssh_publickey( AddSshPublicKeyPartial { title_error, key_error, + key_value: Some(new_key.key), }, ) .into_response()) diff --git a/server/core/templates/credential_update_add_ssh_publickey_partial.html b/server/core/templates/credential_update_add_ssh_publickey_partial.html index 141e19554..31e7c71a9 100644 --- a/server/core/templates/credential_update_add_ssh_publickey_partial.html +++ b/server/core/templates/credential_update_add_ssh_publickey_partial.html @@ -16,7 +16,7 @@ <textarea class="form-control(% if let Some(_) = key_error %) is-invalid(% endif %)" id="key-content" rows="5" name="key" aria-describedby="key-validation-feedback" placeholder="Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'" - ></textarea> + >(% if let Some(key_value) = key_value %)(( key_value ))(% endif %)</textarea> <div id="key-validation-feedback" class="invalid-feedback"> (% if let Some(key_error) = key_error %)(( key_error ))(% endif %) </div>