From 060cb729a7dee02d6a30049933225ada675a6e53 Mon Sep 17 00:00:00 2001 From: Firstyear Date: Mon, 27 Nov 2023 14:35:59 +1000 Subject: [PATCH] Expose TPM in more interface places (#2334) --- Cargo.lock | 18 +-- Cargo.toml | 4 +- book/src/integrations/pam_and_nsswitch.md | 51 +-------- examples/unixd | 111 ++++++++++++++++++- libs/crypto/src/lib.rs | 34 +++--- platform/opensuse/kanidm-unixd.service | 5 + unix_integration/Cargo.toml | 1 + unix_integration/src/constants.rs | 2 +- unix_integration/src/daemon.rs | 47 ++++++-- unix_integration/src/db.rs | 2 +- unix_integration/src/idprovider/interface.rs | 25 ++++- unix_integration/src/idprovider/kanidm.rs | 14 ++- unix_integration/src/resolver.rs | 52 +++++++-- unix_integration/tests/cache_layer_test.rs | 10 +- 14 files changed, 274 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a89294d6c..15997e50b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1433,18 +1433,18 @@ dependencies = [ [[package]] name = "enum-map" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e6b4f374c071b18172e23134e01026653dc980636ee139e0dfe59c538c61e5" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" dependencies = [ "enum-map-derive", ] [[package]] name = "enum-map-derive" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdb3d73d1beaf47c8593a1364e577fde072677cbfd103600345c0f547408cc0" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", @@ -1857,9 +1857,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gix" @@ -2994,11 +2994,12 @@ dependencies = [ [[package]] name = "kanidm-hsm-crypto" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc2a5dbe42b03b3e5e3f99eab1c5773032c8e508896691b3f4562c7de264d67" +checksum = "d325d5f7a3978ad1451f8bad2fdea1cc70a7b33dcaa8bbff7617a80d4c36c449" dependencies = [ "argon2", + "hex", "openssl", "serde", "tracing", @@ -3175,6 +3176,7 @@ dependencies = [ "bytes", "clap", "clap_complete", + "compact_jwt 0.3.2", "csv", "futures", "hashbrown 0.14.2", diff --git a/Cargo.toml b/Cargo.toml index c89922482..8d1f2b7f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ kanidmd_lib_macros = { path = "./server/lib-macros", version = "1.1.0-rc.15-dev" kanidmd_testkit = { path = "./server/testkit", version = "1.1.0-rc.15-dev" } kanidm_build_profiles = { path = "./libs/profiles", version = "1.1.0-rc.15-dev" } kanidm_client = { path = "./libs/client", version = "1.1.0-rc.15-dev" } -kanidm-hsm-crypto = "^0.1.1" +kanidm-hsm-crypto = "^0.1.3" kanidm_lib_crypto = { path = "./libs/crypto", version = "1.1.0-rc.15-dev" } kanidm_lib_file_permissions = { path = "./libs/file_permissions", version = "1.1.0-rc.15-dev" } kanidm_proto = { path = "./proto", version = "1.1.0-rc.15-dev" } @@ -231,8 +231,6 @@ tracing = { version = "^0.1.40", features = [ tracing-subscriber = { version = "^0.3.18", features = ["env-filter"] } tracing-forest = "^0.1.6" -tss-esapi = "^7.4.0" - url = "^2.4.1" urlencoding = "2.1.3" utoipa = "4.1.0" diff --git a/book/src/integrations/pam_and_nsswitch.md b/book/src/integrations/pam_and_nsswitch.md index 96bb4e2d2..c3e3f0108 100644 --- a/book/src/integrations/pam_and_nsswitch.md +++ b/book/src/integrations/pam_and_nsswitch.md @@ -38,7 +38,7 @@ systemctl status kanidm-unixd-tasks ``` > **NOTE** The `kanidm_unixd_tasks` daemon is not required for PAM and nsswitch functionality. If -> disabled, your system will function as usual. It is, however, recommended due to the features it +> disabled, your system will function as usual. It is however strongly recommended due to the features it > provides supporting Kanidm's capabilities. Both unixd daemons use the connection configuration from /etc/kanidm/config. This is the covered in @@ -47,35 +47,9 @@ Both unixd daemons use the connection configuration from /etc/kanidm/config. Thi You can also configure some unixd-specific options with the file /etc/kanidm/unixd: ```toml -pam_allowed_login_groups = ["posix_group"] -default_shell = "/bin/sh" -home_prefix = "/home/" -home_attr = "uuid" -home_alias = "spn" -use_etc_skel = false -uid_attr_map = "spn" -gid_attr_map = "spn" -selinux = true -allow_local_account_override = ["account_name"] +{{#rustdoc_include ../../examples/unixd}} ``` -`pam_allowed_login_groups` defines a set of POSIX groups where membership of any of these groups -will be allowed to login via PAM. All POSIX users and groups can be resolved by nss regardless of -PAM login status. This may be a group name, spn, or uuid. - -`default_shell` is the default shell for users. Defaults to `/bin/sh`. - -`home_prefix` is the prepended path to where home directories are stored. Must end with a trailing -`/`. Defaults to `/home/`. - -`home_attr` is the default token attribute used for the home directory path. Valid choices are -`uuid`, `name`, `spn`. Defaults to `uuid`. - -`home_alias` is the default token attribute used for generating symlinks pointing to the user's home -directory. If set, this will become the value of the home path to nss calls. It is recommended you -choose a "human friendly" attribute here. Valid choices are `none`, `uuid`, `name`, `spn`. Defaults -to `spn`. - > **NOTICE:** All users in Kanidm can change their name (and their spn) at any time. If you change > `home_attr` from `uuid` you _must_ have a plan on how to manage these directory renames in your > system. We recommend that you have a stable ID (like the UUID), and symlinks from the name to the @@ -85,27 +59,6 @@ to `spn`. > **NOTE:** Ubuntu users please see: > [Why aren't snaps launching with home_alias set?](../frequently_asked_questions.md#why-arent-snaps-launching-with-home_alias-set) -`use_etc_skel` controls if home directories should be prepopulated with the contents of `/etc/skel` -when first created. Defaults to false. - -`uid_attr_map` chooses which attribute is used for domain local users in presentation. Defaults to -`spn`. Users from a trust will always use spn. - -`gid_attr_map` chooses which attribute is used for domain local groups in presentation. Defaults to -`spn`. Groups from a trust will always use spn. - -`selinux` controls whether the `kanidm_unixd_tasks` daemon should detect and enable SELinux runtime -compatibility features to ensure that newly created home directories are labeled correctly. This -setting as no bearing on systems without SELinux, as these features will automatically be disabled -if SELinux is not detected when the daemon starts. Note that `kanidm_unixd_tasks` must also be built -with the SELinux feature flag for this functionality. Defaults to true. - -`allow_local_account_override` allows kanidm to "override" the content of a user or group that is -defined locally. By default kanidm will detect when a user/group conflict with their entries from -`/etc/passwd` or `/etc/group` and will ignore the kanidm entry. However if you want kanidm to -override users or groups from the local system, you must list them in this field. Note that this can -have many unexpected consequences, so it is not recommended to enable this. - You can then check the communication status of the daemon: ```bash diff --git a/examples/unixd b/examples/unixd index c80b82a11..516b7c828 100644 --- a/examples/unixd +++ b/examples/unixd @@ -1,12 +1,117 @@ -# this should be at /etc/kanidm/unixd, and configures kanidm-unixd -# some documentation is here: https://github.com/kanidm/kanidm/blob/master/book/src/pam_and_nsswitch.md -# pam_allowed_login_groups = ["posix_group"] +## Kanidm Unixd Service Configuration - /etc/kanidm/unixd + +# Defines a set of POSIX groups where membership of any of these groups +# will be allowed to login via PAM. All POSIX users and groups can be +# resolved by nss regardless of PAM login status. This may be a group +# name, spn, or uuid. +# +# Default: empty set (no access allowed) + +pam_allowed_login_groups = ["posix_group"] + +# Kanidm unix will bind all cached credentials to a local Hardware Security +# Module (HSM) to prevent exfiltration and attacks against these. In addition, +# any internal private keys will also be stored in this HSM. +# +# * soft: A software hsm that encrypts all local key material +# * tpm: Use a tpm for all key storage and binding +# +# Default: soft + +# hsm_type = "tpm" + + +# If using `hsm_type = "tpm"`, this allows configuration of the TCTI name of +# the tpm to use. For more, see: https://tpm2-tools.readthedocs.io/en/latest/man/common/tcti/ +# +# You should leave this value as the default kernel resource manager. +# +# Default: device:/dev/tpmrm0 + +# tpm_tcti_name = "device:/dev/tpmrm0" + + +# Default shell for users if no value is set. +# +# Default: /bin/sh + # default_shell = "/bin/sh" + + +# The prefix prepended to where home directories are stored. Must end with a trailing `/`. +# +# Default: /home/ + # home_prefix = "/home/" + + +# The attribute to use for the stable home directory path. Valid choices are +# `uuid`, `name`, `spn`. + +# > **NOTICE:** All users in Kanidm can change their name (and their spn) at any time. If you change +# > `home_attr` from `uuid` you _must_ have a plan on how to manage these directory renames in your +# > system. We recommend that you have a stable ID (like the UUID), and symlinks from the name to the +# > UUID folder. Automatic support is provided for this via the unixd tasks daemon, as documented +# > here. + +# Default: uuid + # home_attr = "uuid" + + +# The default token attribute used for generating symlinks pointing to the user's home +# directory. If set, this will become the value of the home path to nss calls. It is recommended you +# choose a "human friendly" attribute here. Valid choices are `none`, `uuid`, `name`, `spn`. Defaults +# to `spn`. +# +# Default: spn + # home_alias = "spn" + + +# Controls if home directories should be prepopulated with the contents of `/etc/skel` +# when first created. +# +# Default: false + # use_etc_skel = false + + +# Chooses which attribute is used for domain local users in presentation of the uid value. +# +# Default: spn +# NOTE: Users from a trust will always use spn. + # uid_attr_map = "spn" + + +# Chooses which attribute is used for domain local groups in presentation of the gid value. + +# Default: spn +# NOTE: Groups from a trust will always use spn. + # gid_attr_map = "spn" + + +# `selinux` controls whether the `kanidm_unixd_tasks` daemon should detect and enable SELinux runtime +# compatibility features to ensure that newly created home directories are labeled correctly. This +# setting as no bearing on systems without SELinux, as these features will automatically be disabled +# if SELinux is not detected when the daemon starts. Note that `kanidm_unixd_tasks` must also be built +# with the SELinux feature flag for this functionality. +# +# Default: true + +# selinux = true + + +# allows kanidm to "override" the content of a user or group that is defined locally when a name +# collision occurs. By default kanidm will detect when a user/group conflict with their entries from +# `/etc/passwd` or `/etc/group` and will ignore the kanidm entry. However if you want kanidm to +# override users or groups from the local system, you must list them in this field. Note that this can +# have many unexpected consequences, so it is not recommended to enable this. +# +# Default: Empty set (no overrides) + # allow_local_account_override = ["admin"] + diff --git a/libs/crypto/src/lib.rs b/libs/crypto/src/lib.rs index cbdb77cac..460b1a86c 100644 --- a/libs/crypto/src/lib.rs +++ b/libs/crypto/src/lib.rs @@ -55,10 +55,16 @@ const DS_SSHA512_HASH_LEN: usize = 64; const ARGON2_VERSION: u32 = 19; const ARGON2_SALT_LEN: usize = 16; const ARGON2_KEY_LEN: usize = 32; +// Default amount of ram we sacrifice per thread is 8MB const ARGON2_MIN_RAM_KIB: u32 = 8 * 1024; -const ARGON2_MAX_RAM_KIB: u32 = 32 * 1024; +// Max is 64MB. This may change in time. +const ARGON2_MAX_RAM_KIB: u32 = 64 * 1024; +// Amount of ram to subtract when we do a T cost iter. This +// is because t=2 m=32 == t=3 m=20. So we just step down a little +// to keep the value about the same. +const ARGON2_TCOST_RAM_ITER_KIB: u32 = 12 * 1024; const ARGON2_MIN_T_COST: u32 = 2; -const ARGON2_MAX_T_COST: u32 = 4; +const ARGON2_MAX_T_COST: u32 = 16; const ARGON2_MAX_P_COST: u32 = 1; #[derive(Clone, Debug)] @@ -254,10 +260,7 @@ impl CryptoPolicy { // thread x ram will be used. If we had 8 threads at 64mb of ram, that would require // 512mb of ram alone just for hashing. This becomes worse as core counts scale, with // 24 core xeons easily reaching 1.5GB in these cases. - // - // To try to balance this we cap max ram at 32MB for now. - // Default amount of ram we sacrifice per thread is 8MB let mut m_cost = ARGON2_MIN_RAM_KIB; let mut t_cost = ARGON2_MIN_T_COST; let p_cost = ARGON2_MAX_P_COST; @@ -278,7 +281,7 @@ impl CryptoPolicy { }; if let Some(ubt) = Password::bench_argon2id(params) { - trace!("{}µs - t_cost {} m_cost {}", ubt.as_nanos(), t_cost, m_cost); + debug!("{}µs - t_cost {} m_cost {}", ubt.as_nanos(), t_cost, m_cost); // Parameter adjustment if ubt < target_time { if m_cost < ARGON2_MAX_RAM_KIB { @@ -293,7 +296,7 @@ impl CryptoPolicy { m_cost * 2 } else { // Close! Increase in a small step - m_cost + (2 * 1024) + m_cost + 1024 }; m_cost = if m_adjust > ARGON2_MAX_RAM_KIB { @@ -308,15 +311,20 @@ impl CryptoPolicy { // here though, just to give a little window under that for adjustment. // // Similar, once we hit t=4 we just need to have max ram. - let m_adjust = (t_cost.saturating_sub(ARGON2_MIN_T_COST) - * ARGON2_MIN_RAM_KIB) - + ARGON2_MAX_RAM_KIB; + t_cost += 1; + // Halve the ram cost. + let m_adjust = m_cost + .checked_sub(ARGON2_TCOST_RAM_ITER_KIB) + .unwrap_or(ARGON2_MIN_RAM_KIB); + + // Floor and Ceil m_cost = if m_adjust > ARGON2_MAX_RAM_KIB { ARGON2_MAX_RAM_KIB + } else if m_adjust < ARGON2_MIN_RAM_KIB { + ARGON2_MIN_RAM_KIB } else { m_adjust }; - t_cost += 1; continue; } else { // Unable to proceed, parameters are maxed out. @@ -1291,7 +1299,7 @@ mod tests { let im_pw = "{ARGON2}$argon2id$v=19$m=65536,t=2,p=1$IyTQMsvzB2JHDiWx8fq7Ew$VhYOA7AL0kbRXI5g2kOyyp8St1epkNj7WZyUY4pAIQQ"; let password = "password"; let r = Password::try_from(im_pw).expect("Failed to parse"); - assert!(r.requires_upgrade()); + assert!(!r.requires_upgrade()); assert!(r.verify(password).unwrap_or(false)); } @@ -1363,7 +1371,7 @@ mod tests { let mut hsm: Box = Box::new(SoftTpm::new()); - let auth_value = AuthValue::new_random().unwrap(); + let auth_value = AuthValue::ephemeral().unwrap(); let loadable_machine_key = hsm.machine_key_create(&auth_value).unwrap(); let machine_key = hsm diff --git a/platform/opensuse/kanidm-unixd.service b/platform/opensuse/kanidm-unixd.service index c2e4a68c3..de3aa7f17 100644 --- a/platform/opensuse/kanidm-unixd.service +++ b/platform/opensuse/kanidm-unixd.service @@ -13,10 +13,15 @@ SupplementaryGroups=tss UMask=0027 CacheDirectory=kanidm-unixd RuntimeDirectory=kanidm-unixd +StateDirectory=kanidm-unixd Type=simple ExecStart=/usr/sbin/kanidm_unixd +## If you wish to setup an external HSM pin you should set: +# LoadCredential=hsmpin:/etc/kanidm/kanidm-unixd-hsm-pin +# Environment=KANIDM_HSM_PIN_PATH=%d/hsmpin + # Implied by dynamic user. # ProtectHome= # ProtectSystem=strict diff --git a/unix_integration/Cargo.toml b/unix_integration/Cargo.toml index 319a439a2..7000b2346 100644 --- a/unix_integration/Cargo.toml +++ b/unix_integration/Cargo.toml @@ -57,6 +57,7 @@ base64urlsafedata = { workspace = true } bytes = { workspace = true } clap = { workspace = true, features = ["derive", "env"] } csv = { workspace = true } +compact_jwt = { workspace = true, features = ["hsm-crypto"] } futures = { workspace = true } hashbrown = { workspace = true } libc = { workspace = true } diff --git a/unix_integration/src/constants.rs b/unix_integration/src/constants.rs index ec69453ce..a29b1b3c0 100644 --- a/unix_integration/src/constants.rs +++ b/unix_integration/src/constants.rs @@ -15,4 +15,4 @@ pub const DEFAULT_UID_ATTR_MAP: UidAttr = UidAttr::Spn; pub const DEFAULT_GID_ATTR_MAP: UidAttr = UidAttr::Spn; pub const DEFAULT_SELINUX: bool = true; pub const DEFAULT_TPM_TCTI_NAME: &str = "device:/dev/tpmrm0"; -pub const DEFAULT_HSM_PIN_PATH: &str = "/etc/kanidm/unixd-hsm-pin"; +pub const DEFAULT_HSM_PIN_PATH: &str = "/var/lib/kanidm-unixd/hsm-pin"; diff --git a/unix_integration/src/daemon.rs b/unix_integration/src/daemon.rs index 63ac507fd..b11599212 100644 --- a/unix_integration/src/daemon.rs +++ b/unix_integration/src/daemon.rs @@ -439,7 +439,6 @@ async fn process_etc_passwd_group( async fn read_hsm_pin(hsm_pin_path: &str) -> Result, Box> { if !PathBuf::from_str(hsm_pin_path)?.exists() { - // TODO generate the file by default return Err(std::io::Error::new( std::io::ErrorKind::NotFound, format!("HSM PIN file '{}' not found", hsm_pin_path), @@ -453,6 +452,21 @@ async fn read_hsm_pin(hsm_pin_path: &str) -> Result, Box> { Ok(contents) } +async fn write_hsm_pin(hsm_pin_path: &str) -> Result<(), Box> { + if !PathBuf::from_str(hsm_pin_path)?.exists() { + let new_pin = AuthValue::generate().map_err(|hsm_err| { + error!(?hsm_err, "Unable to generate new pin"); + std::io::Error::new(std::io::ErrorKind::Other, "Unable to generate new pin") + })?; + + std::fs::write(hsm_pin_path, new_pin)?; + + info!("Generated new HSM pin"); + } + + Ok(()) +} + #[tokio::main(flavor = "current_thread")] async fn main() -> ExitCode { let cuid = get_current_uid(); @@ -652,8 +666,8 @@ async fn main() -> ExitCode { .to_str() .unwrap_or("") ); - let diag = kanidm_lib_file_permissions::diagnose_path(db_path.as_ref()); - info!(%diag); + let diag = kanidm_lib_file_permissions::diagnose_path(db_path.as_ref()); + info!(%diag); return ExitCode::FAILURE } @@ -702,8 +716,8 @@ async fn main() -> ExitCode { "Refusing to run - DB path {} already exists and is not a file.", db_path.to_str().unwrap_or("") ); - let diag = kanidm_lib_file_permissions::diagnose_path(db_path.as_ref()); - info!(%diag); + let diag = kanidm_lib_file_permissions::diagnose_path(db_path.as_ref()); + info!(%diag); return ExitCode::FAILURE }; @@ -715,8 +729,8 @@ async fn main() -> ExitCode { db_path.to_str().unwrap_or(""), e ); - let diag = kanidm_lib_file_permissions::diagnose_path(db_path.as_ref()); - info!(%diag); + let diag = kanidm_lib_file_permissions::diagnose_path(db_path.as_ref()); + info!(%diag); return ExitCode::FAILURE } }; @@ -744,6 +758,22 @@ async fn main() -> ExitCode { } }; + // perform any db migrations. + let mut dbtxn = db.write().await; + if dbtxn.migrate() + .and_then(|_| { + dbtxn.commit() + }).is_err() { + error!("Failed to migrate database"); + return ExitCode::FAILURE + } + + // Check for and create the hsm pin if required. + if let Err(err) = write_hsm_pin(cfg.hsm_pin_path.as_str()).await { + error!(?err, "Failed to create HSM PIN into {}", cfg.hsm_pin_path.as_str()); + return ExitCode::FAILURE + }; + // read the hsm pin let hsm_pin = match read_hsm_pin(cfg.hsm_pin_path.as_str()).await { Ok(hp) => hp, @@ -802,7 +832,8 @@ async fn main() -> ExitCode { let machine_key = match hsm.machine_key_load(&auth_value, &loadable_machine_key) { Ok(mk) => mk, Err(err) => { - error!(?err, "Unable to load machine key"); + error!(?err, "Unable to load machine root key - This can occur if you have changed your HSM pin"); + error!("To proceed you must remove the content of the cache db ({}) to reset all keys", cfg.db_path.as_str()); return ExitCode::FAILURE } }; diff --git a/unix_integration/src/db.rs b/unix_integration/src/db.rs index dce3bc8f5..7d39dfcac 100644 --- a/unix_integration/src/db.rs +++ b/unix_integration/src/db.rs @@ -1238,7 +1238,7 @@ mod tests { #[cfg(not(feature = "tpm"))] let mut hsm: Box = Box::new(SoftTpm::new()); - let auth_value = AuthValue::new_random().unwrap(); + let auth_value = AuthValue::ephemeral().unwrap(); let loadable_machine_key = hsm.machine_key_create(&auth_value).unwrap(); let machine_key = hsm diff --git a/unix_integration/src/idprovider/interface.rs b/unix_integration/src/idprovider/interface.rs index d40ff4f1d..ef9721a49 100644 --- a/unix_integration/src/idprovider/interface.rs +++ b/unix_integration/src/idprovider/interface.rs @@ -104,18 +104,34 @@ pub trait IdProvider { Ok(()) } - async fn provider_authenticate(&self) -> Result<(), IdpError>; + /// This is similar to a "domain join" process. What do we actually need to pass here + /// for this to work for kanidm or himmelblau? Should we make it take a generic? + /* + async fn configure_machine_identity( + &self, + _keystore: &mut D, + _tpm: &mut (dyn tpm::Tpm + Send), + _machine_key: &tpm::MachineKey, + ) -> Result<(), IdpError> { + Ok(()) + } + */ + + async fn provider_authenticate(&self, _tpm: &mut (dyn tpm::Tpm + Send)) + -> Result<(), IdpError>; async fn unix_user_get( &self, _id: &Id, _token: Option<&UserToken>, + _tpm: &mut (dyn tpm::Tpm + Send), ) -> Result; async fn unix_user_online_auth_init( &self, _account_id: &str, _token: Option<&UserToken>, + _tpm: &mut (dyn tpm::Tpm + Send), ) -> Result<(AuthRequest, AuthCredHandler), IdpError>; async fn unix_user_online_auth_step( @@ -123,6 +139,7 @@ pub trait IdProvider { _account_id: &str, _cred_handler: &mut AuthCredHandler, _pam_next_req: PamAuthRequest, + _tpm: &mut (dyn tpm::Tpm + Send), ) -> Result<(AuthResult, AuthCacheAction), IdpError>; async fn unix_user_offline_auth_init( @@ -155,5 +172,9 @@ pub trait IdProvider { ) -> Result; */ - async fn unix_group_get(&self, id: &Id) -> Result; + async fn unix_group_get( + &self, + id: &Id, + _tpm: &mut (dyn tpm::Tpm + Send), + ) -> Result; } diff --git a/unix_integration/src/idprovider/kanidm.rs b/unix_integration/src/idprovider/kanidm.rs index 842b71fcf..8ee01a96d 100644 --- a/unix_integration/src/idprovider/kanidm.rs +++ b/unix_integration/src/idprovider/kanidm.rs @@ -115,7 +115,10 @@ impl IdProvider for KanidmProvider { } // Needs .read on all types except re-auth. - async fn provider_authenticate(&self) -> Result<(), IdpError> { + async fn provider_authenticate( + &self, + _tpm: &mut (dyn tpm::Tpm + Send), + ) -> Result<(), IdpError> { match self.client.write().await.auth_anonymous().await { Ok(_uat) => Ok(()), Err(err) => { @@ -129,6 +132,7 @@ impl IdProvider for KanidmProvider { &self, id: &Id, _token: Option<&UserToken>, + _tpm: &mut (dyn tpm::Tpm + Send), ) -> Result { match self .client @@ -191,6 +195,7 @@ impl IdProvider for KanidmProvider { &self, _account_id: &str, _token: Option<&UserToken>, + _tpm: &mut (dyn tpm::Tpm + Send), ) -> Result<(AuthRequest, AuthCredHandler), IdpError> { // Not sure that I need to do much here? Ok((AuthRequest::Password, AuthCredHandler::Password)) @@ -201,6 +206,7 @@ impl IdProvider for KanidmProvider { account_id: &str, cred_handler: &mut AuthCredHandler, pam_next_req: PamAuthRequest, + _tpm: &mut (dyn tpm::Tpm + Send), ) -> Result<(AuthResult, AuthCacheAction), IdpError> { match (cred_handler, pam_next_req) { (AuthCredHandler::Password, PamAuthRequest::Password { cred }) => { @@ -303,7 +309,11 @@ impl IdProvider for KanidmProvider { } */ - async fn unix_group_get(&self, id: &Id) -> Result { + async fn unix_group_get( + &self, + id: &Id, + _tpm: &mut (dyn tpm::Tpm + Send), + ) -> Result { match self .client .read() diff --git a/unix_integration/src/resolver.rs b/unix_integration/src/resolver.rs index 5d99b8c34..bb5721246 100644 --- a/unix_integration/src/resolver.rs +++ b/unix_integration/src/resolver.rs @@ -110,11 +110,6 @@ where let hsm = Mutex::new(hsm); let mut hsm_lock = hsm.lock().await; - // setup and do a migrate. - let mut dbtxn = db.write().await; - dbtxn.migrate().map_err(|_| ())?; - dbtxn.commit().map_err(|_| ())?; - // Setup our internal keys let mut dbtxn = db.write().await; @@ -477,7 +472,16 @@ where account_id: &Id, token: Option, ) -> Result, ()> { - match self.client.unix_user_get(account_id, token.as_ref()).await { + let mut hsm_lock = self.hsm.lock().await; + + let user_get_result = self + .client + .unix_user_get(account_id, token.as_ref(), &mut **hsm_lock.deref_mut()) + .await; + + drop(hsm_lock); + + match user_get_result { Ok(mut n_tok) => { if self.check_nxset(&n_tok.name, n_tok.gidnumber).await { // Refuse to release the token, it's in the denied set. @@ -527,7 +531,16 @@ where grp_id: &Id, token: Option, ) -> Result, ()> { - match self.client.unix_group_get(grp_id).await { + let mut hsm_lock = self.hsm.lock().await; + + let group_get_result = self + .client + .unix_group_get(grp_id, &mut **hsm_lock.deref_mut()) + .await; + + drop(hsm_lock); + + match group_get_result { Ok(n_tok) => { if self.check_nxset(&n_tok.name, n_tok.gidnumber).await { // Refuse to release the token, it's in the denied set. @@ -863,8 +876,9 @@ where }; let maybe_err = if online_at_init { + let mut hsm_lock = self.hsm.lock().await; self.client - .unix_user_online_auth_init(account_id, token.as_ref()) + .unix_user_online_auth_init(account_id, token.as_ref(), &mut **hsm_lock.deref_mut()) .await } else { // Can the auth proceed offline? @@ -919,11 +933,20 @@ where }, CacheState::Online, ) => { + let mut hsm_lock = self.hsm.lock().await; + let maybe_cache_action = self .client - .unix_user_online_auth_step(account_id, cred_handler, pam_next_req) + .unix_user_online_auth_step( + account_id, + cred_handler, + pam_next_req, + &mut **hsm_lock.deref_mut(), + ) .await; + drop(hsm_lock); + match maybe_cache_action { Ok((res, AuthCacheAction::None)) => Ok(res), Ok(( @@ -1120,7 +1143,16 @@ where false } CacheState::OfflineNextCheck(_time) => { - match self.client.provider_authenticate().await { + let mut hsm_lock = self.hsm.lock().await; + + let prov_auth_result = self + .client + .provider_authenticate(&mut **hsm_lock.deref_mut()) + .await; + + drop(hsm_lock); + + match prov_auth_result { Ok(()) => { debug!("OfflineNextCheck -> authenticated"); self.set_cachestate(CacheState::Online).await; diff --git a/unix_integration/tests/cache_layer_test.rs b/unix_integration/tests/cache_layer_test.rs index 68debf075..8b04cfa24 100644 --- a/unix_integration/tests/cache_layer_test.rs +++ b/unix_integration/tests/cache_layer_test.rs @@ -10,7 +10,7 @@ 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::db::Db; +use kanidm_unix_common::db::{Cache, CacheTxn, Db}; use kanidm_unix_common::idprovider::interface::Id; use kanidm_unix_common::idprovider::kanidm::KanidmProvider; use kanidm_unix_common::resolver::Resolver; @@ -103,9 +103,15 @@ async fn setup_test(fix_fn: Fixture) -> (Resolver, KanidmClient) ) .expect("Failed to setup DB"); + let mut dbtxn = db.write().await; + dbtxn + .migrate() + .and_then(|_| dbtxn.commit()) + .expect("Unable to migrate cache db"); + let mut hsm: Box = Box::new(SoftTpm::new()); - let auth_value = AuthValue::new_random().unwrap(); + let auth_value = AuthValue::ephemeral().unwrap(); let loadable_machine_key = hsm.machine_key_create(&auth_value).unwrap(); let machine_key = hsm