mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
On login pw upgrade (#315)
Fixes #295 on login pw upgrade. This adds support for SSHA512 to be imported at the request of @colbyprior, and adds a delayed action queue so that events can be run after-the-fact so that authentication does not need to exist under the write path.
This commit is contained in:
parent
e6e89ed13a
commit
dbfe87e675
403
Cargo.lock
generated
403
Cargo.lock
generated
|
@ -78,7 +78,7 @@ dependencies = [
|
|||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding 2.1.0",
|
||||
"percent-encoding",
|
||||
"v_htmlescape",
|
||||
]
|
||||
|
||||
|
@ -118,7 +118,7 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"log",
|
||||
"mime",
|
||||
"percent-encoding 2.1.0",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"rand",
|
||||
"regex",
|
||||
|
@ -191,9 +191,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "actix-service"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3e4fc95dfa7e24171b2d0bb46b85f8ab0e8499e4e3caec691fc4ea65c287564"
|
||||
checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"pin-project",
|
||||
|
@ -314,7 +314,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"time 0.1.43",
|
||||
"url 2.1.1",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -402,16 +402,63 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.6.2"
|
||||
name = "async-executor"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00d68a33ebc8b57800847d00787307f84a562224a14db069b0acefe4c2abbf5d"
|
||||
checksum = "90f47c78ea98277cb1f5e6f60ba4fc762f5eafe9f6511bc2f7dfd8b75c225650"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"futures-lite",
|
||||
"multitask",
|
||||
"parking 1.0.6",
|
||||
"scoped-tls",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae22a338d28c75b53702b66f77979062cb29675db376d99e451af4fa79dedb3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"parking 2.0.0",
|
||||
"polling",
|
||||
"socket2",
|
||||
"vec-arena",
|
||||
"wepoll-sys-stjepang",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-mutex"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20e85981fc34e84cdff3fc2c9219189752633fdc538a06df8b5ac45b68a4f3a9"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c8da367da62b8ff2313c406c9ac091c1b31d67a165becdd2de380d846260f7"
|
||||
dependencies = [
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-mutex",
|
||||
"async-task",
|
||||
"blocking",
|
||||
"crossbeam-utils",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
|
@ -420,7 +467,6 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
"smol",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
|
@ -432,9 +478,9 @@ checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3"
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.36"
|
||||
version = "0.1.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a265e3abeffdce30b2e26b7a11b222fe37c6067404001b434101457d0385eb92"
|
||||
checksum = "6e1a4a2f97ce50c9d0282c1468816208588441492b40d813b2e0419c22c05e7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -460,9 +506,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "awc"
|
||||
|
@ -481,7 +527,7 @@ dependencies = [
|
|||
"log",
|
||||
"mime",
|
||||
"openssl",
|
||||
"percent-encoding 2.1.0",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -581,15 +627,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "0.4.7"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2468ff7bf85066b4a3678fede6fe66db31846d753ff0adfbfab2c6a6e81612b"
|
||||
checksum = "ea5800d29218fea137b0880387e5948694a23c93fcdde157006966693a865c7c"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"atomic-waker",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"parking",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
|
@ -681,9 +726,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.58"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
|
||||
checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -693,9 +738,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.13"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
|
||||
checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
|
@ -704,9 +749,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.1"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
|
@ -749,9 +794,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.0"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e296417c8154304ac70aceda41f05318f986f7c0c767bcb0a2366fbb890e78e1"
|
||||
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
|
||||
dependencies = [
|
||||
"cache-padded",
|
||||
]
|
||||
|
@ -782,40 +827,31 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
|
||||
dependencies = [
|
||||
"time 0.1.43",
|
||||
"url 1.7.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1373a16a4937bc34efec7b391f9c1500c30b8478a701a4f44c9165cc0475a6e0"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time 0.2.16",
|
||||
"version_check 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie_store"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b2a7e5bf5517bf3c3f4358f13d3ec2092419ac2332aa8593605c957da73d491"
|
||||
checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3"
|
||||
dependencies = [
|
||||
"cookie 0.12.0",
|
||||
"idna 0.2.0",
|
||||
"cookie",
|
||||
"idna",
|
||||
"log",
|
||||
"publicsuffix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"time 0.1.43",
|
||||
"url 2.1.1",
|
||||
"time 0.2.16",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1094,9 +1130,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
|
|||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
|
@ -1109,9 +1145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "enum-as-inner"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc4bfcfacb61d231109d1d55202c1f33263319668b168843e02ad4652725ec9c"
|
||||
checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
@ -1134,18 +1170,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.12.2"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd"
|
||||
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
|
||||
dependencies = [
|
||||
"version_check 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "298f00c3b04c1d9b4cb86aefaaa35348af0957d98b30a5306fc635f8e718923d"
|
||||
checksum = "e1cd41440ae7e4734bbd42302f63eaba892afc93a3912dad84006247f0dedb0e"
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
|
@ -1199,15 +1235,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.3.3"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36a9cb09840f81cd211e435d00a4e487edd263dc3c8ff815c32dd76ad668ebed"
|
||||
checksum = "4bd3bdaaf0a72155260a1c098989b60db1cbb22d6a628e64f16237aa4da93cc7"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
|
||||
checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crc32fast",
|
||||
|
@ -1302,15 +1338,15 @@ checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
|||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe71459749b2e8e66fb95df721b22fa08661ad384a0c5b519e11d3893b4692a"
|
||||
checksum = "97999970129b808f0ccba93211201d431fcc12d7e1ffae03a61b5cedd1a7ced2"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"parking 2.0.0",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
@ -1424,9 +1460,9 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb"
|
||||
checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"autocfg",
|
||||
|
@ -1552,17 +1588,6 @@ dependencies = [
|
|||
"time 0.1.43",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.0"
|
||||
|
@ -1576,9 +1601,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7"
|
||||
checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -1611,6 +1636,12 @@ dependencies = [
|
|||
"winreg 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
|
@ -1637,9 +1668,9 @@ checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.42"
|
||||
version = "0.3.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52732a3d3ad72c58ad2dc70624f9c17b46ecd0943b9a4f1ee37c4c18c5d983e2"
|
||||
checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -1653,11 +1684,12 @@ dependencies = [
|
|||
"actix-rt",
|
||||
"actix-session",
|
||||
"actix-web",
|
||||
"async-std",
|
||||
"base64 0.12.3",
|
||||
"cargo-husky",
|
||||
"chrono",
|
||||
"concread",
|
||||
"cookie 0.14.2",
|
||||
"cookie",
|
||||
"criterion",
|
||||
"crossbeam",
|
||||
"env_logger",
|
||||
|
@ -1829,9 +1861,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.73"
|
||||
version = "0.2.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
|
||||
checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
|
||||
|
||||
[[package]]
|
||||
name = "libnss"
|
||||
|
@ -1947,9 +1979,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
|
||||
checksum = "4d7559a8a40d0f97e1edea3220f698f78b1c5ab67532e49f68fde3910323b722"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
@ -2018,6 +2050,17 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multitask"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c09c35271e7dcdb5f709779111f2c8e8ab8e06c1b587c1c6a9e179d865aaa5b4"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.4"
|
||||
|
@ -2169,9 +2212,9 @@ checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
|
||||
checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
|
@ -2244,6 +2287,12 @@ version = "1.0.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.10.2"
|
||||
|
@ -2313,12 +2362,6 @@ dependencies = [
|
|||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
|
@ -2327,18 +2370,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
|||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17"
|
||||
checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7"
|
||||
checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2376,16 +2419,28 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.8"
|
||||
name = "polling"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||
checksum = "9e09dffb745feffca5be3dea51c02b7b368c4597ab0219a82acaf9799ab3e0d1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wepoll-sys-stjepang",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
|
@ -2396,22 +2451,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn-mid",
|
||||
"version_check 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.16"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
|
||||
checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
|
@ -2435,10 +2488,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b"
|
||||
dependencies = [
|
||||
"error-chain",
|
||||
"idna 0.2.0",
|
||||
"idna",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"url 2.1.1",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2598,13 +2651,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.10.6"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b82c9238b305f26f53443e3a4bc8528d64b8d0bee408ec949eb7bf5635ec680"
|
||||
checksum = "12427a5577082c24419c9c417db35cfeb65962efc7675bb6b0d5f1f9d315bfe6"
|
||||
dependencies = [
|
||||
"base64 0.12.3",
|
||||
"bytes",
|
||||
"cookie 0.12.0",
|
||||
"cookie",
|
||||
"cookie_store",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
|
@ -2613,21 +2666,22 @@ dependencies = [
|
|||
"http-body",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"percent-encoding 2.1.0",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"time 0.1.43",
|
||||
"time 0.2.16",
|
||||
"tokio",
|
||||
"tokio-tls",
|
||||
"url 2.1.1",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
|
@ -2798,9 +2852,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.114"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
|
||||
checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -2817,9 +2871,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.114"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
|
||||
checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2828,9 +2882,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.56"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3"
|
||||
checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -2846,7 +2900,7 @@ dependencies = [
|
|||
"dtoa",
|
||||
"itoa",
|
||||
"serde",
|
||||
"url 2.1.1",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2878,9 +2932,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
|
||||
checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
|
@ -2894,34 +2948,13 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f"
|
||||
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"blocking",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"scoped-tls",
|
||||
"slab",
|
||||
"socket2",
|
||||
"wepoll-sys-stjepang",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.12"
|
||||
|
@ -3017,9 +3050,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
|||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c"
|
||||
checksum = "de5472fb24d7e80ae84a7801b7978f95a19ec32cb1876faea59ab711eb901976"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lazy_static",
|
||||
|
@ -3028,9 +3061,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118"
|
||||
checksum = "1e0eb37335aeeebe51be42e2dc07f031163fbabfa6ac67d7ea68b5c2f68d5f99"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
@ -3041,26 +3074,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.35"
|
||||
version = "1.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb7f4c519df8c117855e19dd8cc851e89eb746fe7a73f0157e0d95fdec5369b0"
|
||||
checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn-mid"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
|
@ -3203,9 +3225,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed"
|
||||
checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
|
@ -3307,9 +3329,9 @@ checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860"
|
|||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.17"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbdf4ccd1652592b01286a5dbe1e2a77d78afaa34beadd9872a5f7396f92aaa9"
|
||||
checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"log",
|
||||
|
@ -3318,9 +3340,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.11"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94ae75f0d28ae10786f3b1895c55fe72e79928fd5ccdebb5438c75e93fec178f"
|
||||
checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
@ -3335,14 +3357,14 @@ dependencies = [
|
|||
"enum-as-inner",
|
||||
"failure",
|
||||
"futures",
|
||||
"idna 0.2.0",
|
||||
"idna",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"url 2.1.1",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3427,26 +3449,15 @@ version = "0.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
dependencies = [
|
||||
"idna 0.1.5",
|
||||
"matches",
|
||||
"percent-encoding 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
||||
dependencies = [
|
||||
"idna 0.2.0",
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding 2.1.0",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3506,6 +3517,12 @@ version = "0.2.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
|
||||
|
||||
[[package]]
|
||||
name = "vec-arena"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cb18268690309760d59ee1a9b21132c126ba384f374c59a94db4bc03adeb561"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
|
@ -3553,9 +3570,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.65"
|
||||
version = "0.2.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3edbcc9536ab7eababcc6d2374a0b7bfe13a2b6d562c5e07f370456b1a8f33d"
|
||||
checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"serde",
|
||||
|
@ -3565,9 +3582,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.65"
|
||||
version = "0.2.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ed2fb8c84bfad20ea66b26a3743f3e7ba8735a69fe7d95118c33ec8fc1244d"
|
||||
checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
@ -3580,9 +3597,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.15"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41ad6e4e8b2b7f8c90b6e09a9b590ea15cb0d1dbe28502b5a405cd95d1981671"
|
||||
checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
|
@ -3592,9 +3609,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.65"
|
||||
version = "0.2.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb071268b031a64d92fc6cf691715ca5a40950694d8f683c5bb43db7c730929e"
|
||||
checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -3602,9 +3619,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.65"
|
||||
version = "0.2.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf592c807080719d1ff2f245a687cbadb3ed28b2077ed7084b47aba8b691f2c6"
|
||||
checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -3615,15 +3632,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.65"
|
||||
version = "0.2.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b6c0220ded549d63860c78c38f3bcc558d1ca3f4efa74942c536ddbbb55e87"
|
||||
checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.42"
|
||||
version = "0.3.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8be2398f326b7ba09815d0b403095f34dd708579220d099caae89be0b32137b2"
|
||||
checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
9
GETTING_STARTED.md
Normal file
9
GETTING_STARTED.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
## Getting Started (for Administrators)
|
||||
|
||||
If you want to deploy kanidm, or to see what it can do, you should read the [kanidm book]
|
||||
|
||||
[kanidm book]: https://github.com/kanidm/kanidm/blob/master/kanidm_book/src/SUMMARY.md
|
||||
|
||||
## Getting Started (for Developers)
|
||||
|
||||
See the README.md file.
|
28
README.md
28
README.md
|
@ -16,34 +16,25 @@ Today the project is still under heavy development to achieve these goals - we d
|
|||
functional release before early 2020. It is important to note that not all needed security features
|
||||
of the system have been completed yet!
|
||||
|
||||
## Code of Conduct
|
||||
## Code of Conduct / Ethics
|
||||
|
||||
See our [code of conduct]
|
||||
|
||||
[code of conduct]: https://github.com/kanidm/kanidm/blob/master/CODE_OF_CONDUCT.md
|
||||
|
||||
## Ethics / Rights
|
||||
|
||||
See our documentation on [rights and ethics]
|
||||
|
||||
[code of conduct]: https://github.com/kanidm/kanidm/blob/master/CODE_OF_CONDUCT.md
|
||||
[rights and ethics]: https://github.com/kanidm/kanidm/blob/master/ethics/README.md
|
||||
|
||||
## Some key ideas
|
||||
|
||||
* All people should be respected and able to be respresented securely.
|
||||
* Devices represent users and their identities - they are part of the authentication.
|
||||
* Human error occurs - we should be designed to minimise human mistakes and empower people.
|
||||
* The system should be easy to understand and reason about for users and admins.
|
||||
|
||||
## Documentation
|
||||
## Documentation / Getting Started / Install
|
||||
|
||||
If you want to deploy kanidm, or to see what it can do, you should read the [kanidm book]
|
||||
|
||||
[kanidm book]: https://github.com/kanidm/kanidm/blob/master/kanidm_book/src/SUMMARY.md
|
||||
|
||||
## Getting in Contact
|
||||
## Getting in Contact / Questions
|
||||
|
||||
We have a [gitter community channel] where we can talk. Firstyear is also happy to answer questions via email, which can be found on their github profile.
|
||||
We have a [gitter community channel] where we can talk. Firstyear is also happy to
|
||||
answer questions via email, which can be found on their github profile.
|
||||
|
||||
[gitter community channel]: https://gitter.im/kanidm/community
|
||||
|
||||
|
@ -70,6 +61,13 @@ We have a [gitter community channel] where we can talk. Firstyear is also happy
|
|||
* Generic database: We don't want to be another NoSQL database, we want to be an IDM solution.
|
||||
* Being LDAP/GSSAPI/Kerberos: These are all legacy protocols that are hard to use and confine our thinking - we should avoid "being like them".
|
||||
|
||||
## Some key ideas
|
||||
|
||||
* All people should be respected and able to be respresented securely.
|
||||
* Devices represent users and their identities - they are part of the authentication.
|
||||
* Human error occurs - we should be designed to minimise human mistakes and empower people.
|
||||
* The system should be easy to understand and reason about for users and admins.
|
||||
|
||||
## Development and Testing
|
||||
|
||||
### Designs
|
||||
|
|
|
@ -102,6 +102,7 @@ pub enum OperationError {
|
|||
PasswordBadListed,
|
||||
CryptographyError,
|
||||
ResourceLimit,
|
||||
QueueDisconnected,
|
||||
}
|
||||
|
||||
impl PartialEq for OperationError {
|
||||
|
|
|
@ -34,6 +34,8 @@ actix-web = { version = "2.0", features = ["openssl"] }
|
|||
actix-session = "0.3"
|
||||
actix-files = "0.2"
|
||||
|
||||
async-std = "1.6"
|
||||
|
||||
log = "0.4"
|
||||
env_logger = "0.7"
|
||||
rand = "0.7"
|
||||
|
|
|
@ -11,6 +11,7 @@ pub struct DbCidV1 {
|
|||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum DbPasswordV1 {
|
||||
PBKDF2(usize, Vec<u8>, Vec<u8>),
|
||||
SSHA512(Vec<u8>, Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
|
@ -36,7 +36,7 @@ use crate::audit::AuditScope;
|
|||
use crate::be::{Backend, BackendTransaction, FsType};
|
||||
use crate::crypto::setup_tls;
|
||||
use crate::filter::{Filter, FilterInvalid};
|
||||
use crate::idm::server::IdmServer;
|
||||
use crate::idm::server::{IdmServer, IdmServerDelayed};
|
||||
use crate::interval::IntervalActor;
|
||||
use crate::ldap::LdapServer;
|
||||
use crate::schema::Schema;
|
||||
|
@ -1301,7 +1301,7 @@ fn setup_qs_idms(
|
|||
audit: &mut AuditScope,
|
||||
be: Backend,
|
||||
schema: Schema,
|
||||
) -> Result<(QueryServer, IdmServer), OperationError> {
|
||||
) -> Result<(QueryServer, IdmServer, IdmServerDelayed), OperationError> {
|
||||
// Create a query_server implementation
|
||||
let query_server = QueryServer::new(be, schema);
|
||||
|
||||
|
@ -1317,9 +1317,9 @@ fn setup_qs_idms(
|
|||
|
||||
// We generate a SINGLE idms only!
|
||||
|
||||
let idms = IdmServer::new(query_server.clone());
|
||||
let (idms, idms_delayed) = IdmServer::new(query_server.clone());
|
||||
|
||||
Ok((query_server, idms))
|
||||
Ok((query_server, idms, idms_delayed))
|
||||
}
|
||||
|
||||
pub fn backup_server_core(config: &Configuration, dst_path: &str) {
|
||||
|
@ -1389,7 +1389,7 @@ pub fn restore_server_core(config: &Configuration, dst_path: &str) {
|
|||
|
||||
info!("Attempting to init query server ...");
|
||||
|
||||
let (qs, _idms) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
let (qs, _idms, _idms_delayed) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
audit.write_log();
|
||||
|
@ -1457,7 +1457,7 @@ pub fn reindex_server_core(config: &Configuration) {
|
|||
|
||||
eprintln!("Attempting to init query server ...");
|
||||
|
||||
let (qs, _idms) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
let (qs, _idms, _idms_delayed) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
audit.write_log();
|
||||
|
@ -1508,7 +1508,7 @@ pub fn domain_rename_core(config: &Configuration, new_domain_name: &str) {
|
|||
}
|
||||
};
|
||||
// setup the qs - *with* init of the migrations and schema.
|
||||
let (qs, _idms) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
let (qs, _idms, _idms_delayed) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
audit.write_log();
|
||||
|
@ -1606,7 +1606,7 @@ pub fn recover_account_core(config: &Configuration, name: &str, password: &str)
|
|||
}
|
||||
};
|
||||
// setup the qs - *with* init of the migrations and schema.
|
||||
let (_qs, idms) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
let (_qs, idms, _idms_delayed) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
audit.write_log();
|
||||
|
@ -1689,7 +1689,7 @@ pub async fn create_server_core(config: Configuration) -> Result<ServerCtx, ()>
|
|||
}
|
||||
};
|
||||
// Start the IDM server.
|
||||
let (qs, idms) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
let (qs, idms, mut idms_delayed) = match setup_qs_idms(&mut audit, be, schema) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
audit.write_log();
|
||||
|
@ -1756,6 +1756,9 @@ pub async fn create_server_core(config: Configuration) -> Result<ServerCtx, ()>
|
|||
let server_write_addr =
|
||||
QueryServerWriteV1::start(log_tx.clone(), config.log_level, qs, idms_arc);
|
||||
|
||||
// TODO #314: For now we just drop everything from the delayed queue until we rewrite to be async.
|
||||
tokio::spawn(async move { idms_delayed.temp_drop_all().await; });
|
||||
|
||||
// Setup timed events associated to the write thread
|
||||
let _int_addr = IntervalActor::new(server_write_addr.clone()).start();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::be::dbvalue::{DbCredV1, DbPasswordV1};
|
|||
use kanidm_proto::v1::OperationError;
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkcs5::pbkdf2_hmac;
|
||||
use openssl::sha::Sha512;
|
||||
use rand::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -20,6 +21,9 @@ const PBKDF2_SALT_LEN: usize = 24;
|
|||
const PBKDF2_KEY_LEN: usize = 64;
|
||||
const PBKDF2_IMPORT_MIN_LEN: usize = 32;
|
||||
|
||||
const DS_SSHA512_SALT_LEN: usize = 8;
|
||||
const DS_SSHA512_HASH_LEN: usize = 64;
|
||||
|
||||
// These are in order of "relative" strength.
|
||||
/*
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -38,6 +42,8 @@ pub enum Policy {
|
|||
enum KDF {
|
||||
// cost, salt, hash
|
||||
PBKDF2(usize, Vec<u8>, Vec<u8>),
|
||||
// salt hash
|
||||
SSHA512(Vec<u8>, Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -53,6 +59,9 @@ impl TryFrom<DbPasswordV1> for Password {
|
|||
DbPasswordV1::PBKDF2(c, s, h) => Ok(Password {
|
||||
material: KDF::PBKDF2(c, s, h),
|
||||
}),
|
||||
DbPasswordV1::SSHA512(s, h) => Ok(Password {
|
||||
material: KDF::SSHA512(s, h),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +97,18 @@ impl TryFrom<&str> for Password {
|
|||
}
|
||||
}
|
||||
|
||||
// Test 389ds formats
|
||||
if let Some(ds_ssha512) = value.strip_prefix("{SSHA512}") {
|
||||
let sh = base64::decode(ds_ssha512).map_err(|_| ())?;
|
||||
let (h, s) = sh.split_at(DS_SSHA512_HASH_LEN);
|
||||
if s.len() != DS_SSHA512_SALT_LEN {
|
||||
return Err(());
|
||||
}
|
||||
return Ok(Password {
|
||||
material: KDF::SSHA512(s.to_vec(), h.to_vec()),
|
||||
});
|
||||
}
|
||||
|
||||
// Nothing matched to this point.
|
||||
Err(())
|
||||
}
|
||||
|
@ -160,6 +181,13 @@ impl Password {
|
|||
&chal_key == key
|
||||
})
|
||||
}
|
||||
KDF::SSHA512(salt, key) => {
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(cleartext.as_bytes());
|
||||
hasher.update(&salt);
|
||||
let r = hasher.finish();
|
||||
Ok(key == &(r.to_vec()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,6 +196,14 @@ impl Password {
|
|||
KDF::PBKDF2(cost, salt, hash) => {
|
||||
DbPasswordV1::PBKDF2(*cost, salt.clone(), hash.clone())
|
||||
}
|
||||
KDF::SSHA512(salt, hash) => DbPasswordV1::SSHA512(salt.clone(), hash.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn requires_upgrade(&self) -> bool {
|
||||
match &self.material {
|
||||
KDF::PBKDF2(_, _, _) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -352,4 +388,14 @@ mod tests {
|
|||
let r = Password::try_from(im_pw).expect("Failed to parse");
|
||||
assert!(r.verify(password).unwrap_or(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_password_from_ds_ssha512() {
|
||||
let im_pw = "{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM";
|
||||
let password = "password";
|
||||
let r = Password::try_from(im_pw).expect("Failed to parse");
|
||||
// Known weak, require upgrade.
|
||||
assert!(r.requires_upgrade());
|
||||
assert!(r.verify(password).unwrap_or(false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,6 +200,31 @@ impl Account {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_credential_pw(
|
||||
&self,
|
||||
cleartext: &str,
|
||||
appid: &Option<String>,
|
||||
) -> Result<bool, OperationError> {
|
||||
match appid {
|
||||
Some(_) => Err(OperationError::InvalidState),
|
||||
None => {
|
||||
match &self.primary {
|
||||
// Check the cred's associated pw.
|
||||
Some(ref primary) => {
|
||||
primary.password.as_ref()
|
||||
.ok_or(OperationError::InvalidState)
|
||||
.and_then(|pw| {
|
||||
pw.verify(cleartext)
|
||||
})
|
||||
}
|
||||
None => {
|
||||
Err(OperationError::InvalidState)
|
||||
}
|
||||
}
|
||||
} // no appid
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn regenerate_radius_secret_mod(
|
||||
&self,
|
||||
cleartext: &str,
|
||||
|
|
|
@ -6,8 +6,13 @@ use kanidm_proto::v1::{AuthAllowed, AuthCredential, AuthState};
|
|||
|
||||
use crate::credential::{totp::TOTP, Credential, Password};
|
||||
|
||||
use crate::idm::delayed::{DelayedAction, PasswordUpgrade};
|
||||
// use crossbeam::channel::Sender;
|
||||
use tokio::sync::mpsc::UnboundedSender as Sender;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
||||
// Each CredHandler takes one or more credentials and determines if the
|
||||
// handlers requirements can be 100% fufilled. This is where MFA or other
|
||||
|
@ -72,22 +77,30 @@ impl TryFrom<&Credential> for CredHandler {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Can this be improved?
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
impl CredHandler {
|
||||
pub fn validate(
|
||||
&mut self,
|
||||
fn maybe_pw_upgrade(
|
||||
au: &mut AuditScope,
|
||||
pw: &Password,
|
||||
who: Uuid,
|
||||
cleartext: &str,
|
||||
async_tx: &Sender<DelayedAction>
|
||||
)
|
||||
{
|
||||
if pw.requires_upgrade() {
|
||||
if let Err(_e) = async_tx.send(DelayedAction::PwUpgrade(PasswordUpgrade {
|
||||
target_uuid: who,
|
||||
existing_password: cleartext.to_string(),
|
||||
appid: None,
|
||||
})) {
|
||||
ladmin_warning!(au, "unable to queue delayed pwupgrade, continuing ... ");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_anonymous(
|
||||
au: &mut AuditScope,
|
||||
creds: &[AuthCredential],
|
||||
ts: &Duration,
|
||||
) -> CredState {
|
||||
match self {
|
||||
CredHandler::Denied => {
|
||||
// Sad trombone.
|
||||
lsecurity!(au, "Handler::Denied -> Result::Denied");
|
||||
CredState::Denied("authentication denied")
|
||||
}
|
||||
CredHandler::Anonymous => {
|
||||
creds.iter().fold(
|
||||
CredState::Continue(vec![AuthAllowed::Anonymous]),
|
||||
|acc, cred| {
|
||||
|
@ -121,8 +134,15 @@ impl CredHandler {
|
|||
} // end match acc
|
||||
},
|
||||
)
|
||||
} // end credhandler::anonymous
|
||||
CredHandler::Password(pw) => {
|
||||
}
|
||||
|
||||
fn validate_password(
|
||||
au: &mut AuditScope,
|
||||
creds: &[AuthCredential],
|
||||
pw: &mut Password,
|
||||
who: Uuid,
|
||||
async_tx: &Sender<DelayedAction>,
|
||||
) -> CredState {
|
||||
creds.iter().fold(
|
||||
// If no creds, remind that we want pw ...
|
||||
CredState::Continue(vec![AuthAllowed::Password]),
|
||||
|
@ -138,6 +158,7 @@ impl CredHandler {
|
|||
AuthCredential::Password(cleartext) => {
|
||||
if pw.verify(cleartext.as_str()).unwrap_or(false) {
|
||||
lsecurity!(au, "Handler::Password -> Result::Success");
|
||||
Self::maybe_pw_upgrade(au, pw, who, cleartext.as_str(), async_tx);
|
||||
CredState::Success(Vec::new())
|
||||
} else {
|
||||
lsecurity!(au, "Handler::Password -> Result::Denied - incorrect password");
|
||||
|
@ -154,8 +175,16 @@ impl CredHandler {
|
|||
} // end match acc
|
||||
},
|
||||
)
|
||||
} // end credhandler::password
|
||||
CredHandler::TOTPPassword(pw_totp) => {
|
||||
}
|
||||
|
||||
fn validate_totp_password(
|
||||
au: &mut AuditScope,
|
||||
creds: &[AuthCredential],
|
||||
ts: &Duration,
|
||||
pw_totp: &mut CredTotpPw,
|
||||
who: Uuid,
|
||||
async_tx: &Sender<DelayedAction>,
|
||||
) -> CredState {
|
||||
// Set the default reminder to both pw + totp
|
||||
creds.iter().fold(
|
||||
// If no creds, remind that we want pw ...
|
||||
|
@ -172,6 +201,7 @@ impl CredHandler {
|
|||
// if pw -> check
|
||||
if pw_totp.pw.verify(cleartext.as_str()).unwrap_or(false) {
|
||||
pw_totp.pw_state = CredVerifyState::Success;
|
||||
Self::maybe_pw_upgrade(au, &pw_totp.pw, who, cleartext.as_str(), async_tx);
|
||||
match pw_totp.totp_state {
|
||||
CredVerifyState::Init => {
|
||||
// TOTP hasn't been run yet, we need it before
|
||||
|
@ -249,6 +279,24 @@ impl CredHandler {
|
|||
},
|
||||
) // end fold
|
||||
} // end CredHandler::TOTPPassword
|
||||
|
||||
pub fn validate(
|
||||
&mut self,
|
||||
au: &mut AuditScope,
|
||||
creds: &[AuthCredential],
|
||||
ts: &Duration,
|
||||
who: Uuid,
|
||||
async_tx: &Sender<DelayedAction>,
|
||||
) -> CredState {
|
||||
match self {
|
||||
CredHandler::Denied => {
|
||||
// Sad trombone.
|
||||
lsecurity!(au, "Handler::Denied -> Result::Denied");
|
||||
CredState::Denied("authentication denied")
|
||||
}
|
||||
CredHandler::Anonymous => Self::validate_anonymous(au, creds),
|
||||
CredHandler::Password(ref mut pw) => Self::validate_password(au, creds, pw, who, async_tx),
|
||||
CredHandler::TOTPPassword(ref mut pw_totp) => Self::validate_totp_password(au, creds, ts, pw_totp, who, async_tx),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,6 +392,7 @@ impl AuthSession {
|
|||
au: &mut AuditScope,
|
||||
creds: &[AuthCredential],
|
||||
time: &Duration,
|
||||
async_tx: &Sender<DelayedAction>,
|
||||
) -> Result<AuthState, OperationError> {
|
||||
if self.finished {
|
||||
return Err(OperationError::InvalidAuthState(
|
||||
|
@ -360,7 +409,7 @@ impl AuthSession {
|
|||
return Ok(AuthState::Denied(BAD_CREDENTIALS.to_string()));
|
||||
}
|
||||
|
||||
match self.handler.validate(au, creds, time) {
|
||||
match self.handler.validate(au, creds, time, self.account.uuid, async_tx) {
|
||||
CredState::Success(claims) => {
|
||||
lsecurity!(au, "Successful cred handling");
|
||||
self.finished = true;
|
||||
|
@ -414,6 +463,10 @@ mod tests {
|
|||
};
|
||||
use kanidm_proto::v1::{AuthAllowed, AuthCredential, AuthState};
|
||||
use std::time::Duration;
|
||||
// use async_std::task;
|
||||
|
||||
use tokio::sync::mpsc::unbounded_channel as unbounded;
|
||||
// , UnboundedSender as Sender, UnboundedReceiver as Receiver};
|
||||
|
||||
#[test]
|
||||
fn test_idm_authsession_anonymous_auth_mech() {
|
||||
|
@ -422,6 +475,7 @@ mod tests {
|
|||
uuid::Uuid::new_v4(),
|
||||
None,
|
||||
);
|
||||
|
||||
let anon_account = entry_str_to_account!(JSON_ANONYMOUS_V1);
|
||||
|
||||
let session = AuthSession::new(&mut audit, anon_account, None);
|
||||
|
@ -445,6 +499,7 @@ mod tests {
|
|||
);
|
||||
let anon_account = entry_str_to_account!(JSON_ANONYMOUS_V1);
|
||||
let mut session = AuthSession::new(&mut audit, anon_account, None);
|
||||
let (async_tx, mut async_rx) = unbounded();
|
||||
|
||||
let attempt = vec![
|
||||
AuthCredential::Anonymous,
|
||||
|
@ -453,12 +508,13 @@ mod tests {
|
|||
AuthCredential::Anonymous,
|
||||
AuthCredential::Anonymous,
|
||||
];
|
||||
match session.validate_creds(&mut audit, &attempt, &Duration::from_secs(0)) {
|
||||
match session.validate_creds(&mut audit, &attempt, &Duration::from_secs(0), &async_tx) {
|
||||
Ok(AuthState::Denied(msg)) => {
|
||||
assert!(msg == BAD_CREDENTIALS);
|
||||
}
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(async_rx.try_recv().is_err());
|
||||
audit.write_log();
|
||||
}
|
||||
|
||||
|
@ -499,6 +555,7 @@ mod tests {
|
|||
|
||||
// now check
|
||||
let mut session = AuthSession::new(&mut audit, account.clone(), None);
|
||||
let (async_tx, mut async_rx) = unbounded();
|
||||
let auth_mechs = session.valid_auth_mechs();
|
||||
|
||||
assert!(
|
||||
|
@ -509,17 +566,18 @@ mod tests {
|
|||
);
|
||||
|
||||
let attempt = vec![AuthCredential::Password("bad_password".to_string())];
|
||||
match session.validate_creds(&mut audit, &attempt, &Duration::from_secs(0)) {
|
||||
match session.validate_creds(&mut audit, &attempt, &Duration::from_secs(0), &async_tx) {
|
||||
Ok(AuthState::Denied(_)) => {}
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let mut session = AuthSession::new(&mut audit, account, None);
|
||||
let attempt = vec![AuthCredential::Password("test_password".to_string())];
|
||||
match session.validate_creds(&mut audit, &attempt, &Duration::from_secs(0)) {
|
||||
match session.validate_creds(&mut audit, &attempt, &Duration::from_secs(0), &async_tx) {
|
||||
Ok(AuthState::Success(_)) => {}
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(async_rx.try_recv().is_err());
|
||||
|
||||
audit.write_log();
|
||||
}
|
||||
|
@ -560,6 +618,7 @@ mod tests {
|
|||
|
||||
// now check
|
||||
let session = AuthSession::new(&mut audit, account.clone(), None);
|
||||
let (async_tx, mut async_rx) = unbounded();
|
||||
let auth_mechs = session.valid_auth_mechs();
|
||||
assert!(auth_mechs.iter().fold(true, |acc, x| match x {
|
||||
AuthAllowed::Password => acc,
|
||||
|
@ -572,7 +631,7 @@ mod tests {
|
|||
// check send anon (fail)
|
||||
{
|
||||
let mut session = AuthSession::new(&mut audit, account.clone(), None);
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::Anonymous], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::Anonymous], &ts, &async_tx) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_AUTH_TYPE_MSG),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -588,11 +647,12 @@ mod tests {
|
|||
&mut audit,
|
||||
&vec![AuthCredential::Password(pw_bad.to_string())],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Continue(cont)) => assert!(cont == vec![AuthAllowed::TOTP]),
|
||||
_ => panic!(),
|
||||
};
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts, &async_tx) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_PASSWORD_MSG),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -605,11 +665,12 @@ mod tests {
|
|||
&mut audit,
|
||||
&vec![AuthCredential::Password(pw_bad.to_string())],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Continue(cont)) => assert!(cont == vec![AuthAllowed::TOTP]),
|
||||
_ => panic!(),
|
||||
};
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_bad)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_bad)], &ts, &async_tx) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_TOTP_MSG),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -623,11 +684,12 @@ mod tests {
|
|||
&mut audit,
|
||||
&vec![AuthCredential::Password(pw_good.to_string())],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Continue(cont)) => assert!(cont == vec![AuthAllowed::TOTP]),
|
||||
_ => panic!(),
|
||||
};
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts, &async_tx) {
|
||||
Ok(AuthState::Success(_)) => {}
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -641,11 +703,12 @@ mod tests {
|
|||
&mut audit,
|
||||
&vec![AuthCredential::Password(pw_good.to_string())],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Continue(cont)) => assert!(cont == vec![AuthAllowed::TOTP]),
|
||||
_ => panic!(),
|
||||
};
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_bad)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_bad)], &ts, &async_tx) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_TOTP_MSG),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -654,7 +717,7 @@ mod tests {
|
|||
// check send bad totp, should fail immediate
|
||||
{
|
||||
let mut session = AuthSession::new(&mut audit, account.clone(), None);
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_bad)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_bad)], &ts, &async_tx) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_TOTP_MSG),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -664,7 +727,7 @@ mod tests {
|
|||
// then bad pw, fail pw
|
||||
{
|
||||
let mut session = AuthSession::new(&mut audit, account.clone(), None);
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts, &async_tx) {
|
||||
Ok(AuthState::Continue(cont)) => assert!(cont == vec![AuthAllowed::Password]),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -672,6 +735,7 @@ mod tests {
|
|||
&mut audit,
|
||||
&vec![AuthCredential::Password(pw_bad.to_string())],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_PASSWORD_MSG),
|
||||
_ => panic!(),
|
||||
|
@ -682,7 +746,7 @@ mod tests {
|
|||
// then good pw, success
|
||||
{
|
||||
let mut session = AuthSession::new(&mut audit, account.clone(), None);
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts) {
|
||||
match session.validate_creds(&mut audit, &vec![AuthCredential::TOTP(totp_good)], &ts, &async_tx) {
|
||||
Ok(AuthState::Continue(cont)) => assert!(cont == vec![AuthAllowed::Password]),
|
||||
_ => panic!(),
|
||||
};
|
||||
|
@ -690,6 +754,7 @@ mod tests {
|
|||
&mut audit,
|
||||
&vec![AuthCredential::Password(pw_good.to_string())],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Success(_)) => {}
|
||||
_ => panic!(),
|
||||
|
@ -708,6 +773,7 @@ mod tests {
|
|||
AuthCredential::TOTP(totp_bad),
|
||||
],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_TOTP_MSG),
|
||||
_ => panic!(),
|
||||
|
@ -723,6 +789,7 @@ mod tests {
|
|||
AuthCredential::Password(pw_bad.to_string()),
|
||||
],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_PASSWORD_MSG),
|
||||
_ => panic!(),
|
||||
|
@ -738,6 +805,7 @@ mod tests {
|
|||
AuthCredential::Password(pw_good.to_string()),
|
||||
],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Denied(msg)) => assert!(msg == BAD_TOTP_MSG),
|
||||
_ => panic!(),
|
||||
|
@ -753,12 +821,14 @@ mod tests {
|
|||
AuthCredential::Password(pw_good.to_string()),
|
||||
],
|
||||
&ts,
|
||||
&async_tx
|
||||
) {
|
||||
Ok(AuthState::Success(_)) => {}
|
||||
_ => panic!(),
|
||||
};
|
||||
}
|
||||
|
||||
assert!(async_rx.try_recv().is_err());
|
||||
audit.write_log();
|
||||
}
|
||||
}
|
||||
|
|
17
kanidmd/src/lib/idm/delayed.rs
Normal file
17
kanidmd/src/lib/idm/delayed.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
pub(crate) enum DelayedAction {
|
||||
PwUpgrade(PasswordUpgrade),
|
||||
UnixPwUpgrade(UnixPasswordUpgrade),
|
||||
}
|
||||
|
||||
pub(crate) struct PasswordUpgrade {
|
||||
pub target_uuid: Uuid,
|
||||
pub existing_password: String,
|
||||
pub appid: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) struct UnixPasswordUpgrade {
|
||||
pub target_uuid: Uuid,
|
||||
pub existing_password: String,
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub(crate) mod delayed;
|
||||
pub(crate) mod account;
|
||||
pub(crate) mod authsession;
|
||||
pub(crate) mod claim;
|
||||
|
|
|
@ -19,6 +19,8 @@ use crate::server::{QueryServer, QueryServerTransaction, QueryServerWriteTransac
|
|||
use crate::utils::{password_from_random, readable_password_from_random, uuid_from_duration, SID};
|
||||
use crate::value::PartialValue;
|
||||
|
||||
use crate::idm::delayed::{DelayedAction, PasswordUpgrade, UnixPasswordUpgrade};
|
||||
|
||||
use kanidm_proto::v1::AuthState;
|
||||
use kanidm_proto::v1::OperationError;
|
||||
use kanidm_proto::v1::RadiusAuthToken;
|
||||
|
@ -27,6 +29,12 @@ use kanidm_proto::v1::SetCredentialResponse;
|
|||
use kanidm_proto::v1::UnixGroupToken;
|
||||
use kanidm_proto::v1::UnixUserToken;
|
||||
|
||||
// use crossbeam::channel::{unbounded, Sender, Receiver, TryRecvError};
|
||||
use tokio::sync::mpsc::{unbounded_channel as unbounded, UnboundedSender as Sender, UnboundedReceiver as Receiver};
|
||||
#[cfg(test)]
|
||||
use tokio::sync::mpsc::error::TryRecvError;
|
||||
|
||||
|
||||
use concread::collections::bptree::*;
|
||||
use rand::prelude::*;
|
||||
use std::time::Duration;
|
||||
|
@ -45,6 +53,7 @@ pub struct IdmServer {
|
|||
// The configured crypto policy for the IDM server. Later this could be transactional
|
||||
// and loaded from the db similar to access. But today it's just to allow dynamic pbkdf2rounds
|
||||
crypto_policy: CryptoPolicy,
|
||||
async_tx: Sender<DelayedAction>,
|
||||
}
|
||||
|
||||
pub struct IdmServerWriteTransaction<'a> {
|
||||
|
@ -55,6 +64,8 @@ pub struct IdmServerWriteTransaction<'a> {
|
|||
pub qs_read: QueryServerReadTransaction<'a>,
|
||||
// thread/server id
|
||||
sid: SID,
|
||||
// For flagging eventual actions.
|
||||
async_tx: Sender<DelayedAction>,
|
||||
}
|
||||
|
||||
pub struct IdmServerProxyReadTransaction<'a> {
|
||||
|
@ -73,9 +84,13 @@ pub struct IdmServerProxyWriteTransaction<'a> {
|
|||
crypto_policy: &'a CryptoPolicy,
|
||||
}
|
||||
|
||||
pub struct IdmServerDelayed {
|
||||
async_rx: Receiver<DelayedAction>,
|
||||
}
|
||||
|
||||
impl IdmServer {
|
||||
// TODO #59: Make number of authsessions configurable!!!
|
||||
pub fn new(qs: QueryServer) -> IdmServer {
|
||||
pub fn new(qs: QueryServer) -> (IdmServer, IdmServerDelayed) {
|
||||
// This is calculated back from:
|
||||
// 500 auths / thread -> 0.002 sec per op
|
||||
// we can then spend up to ~0.001s hashing
|
||||
|
@ -84,12 +99,16 @@ impl IdmServer {
|
|||
// overtime, we could increase this as auth parallelism
|
||||
// improves.
|
||||
let crypto_policy = CryptoPolicy::time_target(Duration::from_millis(1));
|
||||
IdmServer {
|
||||
let (async_tx, async_rx) = unbounded();
|
||||
(IdmServer {
|
||||
sessions: BptreeMap::new(),
|
||||
mfareg_sessions: BptreeMap::new(),
|
||||
qs,
|
||||
crypto_policy,
|
||||
}
|
||||
async_tx
|
||||
}, IdmServerDelayed {
|
||||
async_rx
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write(&self) -> IdmServerWriteTransaction {
|
||||
|
@ -102,6 +121,7 @@ impl IdmServer {
|
|||
// qs: &self.qs,
|
||||
qs_read: self.qs.read(),
|
||||
sid,
|
||||
async_tx: self.async_tx.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,6 +143,47 @@ impl IdmServer {
|
|||
crypto_policy: &self.crypto_policy,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn delayed_action(&self,
|
||||
au: &mut AuditScope,
|
||||
ts: Duration,
|
||||
da: DelayedAction,
|
||||
) -> Result<bool, OperationError> {
|
||||
let mut pw = self.proxy_write(ts);
|
||||
pw.process_delayedaction(au, da)
|
||||
.and_then(|_| {
|
||||
pw.commit(au)
|
||||
})
|
||||
.map(|()| true)
|
||||
}
|
||||
}
|
||||
|
||||
impl IdmServerDelayed {
|
||||
#[cfg(test)]
|
||||
pub fn is_empty_or_panic(&mut self) {
|
||||
assert!(self.async_rx.try_recv().is_err());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn try_recv(&mut self) -> Result<DelayedAction, OperationError> {
|
||||
self.async_rx.try_recv().map_err(|e|
|
||||
match e {
|
||||
TryRecvError::Empty => OperationError::InvalidState,
|
||||
TryRecvError::Closed => OperationError::QueueDisconnected,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn temp_drop_all(&mut self) {
|
||||
loop {
|
||||
match self.async_rx.recv().await {
|
||||
// Drop it
|
||||
Some(_) => {},
|
||||
// Channel has closed
|
||||
None => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IdmServerWriteTransaction<'a> {
|
||||
|
@ -229,7 +290,7 @@ impl<'a> IdmServerWriteTransaction<'a> {
|
|||
// Basically throw them at the auth_session and see what
|
||||
// falls out.
|
||||
auth_session
|
||||
.validate_creds(au, &creds.creds, &ct)
|
||||
.validate_creds(au, &creds.creds, &ct, &self.async_tx)
|
||||
.map(|aus| {
|
||||
AuthResult {
|
||||
// Is this right?
|
||||
|
@ -263,7 +324,7 @@ impl<'a> IdmServerWriteTransaction<'a> {
|
|||
})?;
|
||||
|
||||
// Validate the unix_pw - this checks the account/cred lock states.
|
||||
account.verify_unix_credential(au, uae.cleartext.as_str())
|
||||
account.verify_unix_credential(au, uae.cleartext.as_str(), &self.async_tx)
|
||||
}
|
||||
|
||||
pub fn auth_ldap(
|
||||
|
@ -303,7 +364,7 @@ impl<'a> IdmServerWriteTransaction<'a> {
|
|||
let account =
|
||||
UnixUserAccount::try_from_entry_ro(au, &account_entry, &mut self.qs_read)?;
|
||||
if account
|
||||
.verify_unix_credential(au, lae.cleartext.as_str())?
|
||||
.verify_unix_credential(au, lae.cleartext.as_str(), &self.async_tx)?
|
||||
.is_some()
|
||||
{
|
||||
// Get the anon uat
|
||||
|
@ -797,6 +858,85 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
Ok(next)
|
||||
}
|
||||
|
||||
// -- delayed action processing --
|
||||
fn process_pwupgrade(
|
||||
&mut self,
|
||||
au: &mut AuditScope,
|
||||
pwu: PasswordUpgrade,
|
||||
) -> Result<(), OperationError> {
|
||||
// get the account
|
||||
let account = self.target_to_account(au, &pwu.target_uuid)?;
|
||||
|
||||
// check, does the pw still match?
|
||||
let same = account.check_credential_pw(pwu.existing_password.as_str(), &pwu.appid)?;
|
||||
|
||||
// if yes, gen the pw mod and apply.
|
||||
if same {
|
||||
let modlist = account
|
||||
.gen_password_mod(pwu.existing_password.as_str(), &pwu.appid, self.crypto_policy)
|
||||
.map_err(|e| {
|
||||
ladmin_error!(au, "Unable to generate password mod {:?}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
self.qs_write.internal_modify(
|
||||
au,
|
||||
&filter_all!(f_eq("uuid", PartialValue::new_uuidr(&pwu.target_uuid))),
|
||||
&modlist)
|
||||
} else {
|
||||
// No action needed, it's probably been changed/updated already.
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn process_unixpwupgrade(
|
||||
&mut self,
|
||||
au: &mut AuditScope,
|
||||
pwu: UnixPasswordUpgrade,
|
||||
) -> Result<(), OperationError> {
|
||||
let account = self
|
||||
.qs_write
|
||||
.internal_search_uuid(au, &pwu.target_uuid)
|
||||
.and_then(|account_entry| {
|
||||
UnixUserAccount::try_from_entry_rw(au, &account_entry, &mut self.qs_write)
|
||||
})
|
||||
.map_err(|e| {
|
||||
ladmin_error!(au, "Failed to start unix pw upgrade -> {:?}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
let same = account.check_existing_pw(pwu.existing_password.as_str())?;
|
||||
|
||||
if same {
|
||||
let modlist = account
|
||||
.gen_password_mod(pwu.existing_password.as_str(), self.crypto_policy)
|
||||
.map_err(|e| {
|
||||
ladmin_error!(au, "Unable to generate password mod {:?}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
self.qs_write.internal_modify(
|
||||
au,
|
||||
&filter_all!(f_eq("uuid", PartialValue::new_uuidr(&pwu.target_uuid))),
|
||||
&modlist)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn process_delayedaction(
|
||||
&mut self,
|
||||
au: &mut AuditScope,
|
||||
da: DelayedAction,
|
||||
) -> Result<(), OperationError> {
|
||||
match da {
|
||||
DelayedAction::PwUpgrade(pwu) =>
|
||||
self.process_pwupgrade(au, pwu),
|
||||
DelayedAction::UnixPwUpgrade(upwu) =>
|
||||
self.process_unixpwupgrade(au, upwu),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit(self, au: &mut AuditScope) -> Result<(), OperationError> {
|
||||
lperf_trace_segment!(au, "idm::server::IdmServerWriteTransaction::commit", || {
|
||||
self.mfareg_sessions.commit();
|
||||
|
@ -814,7 +954,7 @@ mod tests {
|
|||
};
|
||||
use crate::credential::policy::CryptoPolicy;
|
||||
use crate::credential::totp::TOTP;
|
||||
use crate::credential::Credential;
|
||||
use crate::credential::{Credential, Password};
|
||||
use crate::entry::{Entry, EntryInit, EntryNew};
|
||||
use crate::event::{AuthEvent, AuthResult, CreateEvent, ModifyEvent};
|
||||
use crate::idm::event::{
|
||||
|
@ -824,15 +964,19 @@ mod tests {
|
|||
};
|
||||
use crate::modify::{Modify, ModifyList};
|
||||
use crate::value::{PartialValue, Value};
|
||||
// use crate::idm::delayed::{PasswordUpgrade, DelayedAction};
|
||||
|
||||
use kanidm_proto::v1::OperationError;
|
||||
use kanidm_proto::v1::SetCredentialResponse;
|
||||
use kanidm_proto::v1::{AuthAllowed, AuthState};
|
||||
|
||||
use crate::audit::AuditScope;
|
||||
use crate::idm::server::IdmServer;
|
||||
// , IdmServerDelayed;
|
||||
use crate::server::QueryServer;
|
||||
use crate::utils::duration_from_epoch_now;
|
||||
use std::time::Duration;
|
||||
use std::convert::TryFrom;
|
||||
use uuid::Uuid;
|
||||
|
||||
const TEST_PASSWORD: &'static str = "ntaoeuntnaoeuhraohuercahu😍";
|
||||
|
@ -842,7 +986,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_anonymous_auth() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed,
|
||||
au: &mut AuditScope| {
|
||||
let sid = {
|
||||
// Start and test anonymous auth.
|
||||
let mut idms_write = idms.write();
|
||||
|
@ -928,7 +1073,7 @@ mod tests {
|
|||
// Test sending anonymous but with no session init.
|
||||
#[test]
|
||||
fn test_idm_anonymous_auth_invalid_states() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
{
|
||||
let mut idms_write = idms.write();
|
||||
let sid = Uuid::new_v4();
|
||||
|
@ -999,14 +1144,13 @@ mod tests {
|
|||
sessionid
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idm_simple_password_auth() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
init_admin_w_password(au, qs, TEST_PASSWORD).expect("Failed to setup admin account");
|
||||
fn check_admin_password(
|
||||
idms: &IdmServer, au: &mut AuditScope, pw: &str
|
||||
) {
|
||||
let sid = init_admin_authsession_sid(idms, au);
|
||||
|
||||
let mut idms_write = idms.write();
|
||||
let anon_step = AuthEvent::cred_step_password(sid, TEST_PASSWORD);
|
||||
let anon_step = AuthEvent::cred_step_password(sid, pw);
|
||||
|
||||
// Expect success
|
||||
let r2 = idms_write.auth(au, &anon_step, Duration::from_secs(TEST_CURRENT_TIME));
|
||||
|
@ -1036,12 +1180,19 @@ mod tests {
|
|||
};
|
||||
|
||||
idms_write.commit(au).expect("Must not fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idm_simple_password_auth() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
init_admin_w_password(au, qs, TEST_PASSWORD).expect("Failed to setup admin account");
|
||||
check_admin_password(idms, au, TEST_PASSWORD);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idm_simple_password_spn_auth() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
init_admin_w_password(au, qs, TEST_PASSWORD).expect("Failed to setup admin account");
|
||||
let mut idms_write = idms.write();
|
||||
let admin_init = AuthEvent::named_init("admin@example.com");
|
||||
|
@ -1098,7 +1249,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_simple_password_invalid() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
init_admin_w_password(au, qs, TEST_PASSWORD).expect("Failed to setup admin account");
|
||||
let sid = init_admin_authsession_sid(idms, au);
|
||||
let mut idms_write = idms.write();
|
||||
|
@ -1137,7 +1288,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_simple_password_reset() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let pce = PasswordChangeEvent::new_internal(&UUID_ADMIN, TEST_PASSWORD, None);
|
||||
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
|
@ -1149,7 +1300,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_anonymous_set_password_denied() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let pce = PasswordChangeEvent::new_internal(&UUID_ANONYMOUS, TEST_PASSWORD, None);
|
||||
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
|
@ -1160,7 +1311,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_session_expire() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
init_admin_w_password(au, qs, TEST_PASSWORD).expect("Failed to setup admin account");
|
||||
let sid = init_admin_authsession_sid(idms, au);
|
||||
let mut idms_write = idms.write();
|
||||
|
@ -1179,7 +1330,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_regenerate_radius_secret() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
let rrse = RegenerateRadiusSecretEvent::new_internal(UUID_ADMIN.clone());
|
||||
|
||||
|
@ -1197,7 +1348,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_radiusauthtoken() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
let rrse = RegenerateRadiusSecretEvent::new_internal(UUID_ADMIN.clone());
|
||||
let r1 = idms_prox_write
|
||||
|
@ -1218,7 +1369,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_simple_password_reject_weak() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
// len check
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
|
||||
|
@ -1251,7 +1402,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_unixusertoken() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
// Modify admin to have posixaccount
|
||||
let me_posix = unsafe {
|
||||
|
@ -1323,7 +1474,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_simple_unix_password_reset() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
// make the admin a valid posix account
|
||||
let me_posix = unsafe {
|
||||
|
@ -1385,7 +1536,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_idm_totp_registration() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let ct = duration_from_epoch_now();
|
||||
let expire = Duration::from_secs(ct.as_secs() + MFAREG_SESSION_TIMEOUT + 2);
|
||||
let mut idms_prox_write = idms.proxy_write(ct.clone());
|
||||
|
@ -1513,4 +1664,92 @@ mod tests {
|
|||
assert!(idms_prox_write.commit(au).is_ok());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idm_simple_password_upgrade() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed, au: &mut AuditScope| {
|
||||
// Assert the delayed action queue is empty
|
||||
idms_delayed.is_empty_or_panic();
|
||||
// Setup the admin w_ an imported password.
|
||||
{
|
||||
let qs_write = qs.write(duration_from_epoch_now());
|
||||
// now modify and provide a primary credential.
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
"password_import".to_string(),
|
||||
Value::from("{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM")
|
||||
)]),
|
||||
)
|
||||
};
|
||||
// go!
|
||||
assert!(qs_write.modify(au, &me_inv_m).is_ok());
|
||||
qs_write.commit(au).expect("failed to commit");
|
||||
}
|
||||
// Still empty
|
||||
idms_delayed.is_empty_or_panic();
|
||||
// Do an auth, this will trigger the action to send.
|
||||
check_admin_password(idms, au, "password");
|
||||
// process it.
|
||||
let da = idms_delayed.try_recv().expect("invalid");
|
||||
assert!(Ok(true) == idms.delayed_action(au, duration_from_epoch_now(), da));
|
||||
// Check the admin pw still matches
|
||||
check_admin_password(idms, au, "password");
|
||||
// No delayed action was queued.
|
||||
idms_delayed.is_empty_or_panic();
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idm_unix_password_upgrade() {
|
||||
run_idm_test!(|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed, au: &mut AuditScope| {
|
||||
// Assert the delayed action queue is empty
|
||||
idms_delayed.is_empty_or_panic();
|
||||
// Setup the admin with an imported unix pw.
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
|
||||
let im_pw = "{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM";
|
||||
let pw = Password::try_from(im_pw).expect("failed to parse");
|
||||
let cred = Credential::new_from_password(pw);
|
||||
let v_cred = Value::new_credential("unix", cred);
|
||||
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present("class".to_string(), Value::new_class("posixaccount")),
|
||||
Modify::Present("gidnumber".to_string(), Value::new_uint32(2001)),
|
||||
Modify::Present("unix_password".to_string(), v_cred),
|
||||
]),
|
||||
)
|
||||
};
|
||||
assert!(idms_prox_write.qs_write.modify(au, &me_posix).is_ok());
|
||||
assert!(idms_prox_write.commit(au).is_ok());
|
||||
idms_delayed.is_empty_or_panic();
|
||||
// Get the auth ready.
|
||||
let uuae = UnixUserAuthEvent::new_internal(&UUID_ADMIN, "password");
|
||||
let mut idms_write = idms.write();
|
||||
let a1 = idms_write.auth_unix(au, &uuae, Duration::from_secs(TEST_CURRENT_TIME));
|
||||
match a1 {
|
||||
Ok(Some(_tok)) => {}
|
||||
_ => assert!(false),
|
||||
};
|
||||
idms_write.commit(au).expect("Must not fail");
|
||||
// The upgrade was queued
|
||||
// Process it.
|
||||
let da = idms_delayed.try_recv().expect("invalid");
|
||||
assert!(Ok(true) == idms.delayed_action(au, duration_from_epoch_now(), da));
|
||||
// Go again
|
||||
let mut idms_write = idms.write();
|
||||
let a2 = idms_write.auth_unix(au, &uuae, Duration::from_secs(TEST_CURRENT_TIME));
|
||||
match a2 {
|
||||
Ok(Some(_tok)) => {}
|
||||
_ => assert!(false),
|
||||
};
|
||||
idms_write.commit(au).expect("Must not fail");
|
||||
// No delayed action was queued.
|
||||
idms_delayed.is_empty_or_panic();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@ use crate::value::{PartialValue, Value};
|
|||
use kanidm_proto::v1::OperationError;
|
||||
use kanidm_proto::v1::{UnixGroupToken, UnixUserToken};
|
||||
|
||||
use crate::idm::delayed::{DelayedAction, UnixPasswordUpgrade};
|
||||
|
||||
// use crossbeam::channel::Sender;
|
||||
use tokio::sync::mpsc::UnboundedSender as Sender;
|
||||
|
||||
use std::iter;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -165,6 +170,7 @@ impl UnixUserAccount {
|
|||
&self,
|
||||
au: &mut AuditScope,
|
||||
cleartext: &str,
|
||||
async_tx: &Sender<DelayedAction>,
|
||||
) -> Result<Option<UnixUserToken>, OperationError> {
|
||||
// TODO #59: Is the cred locked?
|
||||
// is the cred some or none?
|
||||
|
@ -173,6 +179,18 @@ impl UnixUserAccount {
|
|||
Some(pw) => {
|
||||
if pw.verify(cleartext)? {
|
||||
lsecurity!(au, "Successful unix cred handling");
|
||||
if pw.requires_upgrade() {
|
||||
async_tx.send(
|
||||
DelayedAction::UnixPwUpgrade(UnixPasswordUpgrade {
|
||||
target_uuid: self.uuid,
|
||||
existing_password: cleartext.to_string(),
|
||||
})
|
||||
).map_err(|_| {
|
||||
ladmin_error!(au, "failed to queue delayed action - unix password upgrade");
|
||||
OperationError::InvalidState
|
||||
})?;
|
||||
}
|
||||
|
||||
Some(self.to_unixusertoken()).transpose()
|
||||
} else {
|
||||
// Failed to auth
|
||||
|
@ -195,6 +213,25 @@ impl UnixUserAccount {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_existing_pw(
|
||||
&self,
|
||||
cleartext: &str,
|
||||
) -> Result<bool, OperationError> {
|
||||
match &self.cred {
|
||||
Some(cred) => match &cred.password {
|
||||
Some(pw) => {
|
||||
pw.verify(cleartext)
|
||||
}
|
||||
None => {
|
||||
Err(OperationError::InvalidState)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
Err(OperationError::InvalidState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -490,7 +490,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_ldap_simple_bind() {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, au: &mut AuditScope| {
|
||||
run_idm_test!(|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed, au: &mut AuditScope| {
|
||||
let ldaps = LdapServer::new(au, idms).expect("failed to start ldap");
|
||||
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
|
||||
|
|
|
@ -117,7 +117,7 @@ macro_rules! run_idm_test {
|
|||
($test_fn:expr) => {{
|
||||
use crate::audit::AuditScope;
|
||||
use crate::be::{Backend, FsType};
|
||||
use crate::idm::server::IdmServer;
|
||||
use crate::idm::server::{IdmServer, IdmServerDelayed};
|
||||
use crate::schema::Schema;
|
||||
use crate::server::QueryServer;
|
||||
use crate::utils::duration_from_epoch_now;
|
||||
|
@ -145,12 +145,13 @@ macro_rules! run_idm_test {
|
|||
.initialise_helper(&mut audit, duration_from_epoch_now())
|
||||
.expect("init failed");
|
||||
|
||||
let test_idm_server = IdmServer::new(test_server.clone());
|
||||
let (test_idm_server, mut idms_delayed) = IdmServer::new(test_server.clone());
|
||||
|
||||
$test_fn(&test_server, &test_idm_server, &mut audit);
|
||||
$test_fn(&test_server, &test_idm_server, &mut idms_delayed, &mut audit);
|
||||
// Any needed teardown?
|
||||
// Make sure there are no errors.
|
||||
assert!(test_server.verify(&mut audit).len() == 0);
|
||||
idms_delayed.is_empty_or_panic();
|
||||
audit.write_log();
|
||||
}};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue