diff --git a/Cargo.lock b/Cargo.lock index a7c1abfb3..a4b843b4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "android-tzdata" @@ -180,9 +180,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "anymap2" @@ -276,7 +276,7 @@ dependencies = [ "async-lock", "async-task", "concurrent-queue", - "fastrand", + "fastrand 1.9.0", "futures-lite", "slab", ] @@ -621,7 +621,7 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "prettyplease 0.2.10", + "prettyplease 0.2.12", "proc-macro2", "quote", "regex", @@ -722,7 +722,7 @@ dependencies = [ "async-lock", "async-task", "atomic-waker", - "fastrand", + "fastrand 1.9.0", "futures-lite", "log", ] @@ -1478,9 +1478,9 @@ checksum = "304e6508efa593091e97a9abbc10f90aa7ca635b6d2784feff3c89d41dd12272" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encode_unicode" @@ -1609,6 +1609,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "fernet" version = "0.2.1" @@ -1767,7 +1773,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -2222,9 +2228,9 @@ dependencies = [ [[package]] name = "http-range-header" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "http-types" @@ -2485,9 +2491,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -2649,6 +2655,7 @@ dependencies = [ name = "kanidm_unix_int" version = "1.1.0-beta.13-dev" dependencies = [ + "async-trait", "base64urlsafedata", "bytes", "clap 4.3.19", @@ -3025,9 +3032,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" +checksum = "24e6ab01971eb092ffe6a7d42f49f9ff42662f17604681e2843ad65077ba47dc" dependencies = [ "cc", "libc", @@ -3337,9 +3344,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -3654,9 +3661,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" +checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" dependencies = [ "thiserror", "ucd-trie", @@ -3819,9 +3826,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92139198957b410250d43fad93e630d956499a625c527eda65175c8680f83387" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", "syn 2.0.27", @@ -4079,7 +4086,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.2", + "regex-automata 0.3.3", "regex-syntax 0.7.4", ] @@ -4094,9 +4101,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", @@ -4281,15 +4288,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -4334,15 +4341,15 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4353,9 +4360,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -4453,9 +4460,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a16be4fe5320ade08736447e3198294a5ea9a6d44dde6f35f0a5e06859c427a" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] @@ -4504,9 +4511,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc4422959dd87a76cb117c191dcbffc20467f06c9100b76721dab370f24d3a" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ "itoa", "serde", @@ -4837,21 +4844,20 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.9" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8e77cb757a61f51b947ec4a7e3646efd825b73561db1c232a8ccb639e611a0" +checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" dependencies = [ - "autocfg", "cfg-if", - "fastrand", + "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -4872,18 +4878,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", @@ -5117,9 +5123,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.12" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap 2.0.0", "toml_datetime", @@ -5348,9 +5354,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -5948,9 +5954,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.9" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] diff --git a/unix_integration/Cargo.toml b/unix_integration/Cargo.toml index 897eb1fa4..8c54dd343 100644 --- a/unix_integration/Cargo.toml +++ b/unix_integration/Cargo.toml @@ -42,6 +42,7 @@ name = "kanidm_unix_common" path = "src/lib.rs" [dependencies] +async-trait.workspace = true base64urlsafedata = { workspace = true } bytes = { workspace = true } clap = { workspace = true, features = ["derive", "env"] } diff --git a/unix_integration/src/daemon.rs b/unix_integration/src/daemon.rs index ae2c5de30..763e43e05 100644 --- a/unix_integration/src/daemon.rs +++ b/unix_integration/src/daemon.rs @@ -25,8 +25,9 @@ use clap::{Arg, ArgAction, Command}; use futures::{SinkExt, StreamExt}; use kanidm_client::KanidmClientBuilder; use kanidm_proto::constants::DEFAULT_CLIENT_CONFIG_PATH; -use kanidm_unix_common::cache::CacheLayer; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; +use kanidm_unix_common::db::Db; +use kanidm_unix_common::resolver::Resolver; use kanidm_unix_common::unix_config::KanidmUnixdConfig; use kanidm_unix_common::unix_passwd::{parse_etc_group, parse_etc_passwd}; use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse, TaskRequest, TaskResponse}; @@ -181,7 +182,7 @@ async fn handle_task_client( async fn handle_client( sock: UnixStream, - cachelayer: Arc, + cachelayer: Arc, task_channel_tx: &Sender, ) -> Result<(), Box> { debug!("Accepted connection"); @@ -371,7 +372,7 @@ async fn handle_client( Ok(()) } -async fn process_etc_passwd_group(cachelayer: &CacheLayer) -> Result<(), Box> { +async fn process_etc_passwd_group(cachelayer: &Resolver) -> Result<(), Box> { let mut file = File::open("/etc/passwd").await?; let mut contents = vec![]; file.read_to_end(&mut contents).await?; @@ -660,8 +661,16 @@ async fn main() -> ExitCode { } }; - let cl_inner = match CacheLayer::new( - cfg.db_path.as_str(), // The sqlite db path + let db = match Db::new(cfg.db_path.as_str(), &cfg.tpm_policy) { + Ok(db) => db, + Err(_e) => { + error!("Failed to create database"); + return ExitCode::FAILURE + } + }; + + let cl_inner = match Resolver::new( + db, cfg.cache_timeout, rsclient, cfg.pam_allowed_login_groups.clone(), @@ -672,7 +681,6 @@ async fn main() -> ExitCode { cfg.uid_attr_map, cfg.gid_attr_map, cfg.allow_local_account_override.clone(), - &cfg.tpm_policy, ) .await { diff --git a/unix_integration/src/db.rs b/unix_integration/src/db.rs index 367f319e8..706050696 100644 --- a/unix_integration/src/db.rs +++ b/unix_integration/src/db.rs @@ -3,6 +3,7 @@ use std::fmt; use std::time::Duration; use crate::unix_config::TpmPolicy; +use async_trait::async_trait; use kanidm_lib_crypto::CryptoPolicy; use kanidm_lib_crypto::DbPasswordV1; use kanidm_lib_crypto::Password; @@ -11,7 +12,58 @@ use libc::umask; use rusqlite::Connection; use tokio::sync::{Mutex, MutexGuard}; -use crate::cache::Id; +use crate::resolver::Id; + +#[async_trait] +pub trait Cache { + type Txn<'db> + where + Self: 'db; + + async fn write<'db>(&'db self) -> Self::Txn<'db>; +} + +#[derive(Debug)] +pub enum CacheError { + Cryptography, + SerdeJson, + Parse, + Sqlite, + TooManyResults, + TransactionInvalidState, +} + +pub trait CacheTxn { + fn migrate(&self) -> Result<(), CacheError>; + + fn commit(self) -> Result<(), CacheError>; + + fn invalidate(&self) -> Result<(), CacheError>; + + fn clear(&self) -> Result<(), CacheError>; + + fn get_account(&self, account_id: &Id) -> Result, CacheError>; + + fn get_accounts(&self) -> Result, CacheError>; + + fn update_account(&self, account: &UnixUserToken, expire: u64) -> Result<(), CacheError>; + + fn delete_account(&self, a_uuid: &str) -> Result<(), CacheError>; + + fn update_account_password(&self, a_uuid: &str, cred: &str) -> Result<(), CacheError>; + + fn check_account_password(&self, a_uuid: &str, cred: &str) -> Result; + + fn get_group(&self, grp_id: &Id) -> Result, CacheError>; + + fn get_group_members(&self, g_uuid: &str) -> Result, CacheError>; + + fn get_groups(&self) -> Result, CacheError>; + + fn update_group(&self, grp: &UnixGroupToken, expire: u64) -> Result<(), CacheError>; + + fn delete_group(&self, g_uuid: &str) -> Result<(), CacheError>; +} pub struct Db { conn: Mutex, @@ -53,9 +105,14 @@ impl Db { require_tpm, }) } +} + +#[async_trait] +impl Cache for Db { + type Txn<'db> = DbTxn<'db>; #[allow(clippy::expect_used)] - pub async fn write(&self) -> DbTxn<'_> { + async fn write<'db>(&'db self) -> Self::Txn<'db> { let conn = self.conn.lock().await; DbTxn::new(conn, &self.crypto_policy, self.require_tpm.as_ref()) } @@ -68,7 +125,7 @@ impl fmt::Debug for Db { } impl<'a> DbTxn<'a> { - pub fn new( + fn new( conn: MutexGuard<'a, Connection>, crypto_policy: &'a CryptoPolicy, require_tpm: Option<&'a tpm::TpmConfig>, @@ -87,33 +144,109 @@ impl<'a> DbTxn<'a> { } /// This handles an error coming back from an sqlite event and dumps more information from it - fn sqlite_error(&self, msg: &str, error: &rusqlite::Error) { + fn sqlite_error(&self, msg: &str, error: &rusqlite::Error) -> CacheError { error!( "sqlite {} error: {:?} db_path={:?}", msg, error, &self.conn.path() ); + CacheError::Sqlite } /// This handles an error coming back from an sqlite transaction and dumps a load of information from it - fn sqlite_transaction_error(&self, error: &rusqlite::Error, _stmt: &rusqlite::Statement) { + fn sqlite_transaction_error( + &self, + error: &rusqlite::Error, + _stmt: &rusqlite::Statement, + ) -> CacheError { error!( "sqlite transaction error={:?} db_path={:?}", error, &self.conn.path(), ); // TODO: one day figure out if there's an easy way to dump the transaction without the token... + CacheError::Sqlite } - pub fn migrate(&self) -> Result<(), ()> { + fn get_account_data_name(&self, account_id: &str) -> Result, i64)>, CacheError> { + let mut stmt = self.conn + .prepare( + "SELECT token, expiry FROM account_t WHERE uuid = :account_id OR name = :account_id OR spn = :account_id" + ) + .map_err(|e| { + self.sqlite_error("select prepare", &e) + })?; + + // Makes tuple (token, expiry) + let data_iter = stmt + .query_map([account_id], |row| Ok((row.get(0)?, row.get(1)?))) + .map_err(|e| self.sqlite_error("query_map failure", &e))?; + let data: Result, i64)>, _> = data_iter + .map(|v| v.map_err(|e| self.sqlite_error("map failure", &e))) + .collect(); + data + } + + fn get_account_data_gid(&self, gid: u32) -> Result, i64)>, CacheError> { + let mut stmt = self + .conn + .prepare("SELECT token, expiry FROM account_t WHERE gidnumber = :gid") + .map_err(|e| self.sqlite_error("select prepare", &e))?; + + // Makes tuple (token, expiry) + let data_iter = stmt + .query_map(params![gid], |row| Ok((row.get(0)?, row.get(1)?))) + .map_err(|e| self.sqlite_error("query_map", &e))?; + let data: Result, i64)>, _> = data_iter + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) + .collect(); + data + } + + fn get_group_data_name(&self, grp_id: &str) -> Result, i64)>, CacheError> { + let mut stmt = self.conn + .prepare( + "SELECT token, expiry FROM group_t WHERE uuid = :grp_id OR name = :grp_id OR spn = :grp_id" + ) + .map_err(|e| { + self.sqlite_error("select prepare", &e) + })?; + + // Makes tuple (token, expiry) + let data_iter = stmt + .query_map([grp_id], |row| Ok((row.get(0)?, row.get(1)?))) + .map_err(|e| self.sqlite_error("query_map", &e))?; + let data: Result, i64)>, _> = data_iter + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) + .collect(); + data + } + + fn get_group_data_gid(&self, gid: u32) -> Result, i64)>, CacheError> { + let mut stmt = self + .conn + .prepare("SELECT token, expiry FROM group_t WHERE gidnumber = :gid") + .map_err(|e| self.sqlite_error("select prepare", &e))?; + + // Makes tuple (token, expiry) + let data_iter = stmt + .query_map(params![gid], |row| Ok((row.get(0)?, row.get(1)?))) + .map_err(|e| self.sqlite_error("query_map", &e))?; + let data: Result, i64)>, _> = data_iter + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) + .collect(); + data + } +} + +impl<'a> CacheTxn for DbTxn<'a> { + fn migrate(&self) -> Result<(), CacheError> { self.conn.set_prepared_statement_cache_capacity(16); self.conn .prepare("PRAGMA journal_mode=WAL;") .and_then(|mut wal_stmt| wal_stmt.query([]).map(|_| ())) - .map_err(|e| { - self.sqlite_error("account_t create", &e); - })?; + .map_err(|e| self.sqlite_error("account_t create", &e))?; // Setup two tables - one for accounts, one for groups. // correctly index the columns. @@ -132,9 +265,7 @@ impl<'a> DbTxn<'a> { ", [], ) - .map_err(|e| { - self.sqlite_error("account_t create", &e); - })?; + .map_err(|e| self.sqlite_error("account_t create", &e))?; self.conn .execute( @@ -149,9 +280,7 @@ impl<'a> DbTxn<'a> { ", [], ) - .map_err(|e| { - self.sqlite_error("group_t create", &e); - })?; + .map_err(|e| self.sqlite_error("group_t create", &e))?; // We defer group foreign keys here because we now manually cascade delete these when // required. This is because insert or replace into will always delete then add @@ -170,115 +299,54 @@ impl<'a> DbTxn<'a> { ", [], ) - .map_err(|e| { - self.sqlite_error("memberof_t create error", &e); - })?; + .map_err(|e| self.sqlite_error("memberof_t create error", &e))?; Ok(()) } - pub fn commit(mut self) -> Result<(), ()> { + fn commit(mut self) -> Result<(), CacheError> { // debug!("Committing BE txn"); if self.committed { error!("Invalid state, SQL transaction was already committed!"); - return Err(()); + return Err(CacheError::TransactionInvalidState); } self.committed = true; self.conn .execute("COMMIT TRANSACTION", []) .map(|_| ()) - .map_err(|e| { - self.sqlite_error("commit", &e); - }) + .map_err(|e| self.sqlite_error("commit", &e)) } - pub fn invalidate(&self) -> Result<(), ()> { + fn invalidate(&self) -> Result<(), CacheError> { self.conn .execute("UPDATE group_t SET expiry = 0", []) - .map_err(|e| { - self.sqlite_error("update group_t", &e); - })?; + .map_err(|e| self.sqlite_error("update group_t", &e))?; self.conn .execute("UPDATE account_t SET expiry = 0", []) - .map_err(|e| { - self.sqlite_error("update account_t", &e); - })?; + .map_err(|e| self.sqlite_error("update account_t", &e))?; Ok(()) } - pub fn clear_cache(&self) -> Result<(), ()> { + fn clear(&self) -> Result<(), CacheError> { self.conn .execute("DELETE FROM memberof_t", []) - .map_err(|e| { - self.sqlite_error("delete memberof_t", &e); - })?; + .map_err(|e| self.sqlite_error("delete memberof_t", &e))?; - self.conn.execute("DELETE FROM group_t", []).map_err(|e| { - self.sqlite_error("delete group_t", &e); - })?; + self.conn + .execute("DELETE FROM group_t", []) + .map_err(|e| self.sqlite_error("delete group_t", &e))?; self.conn .execute("DELETE FROM account_t", []) - .map_err(|e| { - self.sqlite_error("delete group_t", &e); - })?; + .map_err(|e| self.sqlite_error("delete group_t", &e))?; Ok(()) } - fn get_account_data_name(&self, account_id: &str) -> Result, i64)>, ()> { - let mut stmt = self.conn - .prepare( - "SELECT token, expiry FROM account_t WHERE uuid = :account_id OR name = :account_id OR spn = :account_id" - ) - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; - - // Makes tuple (token, expiry) - let data_iter = stmt - .query_map([account_id], |row| Ok((row.get(0)?, row.get(1)?))) - .map_err(|e| { - self.sqlite_error("query_map failure", &e); - })?; - let data: Result, i64)>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map failure", &e); - }) - }) - .collect(); - data - } - - fn get_account_data_gid(&self, gid: u32) -> Result, i64)>, ()> { - let mut stmt = self - .conn - .prepare("SELECT token, expiry FROM account_t WHERE gidnumber = :gid") - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; - - // Makes tuple (token, expiry) - let data_iter = stmt - .query_map(params![gid], |row| Ok((row.get(0)?, row.get(1)?))) - .map_err(|e| { - self.sqlite_error("query_map", &e); - })?; - let data: Result, i64)>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) - .collect(); - data - } - - pub fn get_account(&self, account_id: &Id) -> Result, ()> { + fn get_account(&self, account_id: &Id) -> Result, CacheError> { let data = match account_id { Id::Name(n) => self.get_account_data_name(n.as_str()), Id::Gid(g) => self.get_account_data_gid(*g), @@ -287,7 +355,7 @@ impl<'a> DbTxn<'a> { // Assert only one result? if data.len() >= 2 { error!("invalid db state, multiple entries matched query?"); - return Err(()); + return Err(CacheError::TooManyResults); } if let Some((token, expiry)) = data.first() { @@ -298,6 +366,7 @@ impl<'a> DbTxn<'a> { Ok(t) => { let e = u64::try_from(*expiry).map_err(|e| { error!("u64 convert error -> {:?}", e); + CacheError::Parse })?; Ok(Some((t, e))) } @@ -311,23 +380,17 @@ impl<'a> DbTxn<'a> { } } - pub fn get_accounts(&self) -> Result, ()> { + fn get_accounts(&self) -> Result, CacheError> { let mut stmt = self .conn .prepare("SELECT token FROM account_t") - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; + .map_err(|e| self.sqlite_error("select prepare", &e))?; - let data_iter = stmt.query_map([], |row| row.get(0)).map_err(|e| { - self.sqlite_error("query_map", &e); - })?; + let data_iter = stmt + .query_map([], |row| row.get(0)) + .map_err(|e| self.sqlite_error("query_map", &e))?; let data: Result>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) .collect(); let data = data?; @@ -346,12 +409,14 @@ impl<'a> DbTxn<'a> { .collect()) } - pub fn update_account(&self, account: &UnixUserToken, expire: u64) -> Result<(), ()> { + fn update_account(&self, account: &UnixUserToken, expire: u64) -> Result<(), CacheError> { let data = serde_json::to_vec(account).map_err(|e| { error!("update_account json error -> {:?}", e); + CacheError::SerdeJson })?; let expire = i64::try_from(expire).map_err(|e| { error!("update_account i64 conversion error -> {:?}", e); + CacheError::Parse })?; // This is needed because sqlites 'insert or replace into', will null the password field @@ -368,7 +433,7 @@ impl<'a> DbTxn<'a> { } ) .map_err(|e| { - self.sqlite_error("delete account_t duplicate", &e); + self.sqlite_error("delete account_t duplicate", &e) }) .map(|_| ())?; @@ -384,14 +449,14 @@ impl<'a> DbTxn<'a> { } ) .map_err(|e| { - self.sqlite_error("delete account_t duplicate", &e); + self.sqlite_error("delete account_t duplicate", &e) })?; if updated == 0 { let mut stmt = self.conn .prepare("INSERT INTO account_t (uuid, name, spn, gidnumber, token, expiry) VALUES (:uuid, :name, :spn, :gidnumber, :token, :expiry) ON CONFLICT(uuid) DO UPDATE SET name=excluded.name, spn=excluded.name, gidnumber=excluded.gidnumber, token=excluded.token, expiry=excluded.expiry") .map_err(|e| { - self.sqlite_error("prepare", &e); + self.sqlite_error("prepare", &e) })?; stmt.execute(named_params! { @@ -405,9 +470,7 @@ impl<'a> DbTxn<'a> { .map(|r| { debug!("insert -> {:?}", r); }) - .map_err(|error| { - self.sqlite_transaction_error(&error, &stmt); - })?; + .map_err(|error| self.sqlite_transaction_error(&error, &stmt))?; } // Now, we have to update the group memberships. @@ -416,24 +479,18 @@ impl<'a> DbTxn<'a> { let mut stmt = self .conn .prepare("DELETE FROM memberof_t WHERE a_uuid = :a_uuid") - .map_err(|e| { - self.sqlite_error("prepare", &e); - })?; + .map_err(|e| self.sqlite_error("prepare", &e))?; stmt.execute([&account.uuid]) .map(|r| { debug!("delete memberships -> {:?}", r); }) - .map_err(|error| { - self.sqlite_transaction_error(&error, &stmt); - })?; + .map_err(|error| self.sqlite_transaction_error(&error, &stmt))?; let mut stmt = self .conn .prepare("INSERT INTO memberof_t (a_uuid, g_uuid) VALUES (:a_uuid, :g_uuid)") - .map_err(|e| { - self.sqlite_error("prepare", &e); - })?; + .map_err(|e| self.sqlite_error("prepare", &e))?; // Now for each group, add the relation. account.groups.iter().try_for_each(|g| { stmt.execute(named_params! { @@ -443,22 +500,18 @@ impl<'a> DbTxn<'a> { .map(|r| { debug!("insert membership -> {:?}", r); }) - .map_err(|error| { - self.sqlite_transaction_error(&error, &stmt); - }) + .map_err(|error| self.sqlite_transaction_error(&error, &stmt)) }) } - pub fn delete_account(&self, a_uuid: &str) -> Result<(), ()> { + fn delete_account(&self, a_uuid: &str) -> Result<(), CacheError> { self.conn .execute( "DELETE FROM memberof_t WHERE a_uuid = :a_uuid", params![a_uuid], ) .map(|_| ()) - .map_err(|e| { - self.sqlite_error("account_t memberof_t cascade delete", &e); - })?; + .map_err(|e| self.sqlite_error("account_t memberof_t cascade delete", &e))?; self.conn .execute( @@ -466,12 +519,10 @@ impl<'a> DbTxn<'a> { params![a_uuid], ) .map(|_| ()) - .map_err(|e| { - self.sqlite_error("account_t delete", &e); - }) + .map_err(|e| self.sqlite_error("account_t delete", &e)) } - pub fn update_account_password(&self, a_uuid: &str, cred: &str) -> Result<(), ()> { + fn update_account_password(&self, a_uuid: &str, cred: &str) -> Result<(), CacheError> { #[allow(unused_variables)] let pw = if let Some(tcti_str) = self.require_tpm { // Do nothing. @@ -485,12 +536,14 @@ impl<'a> DbTxn<'a> { } else { Password::new(self.crypto_policy, cred).map_err(|e| { error!("password error -> {:?}", e); + CacheError::Cryptography })? }; let dbpw = pw.to_dbpasswordv1(); let data = serde_json::to_vec(&dbpw).map_err(|e| { error!("json error -> {:?}", e); + CacheError::SerdeJson })?; self.conn @@ -501,13 +554,11 @@ impl<'a> DbTxn<'a> { ":data": &data, }, ) - .map_err(|e| { - self.sqlite_error("update account_t password", &e); - }) + .map_err(|e| self.sqlite_error("update account_t password", &e)) .map(|_| ()) } - pub fn check_account_password(&self, a_uuid: &str, cred: &str) -> Result { + fn check_account_password(&self, a_uuid: &str, cred: &str) -> Result { #[cfg(not(feature = "tpm"))] if self.require_tpm.is_some() { return Ok(false); @@ -516,20 +567,14 @@ impl<'a> DbTxn<'a> { let mut stmt = self .conn .prepare("SELECT password FROM account_t WHERE uuid = :a_uuid AND password IS NOT NULL") - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; + .map_err(|e| self.sqlite_error("select prepare", &e))?; // Makes tuple (token, expiry) - let data_iter = stmt.query_map([a_uuid], |row| row.get(0)).map_err(|e| { - self.sqlite_error("query_map", &e); - })?; + let data_iter = stmt + .query_map([a_uuid], |row| row.get(0)) + .map_err(|e| self.sqlite_error("query_map", &e))?; let data: Result>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) .collect(); let data = data?; @@ -541,7 +586,7 @@ impl<'a> DbTxn<'a> { if data.len() >= 2 { error!("invalid db state, multiple entries matched query?"); - return Err(()); + return Err(CacheError::TooManyResults); } let pw = data.first().map(|raw| { @@ -570,60 +615,12 @@ impl<'a> DbTxn<'a> { } else { pw.verify(cred).map_err(|e| { error!("password error -> {:?}", e); + CacheError::Cryptography }) } } - fn get_group_data_name(&self, grp_id: &str) -> Result, i64)>, ()> { - let mut stmt = self.conn - .prepare( - "SELECT token, expiry FROM group_t WHERE uuid = :grp_id OR name = :grp_id OR spn = :grp_id" - ) - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; - - // Makes tuple (token, expiry) - let data_iter = stmt - .query_map([grp_id], |row| Ok((row.get(0)?, row.get(1)?))) - .map_err(|e| { - self.sqlite_error("query_map", &e); - })?; - let data: Result, i64)>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) - .collect(); - data - } - - fn get_group_data_gid(&self, gid: u32) -> Result, i64)>, ()> { - let mut stmt = self - .conn - .prepare("SELECT token, expiry FROM group_t WHERE gidnumber = :gid") - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; - - // Makes tuple (token, expiry) - let data_iter = stmt - .query_map(params![gid], |row| Ok((row.get(0)?, row.get(1)?))) - .map_err(|e| { - self.sqlite_error("query_map", &e); - })?; - let data: Result, i64)>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) - .collect(); - data - } - - pub fn get_group(&self, grp_id: &Id) -> Result, ()> { + fn get_group(&self, grp_id: &Id) -> Result, CacheError> { let data = match grp_id { Id::Name(n) => self.get_group_data_name(n.as_str()), Id::Gid(g) => self.get_group_data_gid(*g), @@ -632,7 +629,7 @@ impl<'a> DbTxn<'a> { // Assert only one result? if data.len() >= 2 { error!("invalid db state, multiple entries matched query?"); - return Err(()); + return Err(CacheError::TooManyResults); } if let Some((token, expiry)) = data.first() { @@ -643,6 +640,7 @@ impl<'a> DbTxn<'a> { Ok(t) => { let e = u64::try_from(*expiry).map_err(|e| { error!("u64 convert error -> {:?}", e); + CacheError::Parse })?; Ok(Some((t, e))) } @@ -656,23 +654,19 @@ impl<'a> DbTxn<'a> { } } - pub fn get_group_members(&self, g_uuid: &str) -> Result, ()> { + fn get_group_members(&self, g_uuid: &str) -> Result, CacheError> { let mut stmt = self .conn .prepare("SELECT account_t.token FROM (account_t, memberof_t) WHERE account_t.uuid = memberof_t.a_uuid AND memberof_t.g_uuid = :g_uuid") .map_err(|e| { - self.sqlite_error("select prepare", &e); + self.sqlite_error("select prepare", &e) })?; - let data_iter = stmt.query_map([g_uuid], |row| row.get(0)).map_err(|e| { - self.sqlite_error("query_map", &e); - })?; + let data_iter = stmt + .query_map([g_uuid], |row| row.get(0)) + .map_err(|e| self.sqlite_error("query_map", &e))?; let data: Result>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) .collect(); let data = data?; @@ -683,28 +677,23 @@ impl<'a> DbTxn<'a> { // debug!("{:?}", token); serde_json::from_slice(token.as_slice()).map_err(|e| { error!("json error -> {:?}", e); + CacheError::SerdeJson }) }) .collect() } - pub fn get_groups(&self) -> Result, ()> { + fn get_groups(&self) -> Result, CacheError> { let mut stmt = self .conn .prepare("SELECT token FROM group_t") - .map_err(|e| { - self.sqlite_error("select prepare", &e); - })?; + .map_err(|e| self.sqlite_error("select prepare", &e))?; - let data_iter = stmt.query_map([], |row| row.get(0)).map_err(|e| { - self.sqlite_error("query_map", &e); - })?; + let data_iter = stmt + .query_map([], |row| row.get(0)) + .map_err(|e| self.sqlite_error("query_map", &e))?; let data: Result>, _> = data_iter - .map(|v| { - v.map_err(|e| { - self.sqlite_error("map", &e); - }) - }) + .map(|v| v.map_err(|e| self.sqlite_error("map", &e))) .collect(); let data = data?; @@ -723,18 +712,20 @@ impl<'a> DbTxn<'a> { .collect()) } - pub fn update_group(&self, grp: &UnixGroupToken, expire: u64) -> Result<(), ()> { + fn update_group(&self, grp: &UnixGroupToken, expire: u64) -> Result<(), CacheError> { let data = serde_json::to_vec(grp).map_err(|e| { error!("json error -> {:?}", e); + CacheError::SerdeJson })?; let expire = i64::try_from(expire).map_err(|e| { error!("i64 convert error -> {:?}", e); + CacheError::Parse })?; let mut stmt = self.conn .prepare("INSERT OR REPLACE INTO group_t (uuid, name, spn, gidnumber, token, expiry) VALUES (:uuid, :name, :spn, :gidnumber, :token, :expiry)") .map_err(|e| { - self.sqlite_error("prepare", &e); + self.sqlite_error("prepare", &e) })?; stmt.execute(named_params! { @@ -748,24 +739,18 @@ impl<'a> DbTxn<'a> { .map(|r| { debug!("insert -> {:?}", r); }) - .map_err(|e| { - self.sqlite_error("execute", &e); - }) + .map_err(|e| self.sqlite_error("execute", &e)) } - pub fn delete_group(&self, g_uuid: &str) -> Result<(), ()> { + fn delete_group(&self, g_uuid: &str) -> Result<(), CacheError> { self.conn .execute("DELETE FROM memberof_t WHERE g_uuid = :g_uuid", [g_uuid]) .map(|_| ()) - .map_err(|e| { - self.sqlite_error("group_t memberof_t cascade delete", &e); - })?; + .map_err(|e| self.sqlite_error("group_t memberof_t cascade delete", &e))?; self.conn .execute("DELETE FROM group_t WHERE uuid = :g_uuid", [g_uuid]) .map(|_| ()) - .map_err(|e| { - self.sqlite_error("group_t delete", &e); - }) + .map_err(|e| self.sqlite_error("group_t delete", &e)) } } @@ -1143,9 +1128,10 @@ pub(crate) mod tpm { #[cfg(test)] mod tests { use kanidm_proto::v1::{UnixGroupToken, UnixUserToken}; + // use std::assert_matches::assert_matches; - use super::Db; - use crate::cache::Id; + use super::{Cache, CacheTxn, Db}; + use crate::resolver::Id; use crate::unix_config::TpmPolicy; const TESTACCOUNT1_PASSWORD_A: &str = "password a for account1 test"; @@ -1220,7 +1206,7 @@ mod tests { assert!(r4.is_some()); // Clear cache - assert!(dbtxn.clear_cache().is_ok()); + assert!(dbtxn.clear().is_ok()); // should be nothing let r1 = dbtxn.get_account(&id_name2).unwrap(); @@ -1295,7 +1281,7 @@ mod tests { assert!(r4.is_some()); // clear cache - assert!(dbtxn.clear_cache().is_ok()); + assert!(dbtxn.clear().is_ok()); // should be nothing. let r1 = dbtxn.get_group(&id_name2).unwrap(); @@ -1407,30 +1393,51 @@ mod tests { }; // Test that with no account, is false - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A) == Ok(false)); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A), + Ok(false) + )); // test adding an account dbtxn.update_account(&ut1, 0).unwrap(); // check with no password is false. - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A) == Ok(false)); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A), + Ok(false) + )); // update the pw assert!(dbtxn .update_account_password(uuid1, TESTACCOUNT1_PASSWORD_A) .is_ok()); // Check it now works. - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A) == Ok(true)); - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_B) == Ok(false)); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A), + Ok(true) + )); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_B), + Ok(false) + )); // Update the pw assert!(dbtxn .update_account_password(uuid1, TESTACCOUNT1_PASSWORD_B) .is_ok()); // Check it matches. - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A) == Ok(false)); - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_B) == Ok(true)); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_A), + Ok(false) + )); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_B), + Ok(true) + )); // Check that updating the account does not break the password. ut1.displayname = "Test User Update".to_string(); dbtxn.update_account(&ut1, 0).unwrap(); - assert!(dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_B) == Ok(true)); + assert!(matches!( + dbtxn.check_account_password(uuid1, TESTACCOUNT1_PASSWORD_B), + Ok(true) + )); assert!(dbtxn.commit().is_ok()); } diff --git a/unix_integration/src/lib.rs b/unix_integration/src/lib.rs index cc91975a4..97645060c 100644 --- a/unix_integration/src/lib.rs +++ b/unix_integration/src/lib.rs @@ -17,8 +17,6 @@ extern crate tracing; #[macro_use] extern crate rusqlite; -#[cfg(target_family = "unix")] -pub mod cache; #[cfg(target_family = "unix")] pub mod client; #[cfg(target_family = "unix")] @@ -26,7 +24,9 @@ pub mod client_sync; #[cfg(target_family = "unix")] pub mod constants; #[cfg(target_family = "unix")] -pub(crate) mod db; +pub mod db; +#[cfg(target_family = "unix")] +pub mod resolver; #[cfg(all(target_family = "unix", feature = "selinux"))] pub mod selinux_util; #[cfg(target_family = "unix")] diff --git a/unix_integration/src/cache.rs b/unix_integration/src/resolver.rs similarity index 97% rename from unix_integration/src/cache.rs rename to unix_integration/src/resolver.rs index 493b4010d..7905f7571 100644 --- a/unix_integration/src/cache.rs +++ b/unix_integration/src/resolver.rs @@ -12,8 +12,9 @@ use lru::LruCache; use reqwest::StatusCode; use tokio::sync::{Mutex, RwLock}; -use crate::db::Db; -use crate::unix_config::{HomeAttr, TpmPolicy, UidAttr}; +use crate::db::{Cache, CacheTxn, Db}; + +use crate::unix_config::{HomeAttr, UidAttr}; use crate::unix_proto::{HomeDirectoryInfo, NssGroup, NssUser}; // use crate::unix_passwd::{EtcUser, EtcGroup}; @@ -34,7 +35,7 @@ enum CacheState { } #[derive(Debug)] -pub struct CacheLayer { +pub struct Resolver { db: Db, client: RwLock, state: Mutex, @@ -60,12 +61,14 @@ impl ToString for Id { } } -impl CacheLayer { - // TODO: Could consider refactoring this to be better ... +impl Resolver { #[allow(clippy::too_many_arguments)] pub async fn new( + db: Db, // need db path - path: &str, + // path: &str, + // tpm_policy: &TpmPolicy, + // cache timeout timeout_seconds: u64, // @@ -78,15 +81,12 @@ impl CacheLayer { uid_attr_map: UidAttr, gid_attr_map: UidAttr, allow_id_overrides: Vec, - tpm_policy: &TpmPolicy, ) -> Result { - let db = Db::new(path, tpm_policy)?; - // setup and do a migrate. { let dbtxn = db.write().await; - dbtxn.migrate()?; - dbtxn.commit()?; + dbtxn.migrate().map_err(|_| ())?; + dbtxn.commit().map_err(|_| ())?; } if pam_allow_groups.is_empty() { @@ -95,7 +95,7 @@ impl CacheLayer { // We assume we are offline at start up, and we mark the next "online check" as // being valid from "now". - Ok(CacheLayer { + Ok(Resolver { db, client: RwLock::new(client), state: Mutex::new(CacheState::OfflineNextCheck(SystemTime::now())), @@ -137,24 +137,27 @@ impl CacheLayer { let mut nxcache_txn = self.nxcache.lock().await; nxcache_txn.clear(); let dbtxn = self.db.write().await; - dbtxn.clear_cache().and_then(|_| dbtxn.commit()) + dbtxn.clear().and_then(|_| dbtxn.commit()).map_err(|_| ()) } pub async fn invalidate(&self) -> Result<(), ()> { let mut nxcache_txn = self.nxcache.lock().await; nxcache_txn.clear(); let dbtxn = self.db.write().await; - dbtxn.invalidate().and_then(|_| dbtxn.commit()) + dbtxn + .invalidate() + .and_then(|_| dbtxn.commit()) + .map_err(|_| ()) } async fn get_cached_usertokens(&self) -> Result, ()> { let dbtxn = self.db.write().await; - dbtxn.get_accounts() + dbtxn.get_accounts().map_err(|_| ()) } async fn get_cached_grouptokens(&self) -> Result, ()> { let dbtxn = self.db.write().await; - dbtxn.get_groups() + dbtxn.get_groups().map_err(|_| ()) } async fn set_nxcache(&self, id: &Id) { @@ -201,7 +204,7 @@ impl CacheLayer { // * uuid // Attempt to search these in the db. let dbtxn = self.db.write().await; - let r = dbtxn.get_account(account_id)?; + let r = dbtxn.get_account(account_id).map_err(|_| ())?; match r { Some((ut, ex)) => { @@ -252,7 +255,7 @@ impl CacheLayer { // * uuid // Attempt to search these in the db. let dbtxn = self.db.write().await; - let r = dbtxn.get_group(grp_id)?; + let r = dbtxn.get_group(grp_id).map_err(|_| ())?; match r { Some((ut, ex)) => { @@ -344,6 +347,7 @@ impl CacheLayer { dbtxn .update_account(token, offset.as_secs())) .and_then(|_| dbtxn.commit()) + .map_err(|_| ()) } async fn set_cache_grouptoken(&self, token: &UnixGroupToken) -> Result<(), ()> { @@ -359,16 +363,23 @@ impl CacheLayer { dbtxn .update_group(token, offset.as_secs()) .and_then(|_| dbtxn.commit()) + .map_err(|_| ()) } async fn delete_cache_usertoken(&self, a_uuid: &str) -> Result<(), ()> { let dbtxn = self.db.write().await; - dbtxn.delete_account(a_uuid).and_then(|_| dbtxn.commit()) + dbtxn + .delete_account(a_uuid) + .and_then(|_| dbtxn.commit()) + .map_err(|_| ()) } async fn delete_cache_grouptoken(&self, g_uuid: &str) -> Result<(), ()> { let dbtxn = self.db.write().await; - dbtxn.delete_group(g_uuid).and_then(|_| dbtxn.commit()) + dbtxn + .delete_group(g_uuid) + .and_then(|_| dbtxn.commit()) + .map_err(|_| ()) } async fn set_cache_userpassword(&self, a_uuid: &str, cred: &str) -> Result<(), ()> { @@ -376,6 +387,7 @@ impl CacheLayer { dbtxn .update_account_password(a_uuid, cred) .and_then(|x| dbtxn.commit().map(|_| x)) + .map_err(|_| ()) } async fn check_cache_userpassword(&self, a_uuid: &str, cred: &str) -> Result { @@ -383,6 +395,7 @@ impl CacheLayer { dbtxn .check_account_password(a_uuid, cred) .and_then(|x| dbtxn.commit().map(|_| x)) + .map_err(|_| ()) } async fn refresh_usertoken( diff --git a/unix_integration/tests/cache_layer_test.rs b/unix_integration/tests/cache_layer_test.rs index 824609264..99f90d9b1 100644 --- a/unix_integration/tests/cache_layer_test.rs +++ b/unix_integration/tests/cache_layer_test.rs @@ -6,11 +6,12 @@ use std::sync::atomic::{AtomicU16, Ordering}; use std::time::Duration; use kanidm_client::{KanidmClient, KanidmClientBuilder}; -use kanidm_unix_common::cache::{CacheLayer, Id}; 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::resolver::{Id, Resolver}; use kanidm_unix_common::unix_config::TpmPolicy; use kanidmd_core::config::{Configuration, IntegrationTestConfig, ServerRole}; use kanidmd_core::create_server_core; @@ -41,7 +42,7 @@ where Box::new(move |n| Box::pin(f(n))) } -async fn setup_test(fix_fn: Fixture) -> (CacheLayer, KanidmClient) { +async fn setup_test(fix_fn: Fixture) -> (Resolver, KanidmClient) { sketching::test_init(); let mut counter = 0; @@ -99,8 +100,14 @@ async fn setup_test(fix_fn: Fixture) -> (CacheLayer, KanidmClient) { .build() .expect("Failed to build client"); - let cachelayer = CacheLayer::new( + let db = Db::new( "", // The sqlite db path, this is in memory. + &TpmPolicy::default(), + ) + .expect("Failed to setup DB"); + + let cachelayer = Resolver::new( + db, 300, rsclient, vec!["allowed_group".to_string()], @@ -111,7 +118,6 @@ async fn setup_test(fix_fn: Fixture) -> (CacheLayer, KanidmClient) { DEFAULT_UID_ATTR_MAP, DEFAULT_GID_ATTR_MAP, vec!["masked_group".to_string()], - &TpmPolicy::default(), ) .await .expect("Failed to build cache layer.");