From 5e8e8590f1f10c8a430840b5bb2c49e4825a4260 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Sun, 16 Mar 2025 05:18:42 +0100 Subject: [PATCH] Massive refactor --- Cargo.lock | 1213 +++++------------ Cargo.toml | 5 +- src/context.rs | 81 ++ src/error.rs | 1 + src/lib.rs | 1 + src/lldap.rs | 186 ++- src/main.rs | 242 +--- src/resources.rs | 143 +- ...urces__tests__service_user_crd_output.snap | 10 +- 9 files changed, 755 insertions(+), 1127 deletions(-) create mode 100644 src/context.rs create mode 100644 src/error.rs diff --git a/Cargo.lock b/Cargo.lock index c48c4fb..ab7ab60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,60 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher", -] - -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug", -] - [[package]] name = "ahash" version = "0.8.11" @@ -144,119 +90,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener 5.4.0", + "event-listener", "event-listener-strategy", "futures-core", "pin-project-lite", ] -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.3.0", - "futures-lite 2.6.0", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite 2.6.0", - "once_cell", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite 2.6.0", - "parking", - "polling", - "rustix", - "slab", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.4.0", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-std" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" -dependencies = [ - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite 2.6.0", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - [[package]] name = "async-stream" version = "0.3.6" @@ -279,17 +118,11 @@ dependencies = [ "syn 2.0.99", ] -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" -version = "0.1.87" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", @@ -314,7 +147,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49fef586913a57ff189f25c9b3d034356a5bf6b3fa9a7f067588fe1698ba1f5d" dependencies = [ - "fastrand 2.3.0", + "fastrand", "gloo-timers", "tokio", ] @@ -331,15 +164,9 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base64" version = "0.13.1" @@ -399,19 +226,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite 2.6.0", - "piper", -] - [[package]] name = "bumpalo" version = "3.17.0" @@ -424,12 +238,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.10.0" @@ -466,15 +274,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -496,35 +295,12 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "const_fn" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e" - [[package]] name = "constant_time_eq" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "aes-gcm", - "base64 0.13.1", - "hkdf 0.10.0", - "hmac 0.10.1", - "percent-encoding", - "rand 0.8.5", - "sha2 0.9.9", - "time", - "version_check", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -560,12 +336,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -582,16 +352,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.0" @@ -602,46 +362,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - -[[package]] -name = "curl" -version = "0.4.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "curl-sys" -version = "0.4.78+curl-8.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.52.0", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -664,10 +384,10 @@ checksum = "c99c59968c8aa7f90d84240ab6ded4d3864125ce36b5b044554542cebc974946" dependencies = [ "cynic-proc-macros", "ref-cast", + "reqwest", "serde", "serde_json", "static_assertions", - "surf", "thiserror 1.0.69", ] @@ -786,12 +506,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "displaydoc" version = "0.1.7" @@ -889,12 +603,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.4.0" @@ -912,36 +620,16 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ - "event-listener 5.4.0", + "event-listener", "pin-project-lite", ] -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "flume" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" -dependencies = [ - "futures-core", - "futures-sink", - "spinning_top", -] - [[package]] name = "fnv" version = "1.0.7" @@ -954,6 +642,21 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1011,34 +714,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" -dependencies = [ - "fastrand 2.3.0", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.31" @@ -1125,13 +800,15 @@ dependencies = [ ] [[package]] -name = "ghash" +name = "getrandom" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ - "opaque-debug", - "polyval", + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -1152,6 +829,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "h2" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -1170,12 +866,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64 0.21.7", - "bytes 1.10.0", + "bytes", "headers-core", - "http 1.3.1", + "http", "httpdate", "mime", - "sha1 0.10.6", + "sha1", ] [[package]] @@ -1184,7 +880,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.3.1", + "http", ] [[package]] @@ -1193,22 +889,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest 0.9.0", - "hmac 0.10.1", -] - [[package]] name = "hkdf" version = "0.11.0" @@ -1216,17 +896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" dependencies = [ "digest 0.9.0", - "hmac 0.11.0", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac 0.10.0", - "digest 0.9.0", + "hmac", ] [[package]] @@ -1235,7 +905,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.0", + "crypto-mac", "digest 0.9.0", ] @@ -1259,24 +929,13 @@ dependencies = [ "windows", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes 1.10.0", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ - "bytes 1.10.0", + "bytes", "fnv", "itoa", ] @@ -1287,8 +946,8 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "bytes 1.10.0", - "http 1.3.1", + "bytes", + "http", ] [[package]] @@ -1297,49 +956,13 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "bytes 1.10.0", + "bytes", "futures-core", - "http 1.3.1", + "http", "http-body", "pin-project-lite", ] -[[package]] -name = "http-client" -version = "6.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1947510dc91e2bf586ea5ffb412caad7673264e14bb39fb9078da114a94ce1a5" -dependencies = [ - "async-std", - "async-trait", - "cfg-if", - "http-types", - "isahc", - "log", -] - -[[package]] -name = "http-types" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" -dependencies = [ - "anyhow", - "async-channel 1.9.0", - "async-std", - "base64 0.13.1", - "cookie", - "futures-lite 1.13.0", - "infer", - "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", -] - [[package]] name = "httparse" version = "1.10.1" @@ -1358,10 +981,11 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ - "bytes 1.10.0", + "bytes", "futures-channel", "futures-util", - "http 1.3.1", + "h2", + "http", "http-body", "httparse", "itoa", @@ -1377,10 +1001,10 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ad4b0a1e37510028bc4ba81d0e38d239c39671b0f0ce9e02dfa93a8133f7c08" dependencies = [ - "bytes 1.10.0", + "bytes", "futures-util", "headers", - "http 1.3.1", + "http", "hyper", "hyper-rustls", "hyper-util", @@ -1398,7 +1022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.3.1", + "http", "hyper", "hyper-util", "log", @@ -1423,16 +1047,32 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ - "bytes 1.10.0", + "bytes", "futures-channel", "futures-util", - "http 1.3.1", + "http", "http-body", "hyper", "pin-project-lite", @@ -1620,12 +1260,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "infer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" - [[package]] name = "insta" version = "1.42.2" @@ -1641,36 +1275,10 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.13" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "isahc" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" -dependencies = [ - "bytes 0.5.6", - "crossbeam-utils", - "curl", - "curl-sys", - "flume", - "futures-lite 1.13.0", - "http 0.2.12", - "log", - "once_cell", - "slab", - "sluice", - "tracing", - "tracing-futures", - "url", - "waker-fn", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "itoa" @@ -1756,12 +1364,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc2ed952042df20d15ac2fe9614d0ec14b6118eab89633985d4b36e688dccf1" dependencies = [ "base64 0.22.1", - "bytes 1.10.0", + "bytes", "chrono", "either", "futures", "home", - "http 1.3.1", + "http", "http-body", "http-body-util", "hyper", @@ -1794,7 +1402,7 @@ checksum = "ff0d0793db58e70ca6d689489183816cb3aa481673e7433dc618cf7e8007c675" dependencies = [ "chrono", "form_urlencoded", - "http 1.3.1", + "http", "json-patch", "k8s-openapi", "schemars", @@ -1846,15 +1454,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lalrpop-util" version = "0.22.1" @@ -1876,28 +1475,6 @@ version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" -[[package]] -name = "libnghttp2-sys" -version = "0.1.10+1.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1906,9 +1483,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" @@ -1921,6 +1498,7 @@ name = "lldap-controller" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "chrono", "cynic", "futures", @@ -1930,12 +1508,12 @@ dependencies = [ "lldap_auth", "passwords", "queries", - "rand 0.8.5", + "rand", + "reqwest", "schemars", "serde", "serde_json", "serde_yaml", - "surf", "thiserror 2.0.12", "tokio", "tracing", @@ -1954,7 +1532,7 @@ dependencies = [ "generic-array", "getrandom 0.2.15", "opaque-ke", - "rand 0.8.5", + "rand", "rust-argon2", "serde", "sha2 0.9.9", @@ -1976,9 +1554,6 @@ name = "log" version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" -dependencies = [ - "value-bag", -] [[package]] name = "logos" @@ -2034,16 +1609,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "miniz_oxide" version = "0.8.5" @@ -2064,6 +1629,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2116,15 +1698,41 @@ dependencies = [ "displaydoc 0.1.7", "generic-array", "generic-bytes", - "hkdf 0.11.0", - "hmac 0.11.0", - "rand 0.8.5", + "hkdf", + "hmac", + "rand", "serde", "subtle", "thiserror 1.0.69", "zeroize", ] +[[package]] +name = "openssl" +version = "0.10.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "openssl-probe" version = "0.1.6" @@ -2208,7 +1816,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -2313,49 +1921,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" -[[package]] -name = "polling" -version = "3.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "polyval" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug", - "universal-hash", -] - [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2411,19 +1982,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -2431,20 +1989,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", + "rand_chacha", "rand_core 0.6.4", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -2473,15 +2021,6 @@ dependencies = [ "getrandom 0.2.15", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "random-number" version = "0.1.9" @@ -2489,7 +2028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc8cdd49be664772ffc3dbfa743bb8c34b78f9cc6a9f50e56ae878546796067" dependencies = [ "proc-macro-hack", - "rand 0.8.5", + "rand", "random-number-macro-impl", ] @@ -2586,6 +2125,50 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e327e510263980e231de548a33e63d34962d29ae61b467389a1a09627a254" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "ring" version = "0.17.14" @@ -2617,20 +2200,11 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - [[package]] name = "rustix" -version = "0.38.44" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" dependencies = [ "bitflags", "errno", @@ -2802,21 +2376,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.219" @@ -2870,17 +2429,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2906,15 +2454,6 @@ dependencies = [ "unsafe-libyaml", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.6" @@ -2926,12 +2465,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - [[package]] name = "sha2" version = "0.9.9" @@ -2995,17 +2528,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "sluice" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" -dependencies = [ - "async-channel 1.9.0", - "futures-core", - "futures-io", -] - [[package]] name = "smallvec" version = "1.14.0" @@ -3022,85 +2544,18 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spinning_top" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" -dependencies = [ - "lock_api", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.10.0" @@ -3119,29 +2574,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "surf" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7" -dependencies = [ - "async-std", - "async-trait", - "cfg-if", - "encoding_rs", - "futures-util", - "getrandom 0.2.15", - "http-client", - "http-types", - "log", - "mime_guess", - "once_cell", - "pin-project-lite", - "serde", - "serde_json", - "web-sys", -] - [[package]] name = "syn" version = "1.0.109" @@ -3169,6 +2601,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -3181,6 +2616,40 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" +dependencies = [ + "fastrand", + "getrandom 0.3.1", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -3231,44 +2700,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.109", -] - [[package]] name = "tinystr" version = "0.7.6" @@ -3286,7 +2717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" dependencies = [ "backtrace", - "bytes 1.10.0", + "bytes", "libc", "mio", "parking_lot", @@ -3308,6 +2739,16 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.2" @@ -3324,7 +2765,7 @@ version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ - "bytes 1.10.0", + "bytes", "futures-core", "futures-sink", "pin-project-lite", @@ -3357,8 +2798,8 @@ checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ "base64 0.22.1", "bitflags", - "bytes 1.10.0", - "http 1.3.1", + "bytes", + "http", "http-body", "mime", "pin-project-lite", @@ -3412,16 +2853,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -3482,12 +2913,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - [[package]] name = "unicode-ident" version = "1.0.18" @@ -3500,16 +2925,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "universal-hash" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -3531,7 +2946,6 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde", ] [[package]] @@ -3552,12 +2966,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "value-bag" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" - [[package]] name = "vcpkg" version = "0.2.15" @@ -3570,12 +2978,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "want" version = "0.3.1" @@ -3597,6 +2999,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -3707,7 +3118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3716,7 +3127,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3725,13 +3136,42 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-result" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3740,7 +3180,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3749,14 +3189,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -3765,48 +3221,105 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 0a61f6c..a076863 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,7 @@ anyhow = "1.0.97" lldap_auth = { git = "https://github.com/lldap/lldap" } rand = { version = "0.8.0" } serde_json = "1.0.140" -surf = "2.3.2" -cynic = { workspace = true, features = ["http-surf"] } +cynic = { workspace = true, features = ["http-reqwest"] } tokio = { version = "1.44.0", features = ["full"] } kube = { version = "0.99.0", features = ["derive", "runtime"] } k8s-openapi = { version = "0.24.0", features = ["v1_31"] } @@ -31,6 +30,8 @@ tracing = "0.1.41" thiserror = "2.0.12" chrono = "0.4.40" passwords = "3.1.16" +async-trait = "0.1.88" +reqwest = "0.12.14" [dev-dependencies] insta = { workspace = true } diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..16628de --- /dev/null +++ b/src/context.rs @@ -0,0 +1,81 @@ +use async_trait::async_trait; +use k8s_openapi::api::core::v1::Secret; +use kube::{ + runtime::events::{Event, EventType, Recorder, Reporter}, + Resource, ResourceExt, +}; + +use crate::lldap::LldapConfig; + +pub struct Context { + pub client: kube::Client, + pub lldap_config: LldapConfig, + pub controller_name: String, + pub recorder: Recorder, +} + +impl Context { + pub fn new(controller_name: &str, client: kube::Client, lldap_config: LldapConfig) -> Self { + let reporter: Reporter = controller_name.into(); + let recorder = Recorder::new(client.clone(), reporter); + + Self { + client, + lldap_config, + controller_name: controller_name.into(), + recorder, + } + } +} + +#[async_trait] +pub trait ControllerEvents { + type Error; + + async fn secret_created(&self, obj: &T, secret: &Secret) -> Result<(), Self::Error> + where + T: Resource + Sync; + + async fn user_created(&self, obj: &T, username: &str) -> Result<(), Self::Error> + where + T: Resource + Sync; +} + +#[async_trait] +impl ControllerEvents for Recorder { + type Error = kube::Error; + + async fn secret_created(&self, obj: &T, secret: &Secret) -> Result<(), Self::Error> + where + T: Resource + Sync, + { + self.publish( + &Event { + type_: EventType::Normal, + reason: "SecretCreated".into(), + note: Some(format!("Created secret '{}'", secret.name_any())), + action: "SecretCreated".into(), + secondary: Some(secret.object_ref(&())), + }, + &obj.object_ref(&()), + ) + .await + } + + async fn user_created(&self, obj: &T, username: &str) -> Result<(), Self::Error> + where + T: Resource + Sync, + { + self.publish( + &Event { + type_: EventType::Normal, + reason: "UserCreated".into(), + note: Some(format!("Created user '{username}'")), + action: "UserCreated".into(), + secondary: None, + }, + &obj.object_ref(&()), + ) + .await + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..305f680 --- /dev/null +++ b/src/error.rs @@ -0,0 +1 @@ +pub type Result = anyhow::Result; diff --git a/src/lib.rs b/src/lib.rs index 122b454..c358c67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ +pub mod context; pub mod lldap; pub mod resources; diff --git a/src/lldap.rs b/src/lldap.rs index 017e1fe..d7f6131 100644 --- a/src/lldap.rs +++ b/src/lldap.rs @@ -1,49 +1,155 @@ -use anyhow::{anyhow, Context}; +use anyhow::Context; +use lldap_auth::opaque::AuthenticationError; +use lldap_auth::registration::ServerRegistrationStartResponse; use lldap_auth::{opaque, registration}; -use surf::Client; +use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION}; +use std::time::Duration; use tracing::debug; -pub async fn change_password(client: &Client, user_id: &str, password: &str) -> anyhow::Result<()> { - let mut rng = rand::rngs::OsRng; - let registration_start_request = - opaque::client::registration::start_registration(password.as_bytes(), &mut rng) - .context("Could not initiate password change")?; +use cynic::http::{CynicReqwestError, ReqwestExt}; +use cynic::{GraphQlError, GraphQlResponse, MutationBuilder, QueryBuilder}; +use lldap_auth::login::{ClientSimpleLoginRequest, ServerLoginResponse}; +use queries::{CreateUser, CreateUserVariables, ListUsers}; - let start_request = registration::ClientRegistrationStartRequest { - username: user_id.into(), - registration_start_request: registration_start_request.message, - }; +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("{0}")] + Cynic(#[from] CynicReqwestError), + #[error("{0}")] + Reqwest(#[from] reqwest::Error), + #[error("{0}")] + Authentication(#[from] AuthenticationError), + #[error("{0}")] + GraphQl(#[from] GraphQlError), +} - let mut response = client - .post("/auth/opaque/register/start") - .body_json(&start_request) - .map_err(|e| anyhow!(e))? - .await - .map_err(|e| anyhow!(e))?; +pub type Result = std::result::Result; - let response: registration::ServerRegistrationStartResponse = - response.body_json().await.map_err(|e| anyhow!(e))?; - - let registration_finish = opaque::client::registration::finish_registration( - registration_start_request.state, - response.registration_response, - &mut rng, - ) - .context("Error during password change")?; - - let request = registration::ClientRegistrationFinishRequest { - server_data: response.server_data, - registration_upload: registration_finish.message, - }; - - let _response = client - .post("/auth/opaque/register/finish") - .body_json(&request) - .map_err(|e| anyhow!(e))? - .await - .map_err(|e| anyhow!(e))?; - - debug!("Changed '{user_id}' password successfully"); +fn check_graphql_errors(response: &GraphQlResponse) -> Result<()> { + if let Some(errors) = &response.errors { + if !errors.is_empty() { + Err(errors.first().expect("Should not be empty").clone())?; + } + } Ok(()) } + +pub struct LldapConfig { + username: String, + password: String, + url: String, +} + +impl LldapConfig { + pub fn try_from_env() -> anyhow::Result { + Ok(Self { + username: std::env::var("LLDAP_USERNAME") + .context("Variable 'LLDAP_USERNAME' is not set or invalid")?, + password: std::env::var("LLDAP_PASSWORD") + .context("Variable 'LLDAP_PASSWORD' is not set or invalid")?, + url: std::env::var("LLDAP_URL") + .context("Variable 'LLDAP_URL' is not set or invalid")?, + }) + } + + pub async fn build_client(&self) -> Result { + let timeout = Duration::from_secs(1); + + let client = reqwest::ClientBuilder::new().timeout(timeout).build()?; + + let response: ServerLoginResponse = client + .post(format!("{}/auth/simple/login", self.url)) + .json(&ClientSimpleLoginRequest { + username: self.username.clone().into(), + password: self.password.clone(), + }) + .send() + .await? + .json() + .await?; + + let mut auth: HeaderValue = format!("Bearer {}", response.token) + .try_into() + .expect("Token comes from api and should be ascii"); + auth.set_sensitive(true); + let mut headers = HeaderMap::new(); + headers.insert(AUTHORIZATION, auth); + + let client = reqwest::ClientBuilder::new() + .timeout(timeout) + .default_headers(headers) + .build()?; + + Ok(LldapClient(client)) + } +} + +pub struct LldapClient(reqwest::Client); + +impl LldapClient { + pub async fn list_users(&self) -> Result> { + let operation = ListUsers::build(()); + let response = self.0.post("/api/graphql").run_graphql(operation).await?; + + check_graphql_errors(&response)?; + + Ok(response + .data + .expect("Data should be valid if there are no error") + .users + .into_iter() + .map(|user| user.id)) + } + + pub async fn create_user(&self, username: &str) -> Result<()> { + let operation = CreateUser::build(CreateUserVariables { id: username }); + + // TODO: Check the response? + let response = self.0.post("/api/graphql").run_graphql(operation).await?; + + check_graphql_errors(&response) + } + + pub async fn update_password(&self, username: &str, password: &str) -> Result<()> { + let mut rng = rand::rngs::OsRng; + let registration_start_request = + opaque::client::registration::start_registration(password.as_bytes(), &mut rng)?; + + let start_request = registration::ClientRegistrationStartRequest { + username: username.into(), + registration_start_request: registration_start_request.message, + }; + + let response: ServerRegistrationStartResponse = self + .0 + .post("/auth/opaque/register/start") + .json(&start_request) + .send() + .await? + .json() + .await?; + + let registration_finish = opaque::client::registration::finish_registration( + registration_start_request.state, + response.registration_response, + &mut rng, + )?; + + let request = registration::ClientRegistrationFinishRequest { + server_data: response.server_data, + registration_upload: registration_finish.message, + }; + + let _response = self + .0 + .post("/auth/opaque/register/finish") + .json(&request) + .send() + .await?; + + debug!("Changed '{username}' password successfully"); + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index bb96749..bf4979c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,215 +1,20 @@ -use std::{collections::BTreeMap, str::from_utf8, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; -use cynic::{http::SurfExt, MutationBuilder, QueryBuilder}; use futures::StreamExt; use k8s_openapi::api::core::v1::Secret; use kube::{ - api::{ObjectMeta, Patch, PatchParams, PostParams}, - runtime::{ - controller::Action, - events::{Event, EventType, Recorder, Reporter}, - Controller, - }, - Api, Client as KubeClient, Resource, + runtime::{controller::Action, Controller}, + Api, Client as KubeClient, }; -use lldap_auth::login::{ClientSimpleLoginRequest, ServerLoginResponse}; use lldap_controller::{ - lldap::change_password, - resources::{ServiceUser, ServiceUserStatus}, + context::Context, + lldap::LldapConfig, + resources::{self, ServiceUser}, }; -use passwords::PasswordGenerator; -use queries::{CreateUser, CreateUserVariables, ListUsers}; -use serde_json::json; -use surf::{Client as SurfClient, Config, Url}; -use tracing::{debug, info, instrument, warn}; +use tracing::{debug, info, warn}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry}; -#[derive(thiserror::Error, Debug)] -enum Error { - #[error("Failed to commit secret: {0}")] - Commit(#[source] kube::api::entry::CommitError), - #[error("{0}")] - Kube(#[source] kube::Error), - #[error("MissingObjectKey: {0}")] - MissingObjectKey(&'static str), -} - -type Result = std::result::Result; - -struct LldapConfig { - username: String, - password: String, - url: String, -} - -impl LldapConfig { - async fn client(&self) -> std::result::Result { - let client: SurfClient = Config::new() - .set_base_url(Url::parse(&self.url)?) - .set_timeout(Some(Duration::from_secs(1))) - .try_into()?; - - let response: ServerLoginResponse = client - .post("/auth/simple/login") - .body_json(&ClientSimpleLoginRequest { - username: self.username.clone().into(), - password: self.password.clone(), - })? - .recv_json() - .await?; - - let client = client - .config() - .clone() - .add_header("Authorization", format!("Bearer {}", response.token))? - .try_into()?; - - Ok(client) - } -} - -struct Data { - client: KubeClient, - lldap: LldapConfig, - recorder: Recorder, - pg: PasswordGenerator, -} - -const CONTROLLER_NAME: &str = "lldap.huizinga.dev"; - -#[instrument(skip(obj, ctx))] -async fn reconcile(obj: Arc, ctx: Arc) -> Result { - let name = obj - .metadata - .name - .clone() - .ok_or(Error::MissingObjectKey(".metadata.name"))?; - let secret_name = format!("{name}-lldap-credentials"); - let namespace = obj - .metadata - .namespace - .clone() - .ok_or(Error::MissingObjectKey(".metadata.namespace"))?; - let username = format!("{name}.{namespace}"); - let oref = obj.controller_owner_ref(&()).unwrap(); - - debug!(name, "reconcile request"); - - let client = &ctx.client; - let secrets = Api::::namespaced(client.clone(), &namespace); - - // TODO: Potentially issue: someone modifies the secret and removes the pass - let mut created = false; - let mut secret = secrets - .entry(&secret_name) - .await - .map_err(Error::Kube)? - .or_insert(|| { - debug!(name, secret_name, "Generating new secret"); - - let mut contents = BTreeMap::new(); - contents.insert("username".into(), username.clone()); - contents.insert("password".into(), ctx.pg.generate_one().unwrap()); - - created = true; - - Secret { - metadata: ObjectMeta { - owner_references: Some(vec![oref]), - ..Default::default() - }, - string_data: Some(contents), - ..Default::default() - } - }); - - secret - .commit(&PostParams { - dry_run: false, - field_manager: Some(CONTROLLER_NAME.into()), - }) - .await - .map_err(Error::Commit)?; - let secret = secret; - - if created { - debug!(name, "Sending SecretCreated event"); - - // The reason this is here instead of inside the or_insert is that we - // want to send the event _after_ it successfully committed. - // Also or_insert is not async! - ctx.recorder - .publish( - &Event { - type_: EventType::Normal, - reason: "SecretCreated".into(), - note: Some(format!("Created secret '{secret_name}'")), - action: "SecretCreated".into(), - secondary: Some(secret.get().object_ref(&())), - }, - &obj.object_ref(&()), - ) - .await - .map_err(Error::Kube)?; - } - - let lldap_client = ctx.lldap.client().await.unwrap(); - - let operation = ListUsers::build(()); - let response = lldap_client - .post("/api/graphql") - .run_graphql(operation) - .await - .unwrap(); - - if !response - .data - .expect("Should get data") - .users - .iter() - .any(|user| user.id == username) - { - let operation = CreateUser::build(CreateUserVariables { id: &username }); - lldap_client - .post("/api/graphql") - .run_graphql(operation) - .await - .unwrap(); - - ctx.recorder - .publish( - &Event { - type_: EventType::Normal, - reason: "UserCreated".into(), - note: Some(format!("Created user '{username}'")), - action: "UserCreated".into(), - secondary: None, - }, - &obj.object_ref(&()), - ) - .await - .map_err(Error::Kube)?; - } - - let password = secret.get().data.as_ref().unwrap().get("password").unwrap(); - let password = from_utf8(&password.0).unwrap(); - change_password(&lldap_client, &username, password) - .await - .unwrap(); - - let service_users = Api::::namespaced(client.clone(), &namespace); - let status = json!({ - "status": ServiceUserStatus { secret_created: secret.get().meta().creation_timestamp.as_ref().map(|ts| ts.0) } - }); - service_users - .patch_status(&name, &PatchParams::default(), &Patch::Merge(&status)) - .await - .map_err(Error::Kube)?; - - Ok(Action::requeue(Duration::from_secs(3600))) -} - -fn error_policy(_obj: Arc, err: &Error, _ctx: Arc) -> Action { +fn error_policy(_obj: Arc, err: &resources::Error, _ctx: Arc) -> Action { warn!("error: {}", err); Action::requeue(Duration::from_secs(5)) } @@ -219,27 +24,19 @@ async fn main() -> anyhow::Result<()> { let logger = tracing_subscriber::fmt::layer().json(); let env_filter = EnvFilter::try_from_default_env() .or_else(|_| EnvFilter::try_new("info")) - .unwrap(); + .expect("Fallback should be valid"); Registry::default().with(logger).with(env_filter).init(); info!("Starting controller"); - let lldap = LldapConfig { - username: std::env::var("LLDAP_USERNAME").unwrap(), - password: std::env::var("LLDAP_PASSWORD").unwrap(), - url: std::env::var("LLDAP_URL").unwrap(), - }; - let client = KubeClient::try_default().await?; - let reporter: Reporter = CONTROLLER_NAME.into(); - let recorder = Recorder::new(client.clone(), reporter); - - let pg = PasswordGenerator::new() - .length(32) - .uppercase_letters(true) - .strict(true); + let data = Context::new( + "lldap.huizinga.dev", + client.clone(), + LldapConfig::try_from_env()?, + ); let service_users = Api::::all(client.clone()); let secrets = Api::::all(client.clone()); @@ -247,16 +44,7 @@ async fn main() -> anyhow::Result<()> { Controller::new(service_users.clone(), Default::default()) .owns(secrets, Default::default()) .shutdown_on_signal() - .run( - reconcile, - error_policy, - Arc::new(Data { - client, - lldap, - recorder, - pg, - }), - ) + .run(ServiceUser::reconcile, error_policy, Arc::new(data)) .for_each(|res| async move { match res { Ok(obj) => debug!("reconciled {:?}", obj.0.name), diff --git a/src/resources.rs b/src/resources.rs index bb1528d..46b929f 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,7 +1,36 @@ +use std::collections::BTreeMap; +use std::str::from_utf8; +use std::sync::Arc; +use std::time::Duration; + use chrono::{DateTime, Utc}; -use kube::CustomResource; +use k8s_openapi::api::core::v1::Secret; +use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference; +use kube::api::{ObjectMeta, Patch, PatchParams, PostParams}; +use kube::runtime::controller::Action; +use kube::{Api, CustomResource, Resource}; +use passwords::PasswordGenerator; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use serde_json::json; +use tracing::{debug, instrument}; + +use crate::context::{Context, ControllerEvents}; +use crate::lldap; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Failed to commit: {0}")] + Commit(#[from] kube::api::entry::CommitError), + #[error("Kube api error: {0}")] + Kube(#[from] kube::Error), + #[error("LLDAP error: {0}")] + Lldap(#[from] lldap::Error), + #[error("MissingObjectKey: {0}")] + MissingObjectKey(&'static str), +} + +pub type Result = std::result::Result; #[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)] #[kube( @@ -15,8 +44,8 @@ use serde::{Deserialize, Serialize}; shortname = "lsu", doc = "Custom resource for managing Service Users inside of LLDAP", printcolumn = r#"{"name":"Manager", "type":"boolean", "description":"Can the service user manage passwords", "jsonPath":".spec.passwordManager"}"#, - printcolumn = r#"{"name":"Age", "type":"date", "jsonPath":".metadata.creationTimestamp"}"#, - printcolumn = r#"{"name":"Secret", "type":"date", "description":"Secret creation timestamp", "jsonPath":".status.secret_created"}"# + printcolumn = r#"{"name":"Password", "type":"date", "description":"Secret creation timestamp", "jsonPath":".status.secretCreated"}"#, + printcolumn = r#"{"name":"Age", "type":"date", "jsonPath":".metadata.creationTimestamp"}"# )] #[serde(rename_all = "camelCase")] pub struct ServiceUserSpec { @@ -27,10 +56,118 @@ pub struct ServiceUserSpec { } #[derive(Deserialize, Serialize, Clone, Default, Debug, JsonSchema)] +#[serde(rename_all = "camelCase")] pub struct ServiceUserStatus { pub secret_created: Option>, } +fn new_secret(username: &str, oref: OwnerReference) -> Secret { + let pg = PasswordGenerator::new() + .length(32) + .uppercase_letters(true) + .strict(true); + + let mut contents = BTreeMap::new(); + contents.insert("username".into(), username.into()); + contents.insert( + "password".into(), + pg.generate_one().expect("Settings should be valid"), + ); + + Secret { + metadata: ObjectMeta { + owner_references: Some(vec![oref]), + ..Default::default() + }, + string_data: Some(contents), + ..Default::default() + } +} + +impl ServiceUser { + #[instrument(skip(self, ctx))] + pub async fn reconcile(self: Arc, ctx: Arc) -> Result { + let name = self + .metadata + .name + .clone() + .ok_or(Error::MissingObjectKey(".metadata.name"))?; + let namespace = self + .metadata + .namespace + .clone() + .ok_or(Error::MissingObjectKey(".metadata.namespace"))?; + let oref = self + .controller_owner_ref(&()) + .expect("Field should populated by apiserver"); + + debug!(name, "reconcile request"); + + let secret_name = format!("{name}-lldap-credentials"); + let username = format!("{name}.{namespace}"); + + let client = &ctx.client; + let secrets = Api::::namespaced(client.clone(), &namespace); + + // TODO: Potentially issue: someone modifies the secret and removes the pass + let mut created = false; + let mut secret = secrets + .entry(&secret_name) + .await? + .and_modify(|_| { + debug!(name, secret_name, "Secret already exists"); + }) + .or_insert(|| { + created = true; + debug!(name, secret_name, "Generating new secret"); + + new_secret(&username, oref) + }); + + secret + .commit(&PostParams { + dry_run: false, + field_manager: Some(ctx.controller_name.clone()), + }) + .await?; + let secret = secret; + + if created { + // The reason this is here instead of inside the or_insert is that we + // want to send the event _after_ it successfully committed. + // Also or_insert is not async! + ctx.recorder + .secret_created(self.as_ref(), secret.get()) + .await?; + } + + let lldap_client = ctx.lldap_config.build_client().await?; + + if lldap_client.list_users().await?.any(|id| id == username) { + debug!(name, username, "User already exists"); + } else { + debug!(name, username, "Creating new user"); + + lldap_client.create_user(&username).await?; + ctx.recorder.user_created(self.as_ref(), &username).await?; + } + + let password = secret.get().data.as_ref().unwrap().get("password").unwrap(); + let password = from_utf8(&password.0).unwrap(); + lldap_client.update_password(&username, password).await?; + + let service_users = Api::::namespaced(client.clone(), &namespace); + let status = json!({ + "status": ServiceUserStatus { secret_created: secret.get().meta().creation_timestamp.as_ref().map(|ts| ts.0) } + }); + service_users + .patch_status(&name, &PatchParams::default(), &Patch::Merge(&status)) + .await?; + + Ok(Action::requeue(Duration::from_secs(3600))) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/snapshots/lldap_controller__resources__tests__service_user_crd_output.snap b/src/snapshots/lldap_controller__resources__tests__service_user_crd_output.snap index b6a1745..82994df 100644 --- a/src/snapshots/lldap_controller__resources__tests__service_user_crd_output.snap +++ b/src/snapshots/lldap_controller__resources__tests__service_user_crd_output.snap @@ -22,13 +22,13 @@ spec: jsonPath: ".spec.passwordManager" name: Manager type: boolean + - description: Secret creation timestamp + jsonPath: ".status.secretCreated" + name: Password + type: date - jsonPath: ".metadata.creationTimestamp" name: Age type: date - - description: Secret creation timestamp - jsonPath: ".status.secret_created" - name: Secret - type: date name: v1 schema: openAPIV3Schema: @@ -48,7 +48,7 @@ spec: status: nullable: true properties: - secret_created: + secretCreated: format: date-time nullable: true type: string