1481 2024 access control rework (#2366)

Rework default access controls to better separate roles and access profiles.
This commit is contained in:
Firstyear 2023-12-18 09:10:13 +10:00 committed by GitHub
parent c2d9c5c941
commit d09c2448ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 2858 additions and 3640 deletions

332
Cargo.lock generated
View file

@ -80,9 +80,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
dependencies = [
"anstyle",
"anstyle-parse",
@ -100,30 +100,30 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -233,7 +233,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -255,7 +255,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -266,7 +266,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -390,7 +390,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -494,7 +494,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.39",
"syn 2.0.41",
"which",
]
@ -724,9 +724,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.10"
version = "4.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272"
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
dependencies = [
"clap_builder",
"clap_derive",
@ -734,9 +734,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.9"
version = "4.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1"
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
dependencies = [
"anstream",
"anstyle",
@ -762,7 +762,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -894,9 +894,9 @@ dependencies = [
[[package]]
name = "core-foundation"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
@ -904,9 +904,9 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "cpufeatures"
@ -989,9 +989,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5"
dependencies = [
"cfg-if",
"crossbeam-utils",
@ -999,9 +999,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@ -1010,22 +1010,21 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
version = "0.9.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset 0.9.0",
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.8"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153"
dependencies = [
"cfg-if",
"crossbeam-utils",
@ -1033,9 +1032,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
dependencies = [
"cfg-if",
]
@ -1207,7 +1206,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1229,7 +1228,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core 0.20.3",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1254,9 +1253,9 @@ dependencies = [
[[package]]
name = "deranged"
version = "0.3.9"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc"
dependencies = [
"powerfmt",
"serde",
@ -1347,7 +1346,16 @@ version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys",
"dirs-sys 0.3.7",
]
[[package]]
name = "dirs"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
dependencies = [
"dirs-sys 0.4.1",
]
[[package]]
@ -1361,6 +1369,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]]
name = "displaydoc"
version = "0.2.4"
@ -1369,7 +1389,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1428,7 +1448,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1448,7 +1468,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1468,7 +1488,7 @@ checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1489,7 +1509,7 @@ dependencies = [
"darling 0.20.3",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1581,9 +1601,9 @@ dependencies = [
[[package]]
name = "faster-hex"
version = "0.8.1"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239f7bfb930f820ab16a9cd95afc26f88264cf6905c960b340a615384aa3338a"
checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
dependencies = [
"serde",
]
@ -1618,14 +1638,14 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.22"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.3.5",
"windows-sys 0.48.0",
"redox_syscall 0.4.1",
"windows-sys 0.52.0",
]
[[package]]
@ -1770,7 +1790,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -1918,9 +1938,9 @@ dependencies = [
[[package]]
name = "gix-chunk"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b42ea64420f7994000130328f3c7a2038f639120518870436d31b8bde704493"
checksum = "d411ecd9b558b0c20b3252b7e409eec48eabc41d18324954fe526bac6e2db55f"
dependencies = [
"thiserror",
]
@ -1962,9 +1982,9 @@ dependencies = [
[[package]]
name = "gix-config-value"
version = "0.14.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea7505b97f4d8e7933e29735a568ba2f86d8de466669d9f0e8321384f9972f47"
checksum = "6419db582ea84dfb58c7e7b0af7fd62c808aa14954af2936a33f89b0f4ed018e"
dependencies = [
"bitflags 2.4.1",
"bstr",
@ -1975,9 +1995,9 @@ dependencies = [
[[package]]
name = "gix-date"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7df669639582dc7c02737642f76890b03b5544e141caba68a7d6b4eb551e0d"
checksum = "468dfbe411f335f01525a1352271727f8e7772075a93fa747260f502086b30be"
dependencies = [
"bstr",
"itoa",
@ -2052,9 +2072,9 @@ dependencies = [
[[package]]
name = "gix-hash"
version = "0.13.1"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1884c7b41ea0875217c1be9ce91322f90bde433e91d374d0e1276073a51ccc60"
checksum = "1f8cf8c2266f63e582b7eb206799b63aa5fa68ee510ad349f637dfe2d0653de0"
dependencies = [
"faster-hex",
"thiserror",
@ -2062,9 +2082,9 @@ dependencies = [
[[package]]
name = "gix-hashtable"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "409268480841ad008e81c17ca5a293393fbf9f2b6c2f85b8ab9de1f0c5176a16"
checksum = "feb61880816d7ec4f0b20606b498147d480860ddd9133ba542628df2f548d3ca"
dependencies = [
"gix-hash",
"hashbrown 0.14.3",
@ -2084,13 +2104,13 @@ dependencies = [
[[package]]
name = "gix-macros"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d8acb5ee668d55f0f2d19a320a3f9ef67a6999ad483e11135abcc2464ed18b6"
checksum = "02a5bcaf6704d9354a3071cede7e77d366a5980c7352e102e2c2f9b645b1d3ae"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -2153,9 +2173,9 @@ dependencies = [
[[package]]
name = "gix-path"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a1d370115171e3ae03c5c6d4f7d096f2981a40ddccb98dfd704c773530ba73b"
checksum = "d86d6fac2fabe07b67b7835f46d07571f68b11aa1aaecae94fe722ea4ef305e1"
dependencies = [
"bstr",
"gix-trace",
@ -2166,9 +2186,9 @@ dependencies = [
[[package]]
name = "gix-quote"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "475c86a97dd0127ba4465fbb239abac9ea10e68301470c9791a6dd5351cdc905"
checksum = "4f84845efa535468bc79c5a87b9d29219f1da0313c8ecf0365a5daa7e72786f2"
dependencies = [
"bstr",
"btoi",
@ -2243,9 +2263,9 @@ dependencies = [
[[package]]
name = "gix-sec"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92b9542ac025a8c02ed5d17b3fc031a111a384e859d0be3532ec4d58c40a0f28"
checksum = "a36ea2c5907d64a9b4b5d3cc9f430e6c30f0509646b5e38eb275ca57c5bf29e2"
dependencies = [
"bitflags 2.4.1",
"gix-path",
@ -2268,9 +2288,9 @@ dependencies = [
[[package]]
name = "gix-trace"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836"
checksum = "b686a35799b53a9825575ca3f06481d0a053a409c4d97ffcf5ddd67a8760b497"
[[package]]
name = "gix-traverse"
@ -2304,18 +2324,18 @@ dependencies = [
[[package]]
name = "gix-utils"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b85d89dc728613e26e0ed952a19583744e7f5240fcd4aa30d6c824ffd8b52f0f"
checksum = "9f82c41937f00e15a1f6cb0b55307f0ca1f77f4407ff2bf440be35aa688c6a3e"
dependencies = [
"fastrand",
]
[[package]]
name = "gix-validate"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05cab2b03a45b866156e052aa38619f4ece4adcb2f79978bfc249bc3b21b8c5"
checksum = "75b7d8e4274be69f284bbc7e6bb2ccf7065dbcdeba22d8c549f2451ae426883f"
dependencies = [
"bstr",
"thiserror",
@ -2626,11 +2646,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.5"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -2652,9 +2672,9 @@ dependencies = [
[[package]]
name = "http-body"
version = "0.4.5"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http",
@ -2934,9 +2954,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.9"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "jobserver"
@ -3155,7 +3175,7 @@ dependencies = [
"rpassword 7.3.1",
"serde",
"serde_json",
"shellexpand",
"shellexpand 2.1.2",
"sketching",
"time",
"tokio",
@ -3331,7 +3351,7 @@ version = "1.1.0-rc.15-dev"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -3541,9 +3561,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.150"
version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]]
name = "libloading"
@ -3610,9 +3630,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "lock_api"
@ -3768,9 +3788,9 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.9"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
dependencies = [
"libc",
"log",
@ -3945,7 +3965,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -4089,9 +4109,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.18.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "oorandom"
@ -4107,9 +4127,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "openssl"
version = "0.10.60"
version = "0.10.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800"
checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
@ -4128,7 +4148,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -4139,9 +4159,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.96"
version = "0.9.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b"
dependencies = [
"cc",
"libc",
@ -4252,6 +4272,12 @@ dependencies = [
"tokio-stream",
]
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "orca"
version = "1.1.0-rc.15-dev"
@ -4514,7 +4540,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -4631,7 +4657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
dependencies = [
"proc-macro2",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -4829,15 +4855,6 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
@ -5019,9 +5036,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40"
checksum = "810294a8a4a0853d4118e3b94bb079905f2107c7fe979d8f0faae98765eb6378"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@ -5030,23 +5047,23 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29"
checksum = "bfc144a1273124a67b8c1d7cd19f5695d1878b31569c0512f6086f0f4676604e"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"shellexpand",
"syn 2.0.39",
"shellexpand 3.1.0",
"syn 2.0.41",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.0.0"
version = "8.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada"
checksum = "816ccd4875431253d6bb54b804bcff4369cbde9bae33defde25fdf6c2ef91d40"
dependencies = [
"sha2 0.10.8",
"walkdir",
@ -5084,15 +5101,15 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.25"
version = "0.38.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -5103,9 +5120,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.15"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "same-file"
@ -5295,7 +5312,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -5357,7 +5374,7 @@ dependencies = [
"darling 0.20.3",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -5421,7 +5438,16 @@ version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
dependencies = [
"dirs",
"dirs 4.0.0",
]
[[package]]
name = "shellexpand"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
dependencies = [
"dirs 5.0.1",
]
[[package]]
@ -5619,9 +5645,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.39"
version = "2.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
dependencies = [
"proc-macro2",
"quote",
@ -5698,27 +5724,27 @@ version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
name = "thiserror"
version = "1.0.50"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.50"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -5809,9 +5835,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.34.0"
version = "1.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
dependencies = [
"backtrace",
"bytes",
@ -5843,7 +5869,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -5858,9 +5884,9 @@ dependencies = [
[[package]]
name = "tokio-openssl"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a"
checksum = "6ffab79df67727f6acf57f1ff743091873c24c579b1e2ce4d8f53e47ded4d63d"
dependencies = [
"futures-util",
"openssl",
@ -6028,7 +6054,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -6127,9 +6153,9 @@ dependencies = [
[[package]]
name = "try-lock"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tss-esapi"
@ -6186,9 +6212,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
version = "0.3.13"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
[[package]]
name = "unicode-bom"
@ -6275,7 +6301,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
"syn 2.0.39",
"syn 2.0.41",
"url",
"uuid",
]
@ -6381,7 +6407,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
"wasm-bindgen-shared",
]
@ -6415,7 +6441,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -6448,7 +6474,7 @@ checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -6925,9 +6951,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.19"
version = "0.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2"
dependencies = [
"memchr",
]
@ -7052,7 +7078,7 @@ checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]
@ -7072,7 +7098,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.41",
]
[[package]]

View file

@ -117,6 +117,7 @@ precommit: ## all the usual test things
precommit: test codespell test/pykanidm doc/format
.PHONY: vendor
vendor: ## Vendor required crates
vendor:
cargo vendor > cargo_vendor_config

View file

@ -15,21 +15,19 @@
- [Installing client tools](installing_client_tools.md)
- [Administration](administrivia.md)
- [Accounts and Groups](accounts_and_groups.md)
- [Account Policy](account_policy.md)
- [Authentication and Credentials](authentication.md)
- [POSIX Accounts and Groups](posix_accounts.md)
- [Backup and Restore](backup_restore.md)
- [Database Maintenance](database_maint.md)
- [Domain Rename](domain_rename.md)
- [Monitoring the platform](monitoring.md)
- [Password Quality and Badlisting](password_quality.md)
- [The Recycle Bin](recycle_bin.md)
- [Replication](repl/readme.md)
- [Planning](repl/planning.md)
- [Deployment](repl/deployment.md)
- [Administration](repl/administration.md)
- [Accounts and Groups](accounts/intro.md)
- [People Accounts](accounts/people.md)
- [Authentication and Credentials](accounts/authentication.md)
- [Groups](accounts/groups.md)
- [Service Accounts](accounts/service.md)
- [Account Policy](accounts/policy.md)
- [POSIX Accounts and Groups](accounts/posix.md)
- [Service Integrations](integrations/readme.md)
- [PAM and nsswitch](integrations/pam_and_nsswitch.md)
@ -46,6 +44,11 @@
- [Kubernetes Ingress](examples/k8s_ingress_example.md)
- [Traefik](examples/traefik.md)
- [Replication](repl/readme.md)
- [Planning](repl/planning.md)
- [Deployment](repl/deployment.md)
- [Administration](repl/administration.md)
- [Synchronisation](sync/concepts.md)
- [FreeIPA](sync/freeipa.md)
- [LDAP](sync/ldap.md)

View file

@ -1,104 +0,0 @@
# Account Policy
Account Policy defines the security requirements that accounts must meet and influences users
sessions.
Policy is defined on groups so that membership of a group influences the security of its members.
This allows you to express that if you can access a system or resource, then the account must also
meet the policy requirements.
## Default Account Policy
A default Account Policy is applied to `idm_all_accounts`. This provides the defaults that influence
all accounts in Kanidm. This policy can be modified the same as any other group's policy.
## Policy Resolution
When an account is affected by multiple policies, the strictest component from each policy is
applied. This can mean that two policies interact and make their combination stricter than their
parts.
| value | ordering |
| ----------------------- | -------------- |
| auth-session | smallest value |
| password-minimum-length | largest value |
| privilege-expiry | smallest value |
### Example Resolution
If we had two policies where the first defined:
```text
auth-session: 86400
password-minimum-length: 10
privilege-expiry: 600
```
And the second
```text
auth-session: 3600
password-minimum-length: 15
privilege-expiry: 3600
```
As the value of auth-session from the second is smaller we would take that. We would take the
smallest value of privilege-expiry from the first. We would take the largest value of
password-minimum-length. This leaves:
```text
auth-session: 3600
password-minimum-length: 15
privilege-expiry: 600
```
## Enabling Account Policy
Account Policy is enabled on a group with the command:
```shell
kanidm group account-policy enable <group name>
kanidm group account-policy enable my_admin_group
```
## Setting Maximum Session Time
The auth-session value influences the maximum time in seconds that an authenticated session can
exist. After this time, the user must reauthenticate.
This value provides a difficult balance - forcing frequent re-authentications can frustrate and
annoy users. However extremely long sessions allow a stolen or disclosed session token/device to
read data for an extended period. Due to Kanidm's read/write separation this mitigates the risk of
disclosed sessions as they can only _read_ data, not write it.
To set the maximum authentication session time
```shell
kanidm group account-policy auth-expiry <group name> <seconds>
kanidm group account-policy auth-expiry my_admin_group 86400
```
## Setting Minimum Password Length
The password-minimum-length value defines the character length of passwords that are acceptable.
There are no-other tunables for passwords in account policy. Other settings such as complexity,
symbols, numbers and so on, have been proven to not matter in any real world attacks.
To set this value:
```shell
kanidm group account-policy password-minimum-length <group name> <length>
kanidm group account-policy password-minimum-length my_admin_group 12
```
## Setting Maximum Privilege Time
The privilege-expiry time defines how long a session retains its write privileges after a
reauthentication. After this time, the session returns to read-only mode.
To set the maximum privilege time
```shell
kanidm group account-policy privilege-expiry <group name> <seconds>
kanidm group account-policy privilege-expiry my_admin_group 900
```

View file

@ -16,14 +16,21 @@ secure method of authentication in Kanidm.
<!-- deno-fmt-ignore-start -->
{{#template templates/kani-warning.md
{{#template ../templates/kani-warning.md
imagepath=images
title=Warning!
text=Kanidm's definition of Passkeys differs to other systems. This is because we adopted the term very early before it has changed and evolved.
text=Kanidm's definition of Passkeys may differ from that of other systems. This is because we adopted the term very early, before it has changed and evolved.
}}
<!-- deno-fmt-ignore-end -->
### Attested Passkeys
These are the same as Passkeys, except that the device must present a cryptographic certificate or
origin during registration. This allows [account policy](policy.md) to be defined to only allow the
use of certain models of authenticator. In general only FIDO2 keys or TPM's are capable of meeting
attestation requirements.
### Password + TOTP
This is a classic Time-based One Time Password combined with a password. Different to other systems
@ -35,8 +42,13 @@ environments due to the fact it is still possible to perform realtime phishing a
## Resetting Person Account Credentials
Members of the `idm_account_manage_priv` group have the rights to manage person and service accounts
security and login aspects. This includes resetting account credentials.
Members of the groups `idm_people_admins`, `idm_people_on_boarding` and `idm_service_desk` have the
rights to initiate a credential reset for a person.
> NOTE: If the person is a member of `idm_high_privilege` then these resets are not allowed. This is
> to prevent `idm_service_desk` and similar roles from privilege escalation by resetting the
> credentials of a higher privileged account. If a person who is a member of `idm_high_privilege`
> requires a credential reset, this must be initiated by a member of `idm_people_admins`.
### Onboarding a New Person / Resetting Credentials
@ -82,16 +94,26 @@ kanidm person credential create-reset-token demo_user 86400 --name idm_admin
If the user wishes you can direct them to `https://idm.mydomain.name/ui/reset` where they can
manually enter their token value.
Once the credential has been set the token is immediately invalidated and can never be used again.
By default the token is valid for 1 hour. You can request a longer token validity time when creating
the token. Tokens are only allowed to be valid for a maximum of 24 hours.
Once the credential reset has been committed the token is immediately invalidated and can never be
used again. By default the token is valid for 1 hour. You can request a longer token validity time
when creating the token. Tokens are only allowed to be valid for a maximum of 24 hours.
### Resetting Credentials Directly
You can perform a password reset on the demo\_user, for example as the idm\_admin user, who is a
You can perform a password reset on the `demo_user`, for example as the `idm_admin` user, who is a
default member of this group. The lines below prefixed with `#` are the interactive credential
update interface. This allows the user to directly manage the credentials of another account.
<!-- deno-fmt-ignore-start -->
{{#template ../templates/kani-warning.md
imagepath=images
title=Warning!
text=Don't use the direct credential reset to lock or invalidate an account. You should expire the account instead.
}}
<!-- deno-fmt-ignore-end -->
```bash
kanidm person credential update demo_user --name idm_admin
# spn: demo_user@idm.example.com
@ -115,15 +137,10 @@ kanidm login --name demo_user
kanidm self whoami --name demo_user
```
<!-- deno-fmt-ignore-start -->
## Credential Deletion
{{#template templates/kani-warning.md
imagepath=images
title=Warning!
text=Don't use the direct credential reset to lock or invalidate an account. You should expire the account instead.
}}
<!-- deno-fmt-ignore-end -->
When a person deletes a credential, all sessions that were created by that credential are
immediately logged out and invalidated.
## Reauthentication / Privilege Access Mode

View file

@ -0,0 +1,76 @@
# Groups
Groups are a collection of other entities that exist within Kanidm.
## Creating Groups
Members of `idm_group_admins` can create new groups. `idm_admin` by default has these privileges.
```bash
kanidm group create demo_group --name idm_admin
kanidm group add-members demo_group demo_user --name idm_admin
kanidm group list-members demo_group --name idm_admin
```
After addition, you will see a reverse link from our `demo_user` showing that it is now a _member
of_ the group `demo_group`. Kanidm makes all group membership determinations by inspecting an
entry's "memberof" attribute.
```bash
kanidm person get demo_user --name idm_admin
```
## Nested Groups
Kanidm supports groups being members of groups, allowing nested groups. These nesting relationships
are shown through the "memberof" attribute on groups and accounts. This allows nested groups to
reflect on accounts.
An example can be easily shown with:
```bash
kanidm group create group_1 --name idm_admin
kanidm group create group_2 --name idm_admin
kanidm person create nest_example "Nesting Account Example" --name idm_admin
kanidm group add-members group_1 group_2 --name idm_admin
kanidm group add-members group_2 nest_example --name idm_admin
kanidm person get nest_example --name anonymous
```
This should result in output similar to:
```
memberof: idm_all_persons@localhost
memberof: idm_all_accounts@localhost
memberof: group_2@localhost
memberof: group_1@localhost
name: nest_example
```
## Delegated Administration
Kanidm supports delegated administration though the "entry managed by" field. This allows specifying
a group or user account that is the "entry manager" of a group. This allows the entry manager to
modify the group without the need to define new access controls.
The `entry_managed_by` attribute of a group may only be modified by members of
`idm_access_control_admins`. During entry creation `idm_group_admins` may set `entry_managed_by`,
but may not change it post creation.
```bash
kanidm group create <NAME> [ENTRY_MANAGED_BY]
kanidm group create delegated_access_group demo_group --name idm_admin
kanidm group get delegated_access_group --name idm_admin
```
Now, as our `demo_user` is a member of `demo_group` they have delegated administration of
`delegated_access_group`.
```bash
kanidm login --name demo_user
note the use of demo_user --\
v
kanidm group add-members delegated_access_group admin --name demo_user
kanidm group get delegated_access_group --name demo_user
```

122
book/src/accounts/intro.md Normal file
View file

@ -0,0 +1,122 @@
# Accounts and groups
Accounts and Groups are the primary reasons for Kanidm to exist. Kanidm is optimised as a repository
for these data. As a result, there are many concepts and important details to understand.
## Service Accounts vs Person Accounts
Kanidm separates accounts into two types. Person accounts (or persons) are intended for use by
humans that will access the system in an interactive way. Service accounts are intended for use by
computers or services that need to identify themself to Kanidm. Generally a person or group of
persons will be responsible for and will manage service accounts. Because of this distinction these
classes of accounts have different properties and methods of authentication and management.
## Groups
Groups represent a collection of entities. This generally is a collection of persons or service
accounts. Groups are commonly used to assign privileges to the accounts that are members of a group.
This allows easier administration over larger systems where privileges can be assigned to groups in
a logical manner, and then only membership of the groups need administration, rather than needing to
assign privileges to each entity directly and uniquely.
Groups may also be nested, where a group can contain another group as a member. This allows
hierarchies to be created again for easier administration.
## Default Accounts and Groups
Kanidm ships with a number of default service accounts and groups. This is to give you the best
out-of-box experience possible, as well as supplying best practice examples related to modern
Identity Management (IDM) systems.
There are two "break-glass" system administration accounts.
`admin` is the default service account which has privileges to configure and administer Kanidm as a
whole. This account can manage access controls, schema, integrations and more. However the `admin`
can not manage persons by default.
`idm_admin` is the default service account which has privileges to create persons and to manage
these accounts and groups. They can perform credential resets and more.
Both the `admin` and the `idm_admin` user should _NOT_ be used for daily activities - they exist for
initial system configuration, and for disaster recovery scenarios. You should delegate permissions
as required to named user accounts instead.
The majority of the builtin groups are privilege groups that provide rights over Kanidm
administrative actions. These include groups for account management, person management (personal and
sensitive data), group management, and more.
`admin` and `idm_admin` both inherit their privileges from these default groups. This allows you to
assign persons to these roles instead.
## Reauthentication and Session Privilege
Kanidm sessions have a concept of session privilege. Conceptually you can consider this like `sudo`
on unix systems or `uac` on windows. This allows a session to briefly access its write permissions
by reauthentication with the identical credential they logged in with.
This allows safe assignment of high privilege roles to persons since their sessions do not have
access to their write privileges by default. They must reauthenticate and use their privileges
within a short time window.
However, these sessions always retain their _read_ privileges - meaning that they can still access
and view high levels of data at any time without reauthentication.
In high risk environments you should still consider assigning seperate administration accounts to
users if this is considered a risk.
## Recovering the Initial Admin Accounts
By default the `admin` and `idm_admin` accounts have no password, and can not be accessed. They need
to be "recovered" from the server that is running the kanidmd server.
You should have already recovered the admin account during your setup process. If not, refer to the
[server configuration chapter](server_configuration.md#default-admin-account) on how to recover
these accounts.
These accounts will be used through the remainder of this document for managing the server.
## Viewing Default Groups
You should take some time to inspect the default groups which are related to default roles and
permissions. Each group has a description to explain its purpose. These can be viewed with:
```bash
kanidm group list --name idm_admin
kanidm group get <name>
```
## Why Can't I Change admin With idm\_admin?
As a security mechanism there is a distinction between "accounts" and "high permission accounts".
This is to help prevent elevation attacks, where a member of a service desk could attempt to reset
the password of idm\_admin or admin, or even a member of HR or System Admin teams to move laterally.
Generally, membership of a "privilege" group that ships with Kanidm, such as:
- idm\_account\_manage\_priv
- idm\_people\_read\_priv
- idm\_schema\_manage\_priv
- many more ...
...indirectly grants you membership to "idm\_high\_privilege". If you are a member of this group,
the standard "account" and "people" rights groups are NOT able to alter, read or manage these
accounts. To manage these accounts higher rights are required, such as those held by the admin
account.
Further, groups that are considered "idm\_high\_privilege" can NOT be managed by the standard
"idm\_group\_manage\_priv" group.
Management of high privilege accounts and groups is granted through the the "hp" variants of all
privileges. A non-conclusive list:
- idm\_hp\_account\_read\_priv
- idm\_hp\_account\_manage\_priv
- idm\_hp\_account\_write\_priv
- idm\_hp\_group\_manage\_priv
- idm\_hp\_group\_write\_priv
Membership of any of these groups should be considered to be equivalent to system administration
rights in the directory, and by extension, over all network resources that trust Kanidm.
All groups that are flagged as "idm\_high\_privilege" should be audited and monitored to ensure that
they are not altered.

118
book/src/accounts/people.md Normal file
View file

@ -0,0 +1,118 @@
# People Accounts
A person represents a human's account in Kanidm. The majority of your users will be a person who
will use this account in their daily activities. These entries may contain personally identifying
information that _is_ considered by Kanidm to be sensitive. Because of this, there are default
limits to who may access these data.
## Creating Person Accounts
Members of the `idm_people_admins` group have the privileges to create new persons in the system. By
default `idm_admin` has this permission.
```bash
kanidm login --name idm_admin
kanidm person create demo_user "Demonstration User" --name idm_admin
kanidm person get demo_user --name idm_admin
```
Kanidm allows person accounts to include personally identifying attributes, such as their legal name
and email address.
Initially, a person does not have these attributes. If desired, a person may be modified to have
these attributes.
```bash
# Note, both the --legalname and --mail flags may be omitted
kanidm person update demo_user --legalname "initial name" --mail "initial@email.address"
```
You can also use anonymous to view accounts - note that you won't see certain fields due to the
limits of the anonymous access control profile.
```bash
kanidm login --name anonymous
kanidm person get demo_user --name anonymous
```
> NOTE: only members of `idm_people_pii_read` and `idm_people_admins` may read personal information
> by default.
<!-- deno-fmt-ignore-start -->
{{#template ../templates/kani-warning.md
imagepath=images
title=Warning!
text=Persons may change their own displayname, name, and legal name at any time. You MUST NOT use these values as primary keys in external systems. You MUST use the `uuid` attribute present on all entries as an external primary key.
}}
<!-- deno-fmt-ignore-end -->
## Account Validity
Kanidm supports accounts that are only able to authenticate between a pair of dates and times; the
"valid from" and "expires" timestamps define these points in time. By default members of
`idm_people_admins` may change these values.
The account validity can be displayed with:
```bash
kanidm person validity show demo_user --name idm_admin
user: demo_user
valid after: any time
expire: never
```
```bash
kanidm person validity show demo_user --name idm_admin
valid after: 2020-09-25T21:22:04+10:00
expire: 2020-09-25T01:22:04+10:00
```
These datetimes are stored in the server as UTC, but presented according to your local system time
to aid correct understanding of when the events will occur.
You may set these time and date values in any timezone you wish (such as your local timezone), and
the server will transform these to UTC. These time values are in ISO8601 format, and you should
specify this as:
```shell
YYYY-MM-DDThh:mm:ssZ+-hh:mm
Year-Month-Day T hour:minutes:seconds Z +- timezone offset
```
Set the earliest time the account can start authenticating:
```bash
kanidm person validity begin-from demo_user '2020-09-25T11:22:04+00:00' --name idm_admin
```
Set the expiry or end date of the account:
```bash
kanidm person validity expire-at demo_user '2020-09-25T11:22:04+00:00' --name idm_admin
```
To unset or remove these values the following can be used, where `any|clear` means you may use
either `any` or `clear`.
```bash
kanidm person validity begin-from demo_user any|clear --name idm_admin
kanidm person validity expire-at demo_user clear|epoch|now --name idm_admin
```
To "lock" an account, you can set the `expire_at` value to `now` or `epoch`. Even in the situation
where the "valid from" is _after_ the `expire_at`, the `expire_at` will be respected.
These validity settings impact all authentication functions of the account (kanidm, ldap, radius).
### Allowing people accounts to change their mail attribute
By default, Kanidm allows an account to change some attributes, but not their mail address.
Adding the user to the `idm_people_self_write_mail` group, as shown below, allows the user to edit
their own mail.
```bash
kanidm group add-members idm_people_self_write_mail_priv demo_user --name idm_admin
```

223
book/src/accounts/policy.md Normal file
View file

@ -0,0 +1,223 @@
# Account Policy
Account Policy defines the security requirements that accounts must meet and influences users
sessions.
Policy is defined on groups so that membership of a group influences the security of its members.
This allows you to express that if you can access a system or resource, then the account must also
meet the policy requirements.
All account policy settings may be managed by members of `idm_account_policy_admins`. This is
assigned to `idm_admin` by default.
## Default Account Policy
A default Account Policy is applied to `idm_all_accounts`. This provides the defaults that influence
all accounts in Kanidm. This policy can be modified the same as any other group's policy.
## Enforced Attributes
### Auth Expiry
The maximum length in seconds that an authentication session may exist for.
### Password Minimum Length
The minimum length for passwords (if they are allowed).
### Privilege Expiry
The maximum length in seconds that privileges will exist after reauthentication for to a read/write
session.
### Webauthn Attestation
The list of certificate authorities and device aaguids that must be used by members of this policy.
This allows limiting devices to specific models.
To generate this list you should use `fido-mds-tool`.
## Policy Resolution
When an account is affected by multiple policies, the strictest component from each policy is
applied. This can mean that two policies interact and make their combination stricter than their
parts.
| value | ordering |
| ---------------------------- | ---------------------------- |
| auth-expiry | smallest value |
| password-minimum-length | largest value |
| privilege-expiry | smallest value |
| webauthn-attestation-ca-list | intersection of equal values |
### Example Resolution
If we had two policies where the first defined:
```text
auth-session: 86400
password-minimum-length: 10
privilege-expiry: 600
webauthn-attestation-ca-list: [ "yubikey 5ci", "yubikey 5fips" ]
```
And the second
```text
auth-session: 3600
password-minimum-length: 15
privilege-expiry: 3600
webauthn-attestation-ca-list: [ "yubikey 5fips", "feitian epass" ]
```
As the value of auth-session from the second is smaller we would take that. We would take the
smallest value of privilege-expiry from the first. We would take the largest value of
password-minimum-length. From the intersection of the webauthn attestation CA lists we would take
only the elements that are in both. This leaves:
```text
auth-session: 3600
password-minimum-length: 15
privilege-expiry: 600
webauthn-attestation-ca-list: [ "yubikey 5fips" ]
```
## Enabling Account Policy
Account Policy is enabled on a group with the command:
```shell
kanidm group account-policy enable <group name>
kanidm group account-policy enable my_admin_group
```
### Setting Maximum Session Time
The auth-session value influences the maximum time in seconds that an authenticated session can
exist. After this time, the user must reauthenticate.
This value provides a difficult balance - forcing frequent re-authentications can frustrate and
annoy users. However extremely long sessions allow a stolen or disclosed session token/device to
read data for an extended period. Due to Kanidm's read/write separation this mitigates the risk of
disclosed sessions as they can only _read_ data, not write it.
To set the maximum authentication session time
```shell
kanidm group account-policy auth-expiry <group name> <seconds>
kanidm group account-policy auth-expiry my_admin_group 86400
```
### Setting Minimum Password Length
The password-minimum-length value defines the character length of passwords that are acceptable.
There are no other tunables for passwords in account policy. Other settings such as complexity,
symbols, numbers and so on, have been proven to not matter in any real world attacks.
To set this value:
```shell
kanidm group account-policy password-minimum-length <group name> <length>
kanidm group account-policy password-minimum-length my_admin_group 12
```
### Setting Maximum Privilege Time
The privilege-expiry time defines how long a session retains its write privileges after a
reauthentication. After this time, the session returns to read-only mode.
To set the maximum privilege time
```shell
kanidm group account-policy privilege-expiry <group name> <seconds>
kanidm group account-policy privilege-expiry my_admin_group 900
```
### Setting Webauthn Attestation CA Lists
The list should be generated with `fido-mds-tool`. This will emit JSON that can be directly used
with Kanidm.
```bash
kanidm group account-policy webauthn-attestation-ca-list <group name> <attestation ca list json>
kanidm group account-policy webauthn-attestation-ca-list idm_all_persons '{"cas":{"D6E4b4Drh .... }'
```
> NOTE: `fido-mds-tool` is available in the `kanidm:tools` container.
## Global Settings
There are a small number of account policy settings that are set globally rather than on a per group
basis.
### Denied Names
Users of Kanidm can change their name at any time. However, there are some cases where you may wish
to deny some name values from being usable. This can be due to conflicting system account names or
to exclude insulting or other abusive terms.
To achieve this you can set names to be in the denied-name list:
```bash
kanidm system denied-names append <name> [<name> ...]
```
You can display the currently denied names with:
```bash
kanidm system denied-names show
```
To allow a name to be used again it can be removed from the list:
```
kanidm system denied-names remove <name> [<name> ...]
```
### Password Quality
Kanidm enforces that all passwords are checked by the library
"[zxcvbn](https://github.com/dropbox/zxcvbn)". This has a large number of checks for password
quality. It also provides constructive feedback to users on how to improve their passwords if they
are rejected.
Some things that zxcvbn looks for is use of the account name or email in the password, common
passwords, low entropy passwords, dates, reverse words and more.
This library can not be disabled - all passwords in Kanidm must pass this check.
### Password Badlisting
This is the process of configuring a list of passwords to exclude from being able to be used. This
is especially useful if a specific business has been notified of compromised accounts, allowing you
to maintain a list of customised excluded passwords.
The other value to this feature is being able to badlist common passwords that zxcvbn does not
detect, or from other large scale password compromises.
By default we ship with a preconfigured badlist that is updated over time as new password breach
lists are made available.
The password badlist by default is append only, meaning it can only grow, but will never remove
passwords previously considered breached.
You can display the current badlist with:
```bash
kanidm system pw-badlist show
```
You can update your own badlist with:
```bash
kanidm system pw-badlist upload "path/to/badlist" [...]
```
Multiple bad lists can be listed and uploaded at once. These are preprocessed to identify and remove
passwords that zxcvbn and our password rules would already have eliminated. That helps to make the
bad list more efficient to operate over at run time.
### Password Rotation
Kanidm will never support this "anti-feature". Password rotation encourages poor password hygiene
and is not shown to prevent any attacks - rather it _significantly weakens password security_.

View file

@ -72,7 +72,7 @@ process applications for HR/People that are capable of supplying this kind of da
### Enabling POSIX Attributes on Accounts
To enable POSIX account features and IDs on an account, you require the permission
`idm_account_unix_extend_priv`. This is provided to `idm_admins` in the default database.
`idm_unix_admins`. This is provided to `idm_admins` by default.
You can then use the following command to enable POSIX extensions on a person or service account.
@ -97,8 +97,8 @@ kanidm service-account posix show --name anonymous demo_account
### Enabling POSIX Attributes on Groups
To enable POSIX group features and IDs on an account, you require the permission
`idm_group_unix_extend_priv`. This is provided to `idm_admins` in the default database.
To enable POSIX group features and IDs on an account, you require the permission `idm_unix_admins`.
This is provided to `idm_admins` by default.
You can then use the following command to enable POSIX extensions:

View file

@ -0,0 +1,78 @@
# Service Accounts
## Creating Service Accounts
Members of `idm_service_account_admins` have the privileges to create new service accounts. By
default `idm_admin` has this access.
When creating a service account you must delegate entry management to another group or account. This
allows other users or groups to update the service account.
The `entry_managed_by` attribute of a service account may be created and modified by members of
`idm_service_account_admins`.
> NOTE: If a service account is a member of `idm_high_privilege` its `entry_managed_by` may only be
> modified by members of `idm_access_control_admins`
```bash
kanidm service-account create <ACCOUNT_ID> <display-name> <entry-managed-by>
kanidm service-account create demo_service "Demonstration Service" demo_group --name idm_admin
kanidm service-account get demo_service --name idm_admin
```
By delegating the administration of this service account to `demo_group` this allows our `demo_user`
to administer the service account.
## Using API Tokens with Service Accounts
Service accounts can have API tokens generated and associated with them. These tokens can be used
for identification of the service account, and for granting extended access rights where the service
account may previously have not had the access. Additionally service accounts can have expiry times
and other auditing information attached.
To show API tokens for a service account:
```bash
kanidm service-account api-token status --name ENTRY_MANAGER ACCOUNT_ID
kanidm service-account api-token status --name demo_user demo_service
```
By default API tokens are issued to be "read only", so they are unable to make changes on behalf of
the service account they represent. To generate a new read only API token with optional expiry time:
```bash
kanidm service-account api-token generate --name ENTRY_MANAGER ACCOUNT_ID LABEL [EXPIRY]
kanidm service-account api-token generate --name demo_user demo_service "Test Token"
kanidm service-account api-token generate --name demo_user demo_service "Test Token" 2020-09-25T11:22:02+10:00
```
If you wish to issue a token that is able to make changes on behalf of the service account, you must
add the `--rw` flag during the generate command. It is recommended you only add `--rw` when the API
token is performing writes to Kanidm.
```bash
kanidm service-account api-token generate --name ENTRY_MANAGER ACCOUNT_ID LABEL [EXPIRY] --rw
kanidm service-account api-token generate --name demo_user demo_service "Test Token" --rw
kanidm service-account api-token generate --name demo_user demo_service "Test Token" 2020-09-25T11:22:02+10:00 --rw
```
To destroy (revoke) an API token you will need its token id. This can be shown with the "status"
command.
```bash
kanidm service-account api-token status --name ENTRY_MANAGER ACCOUNT_ID
kanidm service-account api-token status --name demo_user demo_service
kanidm service-account api-token destroy --name ENTRY_MANAGER ACCOUNT_ID TOKEN_ID
kanidm service-account api-token destroy --name demo_user demo_service 4de2a4e9-e06a-4c5e-8a1b-33f4e7dd5dc7
```
## API Tokens with LDAP
API tokens can also be used to gain extended search permissions with LDAP. To do this you can bind
with a dn of `dn=token` and provide the API token as the password.
```bash
ldapwhoami -H ldaps://URL -x -D "dn=token" -w "TOKEN"
ldapwhoami -H ldaps://idm.example.com -x -D "dn=token" -w "..."
# u: demo_service@idm.example.com
```

View file

@ -1,345 +0,0 @@
# Accounts and groups
Accounts and Groups are the primary reasons for Kanidm to exist. Kanidm is optimised as a repository
for these data. As a result, there are many concepts and important details to understand.
## Service Accounts vs Person Accounts
Kanidm separates accounts into two types. Person accounts (or persons) are intended for use by
humans that will access the system in an interactive way. Service accounts are intended for use by
computers or services that need to identify themself to Kanidm. Generally a person or group of
persons will be responsible for and will manage service accounts. Because of this distinction these
classes of accounts have different properties and methods of authentication and management.
## Groups
Groups represent a collection of entities. This generally is a collection of persons or service
accounts. Groups are commonly used to assign privileges to the accounts that are members of a group.
This allows easier administration over larger systems where privileges can be assigned to groups in
a logical manner, and then only membership of the groups need administration, rather than needing to
assign privileges to each entity directly and uniquely.
Groups may also be nested, where a group can contain another group as a member. This allows
hierarchies to be created again for easier administration.
## Default Accounts and Groups
Kanidm ships with a number of default service accounts and groups. This is to give you the best
out-of-box experience possible, as well as supplying best practice examples related to modern
Identity Management (IDM) systems.
There are two builtin system administration accounts.
`admin` is the default service account which has privileges to configure and administer kanidm as a
whole. This account can manage access controls, schema, integrations and more. However the `admin`
can not manage persons by default to separate the privileges. As this is a service account it is
intended for limited use.
`idm_admin` is the default service account which has privileges to create persons and to manage
these accounts and groups. They can perform credential resets and more.
Both the `admin` and the `idm_admin` user should _NOT_ be used for daily activities - they exist for
initial system configuration, and for disaster recovery scenarios. You should delegate permissions
as required to named user accounts instead.
The majority of the builtin groups are privilege groups that provide rights over Kanidm
administrative actions. These include groups for account management, person management (personal and
sensitive data), group management, and more.
## Recovering the Initial Admin Accounts
By default the `admin` and `idm_admin` accounts have no password, and can not be accessed. They need
to be "recovered" from the server that is running the kanidmd server.
You should have already recovered the admin account during your setup process. If not refer to the
[server configuration chapter](server_configuration.md#default-admin-account) on how to recover this
account.
Once you have access to the admin account, it is able to reset the credentials of the `idm_admin`
account.
```bash
kanidm login -D admin
kanidm service-account credential generate -D admin idm_admin
# Success: wJX...
```
These accounts will be used through the remainder of this document for managing the server.
## Viewing Default Groups
You should take some time to inspect the default groups which are related to default permissions.
These can be viewed with:
```bash
kanidm group list
kanidm group get <name>
```
## Creating Person Accounts
By default `idm_admin` has the privileges to create new persons in the system.
```bash
kanidm login --name idm_admin
kanidm person create demo_user "Demonstration User" --name idm_admin
kanidm person get demo_user --name idm_admin
kanidm group create demo_group --name idm_admin
kanidm group add-members demo_group demo_user --name idm_admin
kanidm group list-members demo_group --name idm_admin
```
You can also use anonymous to view accounts and groups - note that you won't see certain fields due
to the limits of the access control anonymous access profile.
```bash
kanidm login --name anonymous
kanidm person get demo_user --name anonymous
```
Kanidm allows person accounts to include human related attributes, such as their legal name and
email address.
Initially, a person does not have these attributes. If desired, a person may be modified to have
these attributes.
```bash
# Note, both the --legalname and --mail flags may be omitted
kanidm person update demo_user --legalname "initial name" --mail "initial@email.address"
```
<!-- deno-fmt-ignore-start -->
{{#template templates/kani-warning.md
imagepath=images
title=Warning!
text=Persons may change their own displayname, name, and legal name at any time. You MUST NOT use these values as primary keys in external systems. You MUST use the `uuid` attribute present on all entries as an external primary key.
}}
<!-- deno-fmt-ignore-end -->
## Creating Service Accounts
The `admin` service account can be used to create service accounts.
```bash
kanidm service-account create demo_service "Demonstration Service" --name admin
kanidm service-account get demo_service --name admin
```
## Using API Tokens with Service Accounts
Service accounts can have api tokens generated and associated with them. These tokens can be used
for identification of the service account, and for granting extended access rights where the service
account may previously have not had the access. Additionally service accounts can have expiry times
and other auditing information attached.
To show api tokens for a service account:
```bash
kanidm service-account api-token status --name idm_admin ACCOUNT_ID
kanidm service-account api-token status --name idm_admin demo_service
```
By default api tokens are issued to be "read only", so they are unable to make changes on behalf of
the service account they represent. To generate a new read only api token:
```bash
kanidm service-account api-token generate --name idm_admin ACCOUNT_ID LABEL [EXPIRY]
kanidm service-account api-token generate --name idm_admin demo_service "Test Token"
kanidm service-account api-token generate --name idm_admin demo_service "Test Token" 2020-09-25T11:22:02+10:00
```
If you wish to issue a token that is able to make changes on behalf of the service account, you must
add the "--rw" flag during the generate command. It is recommended you only add --rw when the
api-token is performing writes to Kanidm.
```bash
kanidm service-account api-token generate --name idm_admin ACCOUNT_ID LABEL [EXPIRY] --rw
kanidm service-account api-token generate --name idm_admin demo_service "Test Token" --rw
kanidm service-account api-token generate --name idm_admin demo_service "Test Token" 2020-09-25T11:22:02+10:00 --rw
```
To destroy (revoke) an api token you will need it's token id. This can be shown with the "status"
command.
```bash
kanidm service-account api-token destroy --name idm_admin ACCOUNT_ID TOKEN_ID
kanidm service-account api-token destroy --name idm_admin demo_service 4de2a4e9-e06a-4c5e-8a1b-33f4e7dd5dc7
```
Api tokens can also be used to gain extended search permissions with LDAP. To do this you can bind
with a dn of `dn=token` and provide the api token in the password.
```bash
ldapwhoami -H ldaps://URL -x -D "dn=token" -w "TOKEN"
ldapwhoami -H ldaps://idm.example.com -x -D "dn=token" -w "..."
# u: demo_service@idm.example.com
```
## Resetting Service Account Credentials (Deprecated)
<!-- deno-fmt-ignore-start -->
{{#template templates/kani-warning.md
imagepath=images
text=Api Tokens are a better method to manage credentials for service accounts, and passwords may be removed in the future!
}}
<!-- deno-fmt-ignore-end -->
Service accounts can not have their credentials interactively updated in the same manner as persons.
Service accounts may only have server side generated high entropy passwords.
To re-generate this password to an account
```bash
kanidm service-account credential generate demo_service --name admin
```
## Nested Groups
Kanidm supports groups being members of groups, allowing nested groups. These nesting relationships
are shown through the "memberof" attribute on groups and accounts.
Kanidm makes all group membership determinations by inspecting an entry's "memberof" attribute.
An example can be easily shown with:
```bash
kanidm group create group_1 --name idm_admin
kanidm group create group_2 --name idm_admin
kanidm person create nest_example "Nesting Account Example" --name idm_admin
kanidm group add-members group_1 group_2 --name idm_admin
kanidm group add-members group_2 nest_example --name idm_admin
kanidm person get nest_example --name anonymous
```
## Account Validity
Kanidm supports accounts that are only able to authenticate between a pair of dates and times; the
"valid from" and "expires" timestamps define these points in time.
This can be displayed with:
```bash
kanidm person validity show demo_user --name idm_admin
valid after: 2020-09-25T21:22:04+10:00
expire: 2020-09-25T01:22:04+10:00
```
These datetimes are stored in the server as UTC, but presented according to your local system time
to aid correct understanding of when the events will occur.
To set the values, an account with account management permission is required (for example,
idm_admin).
You may set these time and date values in any timezone you wish (such as your local timezone), and
the server will transform these to UTC. These time values are in iso8601 format, and you should
specify this as:
```shell
YYYY-MM-DDThh:mm:ssZ+-hh:mm
Year-Month-Day T hour:minutes:seconds Z +- timezone offset
```
Set the earliest time the account can start authenticating:
```bash
kanidm person validity begin_from demo_user '2020-09-25T11:22:04+00:00' --name idm_admin
```
Set the expiry or end date of the account:
```bash
kanidm person validity expire_at demo_user '2020-09-25T11:22:04+00:00' --name idm_admin
```
To unset or remove these values the following can be used, where `any|clear` means you may use
either `any` or `clear`.
```bash
kanidm person validity begin_from demo_user any|clear --name idm_admin
kanidm person validity expire_at demo_user never|clear --name idm_admin
```
To "lock" an account, you can set the expire_at value to the past, or unix epoch. Even in the
situation where the "valid from" is _after_ the expire_at, the expire_at will be respected.
```bash
kanidm person validity expire_at demo_user 1970-01-01T00:00:00+00:00 --name idm_admin
```
These validity settings impact all authentication functions of the account (kanidm, ldap, radius).
### Allowing people accounts to change their mail attribute
By default, Kanidm allows an account to change some attributes, but not their mail address.
Adding the user to the `idm_people_self_write_mail` group, as shown below, allows the user to edit
their own mail.
```bash
kanidm group add-members idm_people_self_write_mail_priv demo_user --name idm_admin
```
### Denied Names
Users of Kanidm can change their name at any time. However, there are some cases where you may wish
to deny some name values from being usable.
To achieve this you can set names to be in the denied-name list:
```bash
kanidm system denied-names append <name> [<name> ...]
```
You can display the currently denied names with:
```bash
kanidm system denied-names show
```
To allow a name to be used again it can be removed from the list:
```
kanidm system denied-names remove <name> [<name> ...]
```
## Why Can't I Change admin With idm\_admin?
As a security mechanism there is a distinction between "accounts" and "high permission accounts".
This is to help prevent elevation attacks, where say a member of a service desk could attempt to
reset the password of idm\_admin or admin, or even a member of HR or System Admin teams to move
laterally.
Generally, membership of a "privilege" group that ships with Kanidm, such as:
- idm\_account\_manage\_priv
- idm\_people\_read\_priv
- idm\_schema\_manage\_priv
- many more ...
...indirectly grants you membership to "idm\_high\_privilege". If you are a member of this group,
the standard "account" and "people" rights groups are NOT able to alter, read or manage these
accounts. To manage these accounts higher rights are required, such as those held by the admin
account are required.
Further, groups that are considered "idm\_high\_privilege" can NOT be managed by the standard
"idm\_group\_manage\_priv" group.
Management of high privilege accounts and groups is granted through the the "hp" variants of all
privileges. A non-conclusive list:
- idm\_hp\_account\_read\_priv
- idm\_hp\_account\_manage\_priv
- idm\_hp\_account\_write\_priv
- idm\_hp\_group\_manage\_priv
- idm\_hp\_group\_write\_priv
Membership of any of these groups should be considered to be equivalent to system administration
rights in the directory, and by extension, over all network resources that trust Kanidm.
All groups that are flagged as "idm\_high\_privilege" should be audited and monitored to ensure that
they are not altered.

View file

@ -76,7 +76,8 @@ between them. This provides proper isolation between the instances.
`idm.local` - This is a bad example as `.local` is an mDNS domain name suffix which means that
client machines if they visit another network _may_ try to contact `idm.local` believing they are on
their usual network. If TLS verification were disabled, this would allow leaking of credentials.
their usual network. If TLS certificate verification were disabled, this would allow leaking of
credentials.
`kanidm.com` - This is bad because the use of the top level domain means that any subdomain can
access the cookies issued by `kanidm.com`, effectively leaking them to all other hosts.

View file

@ -10,8 +10,6 @@ You can configure `kanidm` to help make commands simpler by modifying `~/.config
```toml
uri = "https://idm.example.com"
verify_ca = true|false
verify_hostnames = true|false
ca_path = "/path/to/ca.pem"
```
@ -32,6 +30,8 @@ establish a session token.
```bash
kanidm login --name USERNAME
kanidm login --name admin
kanidm login -D USERNAME
kanidm login -D admin
```
Once complete, you can use `kanidm` without re-authenticating for a period of time for
@ -43,8 +43,7 @@ You can list active sessions with:
kanidm session list
```
Sessions will expire after a period of time (by default 1 hour). To remove these expired sessions
locally you can use:
Sessions will expire after a period of time. To remove these expired sessions locally you can use:
```bash
kanidm session cleanup

View file

@ -9,10 +9,10 @@ projects can come in different forms so I'll answer to a few of them:
## Is the library in Rust?
If it's not in Rust, it's not eligible for inclusion. There is a single exception today (rlm
python) but it's very likely this will also be removed in the future. Keeping a single language
helps with testing, but also makes the project more accessible and consistent to developers.
Additionally, features exist in Rust that help to improve the quality of the project from development to
If it's not in Rust, it's not eligible for inclusion. There is a single exception today (rlm python)
but it's very likely this will also be removed in the future. Keeping a single language helps with
testing, but also makes the project more accessible and consistent to developers. Additionally,
features exist in Rust that help to improve the quality of the project from development to
production.
## Is the project going to create a microservice like architecture?
@ -93,9 +93,9 @@ correctly increment/advance between the servers. However, Mongo is not aware of
would not be able to give the experience we desire. Mongo is a very good database, it's just not the
right choice for Kanidm.
Additionally, it's worth noting that most of these other databases would violate the previous desires
to keep the language as Rust and may require external configuration or daemons which may not be
possible to test.
Additionally, it's worth noting that most of these other databases would violate the previous
desires to keep the language as Rust and may require external configuration or daemons which may not
be possible to test.
## How PAM/nsswitch Work

View file

@ -120,35 +120,9 @@ alias kanidm="docker run ..."
The tools are available as a cargo download if you have a rust tool chain available. To install rust
you should follow the documentation for [rustup](https://rustup.rs/). These will be installed into
your home directory. To update these, re-run the install command. You will likely need to install additional development libraries, specified in the [Developer Guide](DEVELOPER_README.html).
your home directory. To update these, re-run the install command. You will likely need to install
additional development libraries, specified in the [Developer Guide](DEVELOPER_README.html).
```bash
cargo install kanidm_tools
```
## Initializing the configuration
The client requires a configuration file to connect to the server. This should be at
`/etc/kanidm/config` or `~/.config/kanidm`, and configures the kanidm command line tool.
Here is a minimal example:
```toml
uri = "https://idm.example.com"
verify_ca = true
verify_hostnames = true
```
## Checking that the tools work
Now you can check your instance is working. You may need to provide a CA certificate for
verification with the -C parameter:
```bash
kanidm login --name anonymous
kanidm self whoami -H https://localhost:8443 --name anonymous
kanidm self whoami -C ../path/to/ca.pem -H https://localhost:8443 --name anonymous
```
Now you can take some time to look at what commands are available - please
[ask for help at any time](https://github.com/kanidm/kanidm#getting-in-contact--questions).

View file

@ -38,8 +38,8 @@ systemctl status kanidm-unixd-tasks
```
> **NOTE** The `kanidm_unixd_tasks` daemon is not required for PAM and nsswitch functionality. If
> disabled, your system will function as usual. It is however strongly recommended due to the features it
> provides supporting Kanidm's capabilities.
> disabled, your system will function as usual. It is however strongly recommended due to the
> features it provides supporting Kanidm's capabilities.
Both unixd daemons use the connection configuration from /etc/kanidm/config. This is the covered in
[client_tools](../client_tools.md#kanidm-configuration).
@ -47,7 +47,7 @@ Both unixd daemons use the connection configuration from /etc/kanidm/config. Thi
You can also configure some unixd-specific options with the file /etc/kanidm/unixd:
```toml
{{#rustdoc_include ../../examples/unixd}}
{{#rustdoc_include ../../../examples/unixd}}
```
> **NOTICE:** All users in Kanidm can change their name (and their spn) at any time. If you change

View file

@ -6,33 +6,35 @@ authentication and authorisation within a technical environment.
The intent of the Kanidm project is to:
- Provide a single truth source for accounts, groups and privileges.
- Enable integrations to systems and services so they can authenticate accounts.
- Enable integrations to systems and services so they can trust Kanidm to authenticate accounts.
- Make system, network, application and web authentication easy and accessible.
- Secure and reliable by default, aiming for the highest levels of quality.
- Secure and reliable by default, aiming for the highest levels of quality and stability.
## Why do I want Kanidm?
Whether you work in a business, a volunteer organisation, or are an enthusiast who manages their
personal services, you need methods of authenticating and identifying to your systems, and
subsequently, ways to determine what authorisation and privileges you have while accessing these
systems.
personal services, you need methods of authenticating and identifying to your systems. These systems
also need to determine what authorisation and privileges you have while accessing them.
We've probably all been in workplaces where you end up with multiple accounts on various systems -
one for a workstation, different SSH keys for different tasks, maybe some shared account passwords.
Not only is it difficult for people to manage all these different credentials and what they have
access to, but it also means that sometimes these credentials have more access or privilege than
they require.
they require. In the worst case this can lead to weak credentials (`corpname123` is a common
example) or credentials that are disclosed via git repos.
Kanidm acts as a central authority of accounts in your organisation and allows each account to
associate many devices and credentials with different privileges. An example of how this looks:
Kanidm solves this problem by acting as a central authority of accounts in your organisation. This
allows each account to associate many devices and strong credentials with different privileges. An
example of how this looks:
<img src="images/KanidmUseCases-Light.png" alt="Kanidm Use Case Diagram" class="light-mode-only" />
<img src="images/KanidmUseCases-Dark.png" alt="Kanidm Use Case Diagram" class="dark-mode-only" />
A key design goal is that you authenticate with your device in some manner, and then your device
will continue to authenticate you in the future. Each of these different types of credentials, from
SSH keys, application passwords, to RADIUS passwords and others, are "things your device knows".
Each password has limited capability, and can only access that exact service or resource.
SSH keys, application passwords, to RADIUS passwords and others, are "things your device knows" or
"things your device has". Each credential has limited capability and scope, and can only access that
exact service or resource.
This helps improve security; a compromise of the service or the network transmission does not grant
you unlimited access to your account and all its privileges. As the credentials are specific to a
@ -42,7 +44,7 @@ is compromised, only the credentials for that service need to be revoked.
Due to this model, and the design of Kanidm to centre the device and to have more per-service
credentials, workflows and automation are added or designed to reduce human handling.
## Library documentation
## For Developers
Looking for the `rustdoc` documentation for the libraries themselves?
[Click here!](https://kanidm.com/documentation/)

View file

@ -1,56 +0,0 @@
# Password Quality and Badlisting
Kanidm embeds a set of tools to help your users use and create strong passwords. This is important
as not all user types will require multi-factor authentication (MFA) for their roles, but
compromised accounts still pose a risk. There may also be deployment or other barriers to a site
rolling out sitewide MFA.
## Quality Checking
Kanidm enforces that all passwords are checked by the library
"[zxcvbn](https://github.com/dropbox/zxcvbn)". This has a large number of checks for password
quality. It also provides constructive feedback to users on how to improve their passwords if they
are rejected.
Some things that zxcvbn looks for is use of the account name or email in the password, common
passwords, low entropy passwords, dates, reverse words and more.
This library can not be disabled - all passwords in Kanidm must pass this check.
## Password Badlisting
This is the process of configuring a list of passwords to exclude from being able to be used. This
is especially useful if a specific business has been notified of compromised accounts, allowing you
to maintain a list of customised excluded passwords.
The other value to this feature is being able to badlist common passwords that zxcvbn does not
detect, or from other large scale password compromises.
By default we ship with a preconfigured badlist that is updated over time as new password breach
lists are made available.
The password badlist by default is append only, meaning it can only grow, but will never remove
passwords previously considered breached.
### Updating your own Badlist
You can display the current badlist with:
```bash
kanidm system pw-badlist show
```
You can update your own badlist with:
```bash
kanidm system pw-badlist upload "path/to/badlist" [...]
```
Multiple bad lists can be listed and uploaded at once. These are preprocessed to identify and remove
passwords that zxcvbn and our password rules would already have eliminated. That helps to make the
bad list more efficient to operate over at run time.
## Password Rotation
Kanidm will never support this "anti-feature". Password rotation encourages poor password hygiene
and is not shown to prevent any attacks.

View file

@ -55,13 +55,22 @@ docker run --rm -i -t -v kanidmd:/data \
docker start kanidmd
```
### Recover the admin password
### Recover the Admin Role Passwords
The `admin` account is used to configure Kanidm itself.
```bash
docker exec -i -t kanidmd \
kanidmd recover-account admin
```
The `idm_admin` account is used to manage persons and groups.
```
docker exec -i -t kanidmd \
kanidmd recover-account idm_admin
```
### Setup the client configuration
```toml
@ -74,9 +83,23 @@ verify_ca = false
### Check you can login
```bash
kanidm login
kanidm login --name idm_admin
```
### Create an account for yourself
```
kanidm person create <your username> <Your Displayname>
```
### Setup your account credentials
```
kanidm person credential create-reset-token <your username>
```
Then follow the presented steps.
### What next?
You can now follow the steps in the [administration section](administrivia.md)

View file

@ -154,4 +154,7 @@ docker run --rm -i -t -u 1000:1000 -v kanidmd:/data kanidm/server:latest /sbin/k
## Minimum TLS key lengths
We enforce a minimum RSA key length of 2048 bits, and ECDSA keys need 224 bits.
We enforce a minimum RSA and ECDSA key sizes. If your key is insufficently large, the server will
refuse to start and inform you of this.
Currently accepted key sizes are minimum 2048 bit RSA and 224 bit ECDSA.

View file

@ -1,5 +1,7 @@
# Configuring the Server
In this section we will configure your server and create its container instance.
## Configuring server.toml
You need a configuration file in the volume named `server.toml`. (Within the container it should be
@ -26,7 +28,7 @@ text=You MUST set the `domain` name correctly, aligned with your `origin`, else
<!-- deno-fmt-ignore-end -->
## Check the configuration is valid
### Check the configuration is valid
You should test your configuration is valid before you proceed. This defaults to using
`-c /data/server.toml`.
@ -45,7 +47,7 @@ Now we can run the server so that it can accept connections. This defaults to us
docker run -p 443:8443 -v kanidmd:/data kanidm/server:latest
```
## Using the NET\_BIND\_SERVICE capability
### Using the NET\_BIND\_SERVICE capability
If you plan to run without using docker port mapping or some other reverse proxy, and your
bindaddress or ldapbindaddress port is less than `1024` you will need the `NET_BIND_SERVICE` in
@ -66,14 +68,26 @@ text=However you choose to run your server, you should document and keep note of
<!-- deno-fmt-ignore-end -->
## Default Admin Account
### Default Admin Accounts
Now that the server is running, you can initialise the default admin account. This command will
generate a new random password for the admin account. You must run this command as the same user as
the kanidmd process or as root. This defaults to using `-c /data/server.toml`.
Now that the server is running, you can initialise the default admin accounts. There are two
parallel admin accounts that have seperate functions. `admin` which manages Kanidm's configuration,
and `idm_admin` which manages accounts and groups in Kanidm.
You should consider these as "break-glass" accounts. They exist to allow the server to be
bootstrapped and accessed in emergencies. They are not intended for day-to-day use.
These commands will generate a new random password for the admin accounts. You must run the commands
as the same user as the kanidmd process or as root. This defaults to using `-c /data/server.toml`.
```bash
docker exec -i -t <container name> \
kanidmd recover-account admin
# new_password: "xjgG4..."
```
```bash
docker exec -i -t <container name> \
kanidmd recover-account idm_admin
# new_password: "9Eux1..."
```

View file

@ -50,14 +50,15 @@ text=Downgrades are not possible. It is critical you know how to backup and rest
<!-- deno-fmt-ignore-end -->
Docker updates by deleting and recreating the instance. All that needs to be preserved is contained
in your storage volume.
Docker updates operate by deleting and recreating the container. All state that needs to be
preserved is within your storage volume.
```bash
docker stop <previous instance name>
```
You can test that your configuration is correct, and the server should correctly start.
You can test that your configuration is correct with the new version, and the server should
correctly start.
```bash
docker run --rm -i -t -v kanidmd:/data \
@ -89,7 +90,9 @@ docker start <previous instance name>
If you deleted the previous instance, you can recreate it from your preserved tag instead.
```bash
docker run -p ports -v volumes kanidm/server:<DATE>
docker run [Your Arguments Here] -v kanidmd:/data \
OTHER_CUSTOM_OPTIONS \
kanidm/server:<DATE>
```
If the server from your previous version fails to start, you will need to restore from backup.

View file

@ -41,7 +41,7 @@ db_path = "/var/lib/private/kanidm/kanidm.db"
# Minimum value is 256. If unset
# an automatic heuristic is used to scale this.
# You should only adjust this value if you experience
# pressure on your system.
# memory pressure on your system.
# db_arc_size = 2048
#
# TLS chain and key in pem format. Both must be present
@ -50,7 +50,8 @@ tls_key = "/var/lib/private/kanidm/key.pem"
#
# The log level of the server. May be one of info, debug, trace
#
# NOTE: this is overridden by environment variables at runtime
# NOTE: this can be overridden by the environment variable
# `KANIDM_LOG_LEVEL` at runtime
# Defaults to "info"
# log_level = "info"
#
@ -59,21 +60,22 @@ tls_key = "/var/lib/private/kanidm/key.pem"
# such as webauthn, so it *must* match your DNS
# hostname. It is used to create
# security principal names such as `william@idm.example.com`
# so that in a (future)
# trust configuration it is possible to have unique Security
# Principal Names (spns) throughout the topology.
# so that in a (future) trust configuration it is possible
# to have unique Security Principal Names (spns) throughout
# the topology.
#
# ⚠️ WARNING ⚠️
#
# Changing this value WILL break many types of registered
# credentials for accounts
# including but not limited to webauthn, oauth tokens, and more.
# credentials for accounts including but not limited to
# webauthn, oauth tokens, and more.
# If you change this value you *must* run
# `kanidmd domain_name_change` immediately after.
domain = "idm.example.com"
#
# The origin for webauthn. This is the url to the server,
# with the port included if
# it is non-standard (any port except 443). This must match
# or be a descendent of the
# with the port included if it is non-standard (any port
# except 443). This must match or be a descendent of the
# domain name you configure above. If these two items are
# not consistent, the server WILL refuse to start!
# origin = "https://idm.example.com"

View file

@ -41,7 +41,7 @@ db_path = "/data/kanidm.db"
# Minimum value is 256. If unset
# an automatic heuristic is used to scale this.
# You should only adjust this value if you experience
# pressure on your system.
# memory pressure on your system.
# db_arc_size = 2048
#
# TLS chain and key in pem format. Both must be present
@ -50,7 +50,8 @@ tls_key = "/data/key.pem"
#
# The log level of the server. May be one of info, debug, trace
#
# NOTE: this is overridden by environment variables at runtime
# NOTE: this can be overridden by the environment variable
# `KANIDM_LOG_LEVEL` at runtime
# Defaults to "info"
# log_level = "info"
#
@ -59,21 +60,22 @@ tls_key = "/data/key.pem"
# such as webauthn, so it *must* match your DNS
# hostname. It is used to create
# security principal names such as `william@idm.example.com`
# so that in a (future)
# trust configuration it is possible to have unique Security
# Principal Names (spns) throughout the topology.
# so that in a (future) trust configuration it is possible
# to have unique Security Principal Names (spns) throughout
# the topology.
#
# ⚠️ WARNING ⚠️
#
# Changing this value WILL break many types of registered
# credentials for accounts
# including but not limited to webauthn, oauth tokens, and more.
# credentials for accounts including but not limited to
# webauthn, oauth tokens, and more.
# If you change this value you *must* run
# `kanidmd domain_name_change` immediately after.
domain = "idm.example.com"
#
# The origin for webauthn. This is the url to the server,
# with the port included if
# it is non-standard (any port except 443). This must match
# or be a descendent of the
# with the port included if it is non-standard (any port
# except 443). This must match or be a descendent of the
# domain name you configure above. If these two items are
# not consistent, the server WILL refuse to start!
# origin = "https://idm.example.com"

View file

@ -26,7 +26,8 @@ use std::time::Duration;
use kanidm_proto::constants::uri::V1_AUTH_VALID;
use kanidm_proto::constants::{
APPLICATION_JSON, ATTR_NAME, CLIENT_TOKEN_CACHE, KOPID, KSESSIONID, KVERSION,
APPLICATION_JSON, ATTR_ENTRY_MANAGED_BY, ATTR_NAME, CLIENT_TOKEN_CACHE, KOPID, KSESSIONID,
KVERSION,
};
use kanidm_proto::v1::*;
use reqwest::header::CONTENT_TYPE;
@ -1551,16 +1552,38 @@ impl KanidmClient {
.await
}
pub async fn idm_group_create(&self, name: &str) -> Result<(), ClientError> {
pub async fn idm_group_create(
&self,
name: &str,
entry_managed_by: Option<&str>,
) -> Result<(), ClientError> {
let mut new_group = Entry {
attrs: BTreeMap::new(),
};
new_group
.attrs
.insert(ATTR_NAME.to_string(), vec![name.to_string()]);
if let Some(entry_manager) = entry_managed_by {
new_group.attrs.insert(
ATTR_ENTRY_MANAGED_BY.to_string(),
vec![entry_manager.to_string()],
);
}
self.perform_post_request("/v1/group", new_group).await
}
pub async fn idm_group_set_entry_managed_by(
&self,
id: &str,
entry_manager: &str,
) -> Result<(), ClientError> {
let data = vec![entry_manager];
self.perform_put_request(&format!("/v1/group/{}/_attr/entry_managed_by", id), data)
.await
}
pub async fn idm_group_set_members(
&self,
id: &str,

View file

@ -119,18 +119,6 @@ impl KanidmClient {
.await
}
pub async fn idm_person_account_primary_credential_import_password(
&self,
id: &str,
pw: &str,
) -> Result<(), ClientError> {
self.perform_put_request(
format!("/v1/person/{}/_attr/password_import", id).as_str(),
vec![pw.to_string()],
)
.await
}
pub async fn idm_person_account_get_credential_status(
&self,
id: &str,

View file

@ -1,6 +1,6 @@
use std::collections::BTreeMap;
use kanidm_proto::constants::{ATTR_DISPLAYNAME, ATTR_MAIL, ATTR_NAME};
use kanidm_proto::constants::{ATTR_DISPLAYNAME, ATTR_ENTRY_MANAGED_BY, ATTR_MAIL, ATTR_NAME};
use kanidm_proto::v1::{AccountUnixExtend, ApiToken, ApiTokenGenerate, CredentialStatus, Entry};
use time::OffsetDateTime;
use uuid::Uuid;
@ -22,6 +22,7 @@ impl KanidmClient {
&self,
name: &str,
displayname: &str,
entry_managed_by: &str,
) -> Result<(), ClientError> {
let mut new_acct = Entry {
attrs: BTreeMap::new(),
@ -32,6 +33,11 @@ impl KanidmClient {
new_acct
.attrs
.insert(ATTR_DISPLAYNAME.to_string(), vec![displayname.to_string()]);
new_acct.attrs.insert(
ATTR_ENTRY_MANAGED_BY.to_string(),
vec![entry_managed_by.to_string()],
);
self.perform_post_request("/v1/service_account", new_acct)
.await
}
@ -46,6 +52,7 @@ impl KanidmClient {
id: &str,
newname: Option<&str>,
displayname: Option<&str>,
entry_managed_by: Option<&str>,
mail: Option<&[String]>,
) -> Result<(), ClientError> {
let mut update_entry = Entry {
@ -57,12 +64,21 @@ impl KanidmClient {
.attrs
.insert(ATTR_NAME.to_string(), vec![newname.to_string()]);
}
if let Some(newdisplayname) = displayname {
update_entry.attrs.insert(
ATTR_DISPLAYNAME.to_string(),
vec![newdisplayname.to_string()],
);
}
if let Some(entry_managed_by) = entry_managed_by {
update_entry.attrs.insert(
ATTR_ENTRY_MANAGED_BY.to_string(),
vec![entry_managed_by.to_string()],
);
}
if let Some(mail) = mail {
update_entry
.attrs

View file

@ -34,7 +34,6 @@ CROSS_CONFIG=platform/crossbuild/ubuntu-22.04/Cross.toml \
--bin kanidm_ssh_authorizedkeys \
--bin kanidm-unix \
--release
```
Things will end up in `./target/aarch64-unknown-linux-gnu/release/`

View file

@ -865,6 +865,7 @@ pub async fn create_server_core(
match &config.integration_test_config {
Some(itc) => {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
// We need to get the admin pw.
match idms_prox_write.recover_account("admin", Some(&itc.admin_password)) {
Ok(_) => {}
Err(e) => {
@ -875,6 +876,22 @@ pub async fn create_server_core(
return Err(());
}
};
// Add admin to idm_admins to allow tests more flexibility wrt to permissions.
// This way our default access controls can be stricter to prevent lateral
// movement.
match idms_prox_write.qs_write.internal_modify_uuid(
UUID_IDM_ADMINS,
&ModifyList::new_append(Attribute::Member, Value::Refer(UUID_ADMIN)),
) {
Ok(_) => {}
Err(e) => {
error!(
"Unable to configure INTEGRATION TEST admin as member of idm_admins -> {:?}",
e
);
return Err(());
}
}
match idms_prox_write.commit() {
Ok(_) => {}
Err(e) => {

File diff suppressed because it is too large Load diff

View file

@ -738,7 +738,7 @@ lazy_static! {
Attribute::Description,
Value::new_utf8s("System (local) info and metadata object.")
),
(Attribute::Version, Value::Uint32(16))
(Attribute::Version, Value::Uint32(17))
);
pub static ref E_DOMAIN_INFO_V1: EntryInitNew = entry_init!(

View file

@ -10,6 +10,7 @@ pub struct BuiltinGroup {
pub description: &'static str,
pub uuid: uuid::Uuid,
pub members: Vec<uuid::Uuid>,
pub entry_managed_by: Option<uuid::Uuid>,
pub dyngroup: bool,
pub dyngroup_filter: Option<Filter>,
pub extra_attributes: Vec<(Attribute, Value)>,
@ -47,6 +48,11 @@ impl TryFrom<BuiltinGroup> for EntryInitNew {
}
};
}
if let Some(entry_manager) = val.entry_managed_by {
entry.add_ava(Attribute::EntryManagedBy, Value::Refer(entry_manager));
}
entry.add_ava(Attribute::Uuid, Value::Uuid(val.uuid));
entry.set_ava(
Attribute::Member,
@ -65,201 +71,133 @@ impl TryFrom<BuiltinGroup> for EntryInitNew {
}
lazy_static! {
/// Builtin IDM Administrators Group.
pub static ref BUILTIN_GROUP_IDM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_admins",
description: "Builtin IDM Administrators Group.",
uuid: UUID_IDM_ADMINS,
members: vec![UUID_IDM_ADMIN],
..Default::default()
};
// There are our built in "roles". They encapsulate some higher level collections
// of roles. The intent is to allow a pretty generic and correct by default set
// of these use cases.
pub static ref BUILTIN_GROUP_SYSTEM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "system_admins",
description: "Builtin System Administrators Group.",
uuid: UUID_SYSTEM_ADMINS,
members: vec![BUILTIN_ACCOUNT_ADMIN.uuid],
entry_managed_by: Some(UUID_SYSTEM_ADMINS),
members: vec![UUID_ADMIN],
..Default::default()
};
pub static ref BUILTIN_GROUP_IDM_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_admins",
description: "Builtin IDM Administrators Group.",
uuid: UUID_IDM_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMIN],
..Default::default()
};
pub static ref BUILTIN_GROUP_SERVICE_DESK: BuiltinGroup = BuiltinGroup {
name: "idm_service_desk",
description: "Builtin Service Desk Group.",
uuid: UUID_IDM_SERVICE_DESK,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![],
..Default::default()
};
// These are the "finer" roles. They encapsulate different concepts in the system.
// The next section is the "system style" roles. These adjust the operation of
// kanidm and relate to it's internals and how it functions.
pub static ref BUILTIN_GROUP_RECYCLE_BIN_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_recycle_bin_admins",
description: "Builtin Recycle Bin Administrators Group.",
uuid: UUID_IDM_RECYCLE_BIN_ADMINS,
entry_managed_by: Some(UUID_SYSTEM_ADMINS),
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for granting local domain administration rights and trust administration rights
pub static ref BUILTIN_GROUP_DOMAIN_ADMINS: BuiltinGroup = BuiltinGroup {
name: "domain_admins",
description: "Builtin IDM Group for granting local domain administration rights and trust administration rights.",
uuid: UUID_DOMAIN_ADMINS,
entry_managed_by: Some(UUID_SYSTEM_ADMINS),
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
pub static ref BUILTIN_GROUP_SCHEMA_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_schema_admins",
description: "Builtin Schema Administration Group.",
uuid: UUID_IDM_SCHEMA_ADMINS,
entry_managed_by: Some(UUID_SYSTEM_ADMINS),
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
pub static ref BUILTIN_GROUP_ACCESS_CONTROL_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_access_control_admins",
description: "Builtin Access Control Administration Group.",
entry_managed_by: Some(UUID_SYSTEM_ADMINS),
uuid: UUID_IDM_ACCESS_CONTROL_ADMINS,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
// These are the IDM roles. They concern application integration, user permissions
// and credential security management.
/// Builtin IDM Group for managing persons and their account details
pub static ref BUILTIN_GROUP_PEOPLE_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_people_admins",
description: "Builtin People Administration Group.",
uuid: UUID_IDM_PEOPLE_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
pub static ref BUILTIN_GROUP_PEOPLE_ON_BOARDING: BuiltinGroup = BuiltinGroup {
name: "idm_people_on_boarding",
description: "Builtin People On Boarding Group.",
uuid: UUID_IDM_PEOPLE_ON_BOARDING,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![],
..Default::default()
};
// * People read managers
/// Builtin IDM Group for granting elevated people (personal data) read permissions.
pub static ref IDM_PEOPLE_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_read_priv",
pub static ref BUILTIN_GROUP_PEOPLE_PII_READ: BuiltinGroup = BuiltinGroup {
name: "idm_people_pii_read",
description: "Builtin IDM Group for granting elevated people (personal data) read permissions.",
uuid: UUID_IDM_PEOPLE_READ_PRIV,
members: vec![UUID_IDM_PEOPLE_WRITE_PRIV],
..Default::default()
};
pub static ref IDM_PEOPLE_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_write_priv",
description: "Builtin IDM Group for granting elevated people (personal data) write permissions.",
uuid: UUID_IDM_PEOPLE_WRITE_PRIV,
members: vec![UUID_IDM_PEOPLE_MANAGE_PRIV,UUID_IDM_PEOPLE_EXTEND_PRIV],
uuid: UUID_IDM_PEOPLE_PII_READ,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![],
..Default::default()
};
// * People write managers
/// Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions.
pub static ref IDM_PEOPLE_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_manage_priv",
description: "Builtin IDM Group for granting elevated people (personal data) write and lifecycle management permissions.",
uuid: UUID_IDM_PEOPLE_MANAGE_PRIV,
pub static ref BUILTIN_GROUP_SERVICE_ACCOUNT_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_service_account_admins",
description: "Builtin Service Account Administration Group.",
uuid: UUID_IDM_SERVICE_ACCOUNT_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for importing passwords to person accounts - intended for service account membership only.
pub static ref IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_account_password_import_priv",
description: "Builtin IDM Group for importing passwords to person accounts - intended for service account membership only.",
uuid: UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
/// Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.
pub static ref BUILTIN_GROUP_OAUTH2_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_oauth2_admins",
description: "Builtin Oauth2 Integration Administration Group.",
uuid: UUID_IDM_OAUTH2_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for allowing the ability to extend accounts to have the "person" flag set.
pub static ref IDM_PEOPLE_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_extend_priv",
description: "Builtin System Administrators Group.",
uuid: UUID_IDM_PEOPLE_EXTEND_PRIV,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
/// Self-write of mail
pub static ref IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_self_write_mail_priv",
description: "Builtin IDM Group for people accounts to update their own mail.",
uuid: UUID_IDM_PEOPLE_SELF_WRITE_MAIL_PRIV,
members: Vec::new(),
..Default::default()
};
/// Builtin IDM Group for granting elevated high privilege people (personal data) read permissions.
pub static ref IDM_HP_PEOPLE_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_read_priv",
description: "Builtin IDM Group for granting elevated high privilege people (personal data) read permissions.",
uuid: UUID_IDM_HP_PEOPLE_READ_PRIV,
members: vec![UUID_IDM_HP_PEOPLE_WRITE_PRIV],
..Default::default()
};
/// Builtin IDM Group for granting elevated high privilege people (personal data) write permissions.
pub static ref IDM_HP_PEOPLE_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_write_priv",
description: "Builtin IDM Group for granting elevated high privilege people (personal data) write permissions.",
uuid: UUID_IDM_HP_PEOPLE_WRITE_PRIV,
members: vec![UUID_IDM_HP_PEOPLE_EXTEND_PRIV],
..Default::default()
};
/// Builtin IDM Group for extending high privilege accounts to be people.
pub static ref IDM_HP_PEOPLE_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_people_extend_priv",
description: "Builtin IDM Group for extending high privilege accounts to be people.",
uuid: UUID_IDM_HP_PEOPLE_EXTEND_PRIV,
members: vec![UUID_SYSTEM_ADMINS],
..Default::default()
};
// * group write manager (no read, everyone has read via the anon, etc)
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_manage_priv",
description: "Builtin IDM Group for granting elevated group write and lifecycle permissions.",
uuid: UUID_IDM_GROUP_MANAGE_PRIV,
members: vec![
BUILTIN_GROUP_IDM_ADMINS_V1.uuid,
BUILTIN_GROUP_SYSTEM_ADMINS_V1.uuid,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_write_priv",
description: "Builtin IDM Group for granting elevated group write permissions.",
uuid: UUID_IDM_GROUP_WRITE_PRIV,
members: vec![
UUID_IDM_GROUP_MANAGE_PRIV
],
..Default::default()
};
/// Builtin IDM Group for granting unix group extension permissions.
pub static ref IDM_GROUP_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_unix_extend_priv",
description: "Builtin IDM Group for granting UNIX group extension permissions.",
uuid: UUID_IDM_GROUP_UNIX_EXTEND_PRIV,
members: vec![
UUID_IDM_ADMINS
],
..Default::default()
};
/// Account read manager
pub static ref IDM_ACCOUNT_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_read_priv",
description: "Builtin IDM Group for granting elevated account read permissions.",
uuid: UUID_IDM_ACCOUNT_READ_PRIV,
members: vec![
UUID_IDM_ACCOUNT_WRITE_PRIV,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_manage_priv",
description: "Builtin IDM Group for granting elevated account write and lifecycle permissions.",
uuid: UUID_IDM_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_write_priv",
description: "Builtin IDM Group for granting elevated account write permissions.",
uuid: UUID_IDM_ACCOUNT_WRITE_PRIV,
members: vec![
UUID_IDM_ACCOUNT_MANAGE_PRIV,
],
..Default::default()
};
pub static ref IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_account_unix_extend_priv",
description: "Builtin IDM Group for granting account unix extend permissions.",
uuid: UUID_IDM_ACCOUNT_UNIX_EXTEND_PRIV,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS secret write for all non-hp accounts.
pub static ref IDM_RADIUS_SECRET_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_secret_write_priv",
description: "Builtin IDM Group for RADIUS secret write for all non-hp accounts.",
uuid: UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
members: vec![
UUID_IDM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for RADIUS secret reading for all non-hp accounts.
pub static ref IDM_RADIUS_SECRET_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_radius_secret_read_priv",
description: "Builtin IDM Group for RADIUS secret reading for all non-hp accounts.",
uuid: UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
members: vec![
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
],
pub static ref BUILTIN_GROUP_RADIUS_SERVICE_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_radius_service_admins",
description: "Builtin Radius Administration Group.",
uuid: UUID_IDM_RADIUS_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
@ -268,158 +206,53 @@ lazy_static! {
name: "idm_radius_servers",
description: "Builtin IDM Group for RADIUS server access delegation.",
uuid: UUID_IDM_RADIUS_SERVERS,
entry_managed_by: Some(UUID_IDM_RADIUS_ADMINS),
members: vec![
],
..Default::default()
};
/// High privilege account read manager
pub static ref IDM_HP_ACCOUNT_READ_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_read_priv",
description: "Builtin IDM Group for granting elevated account read permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_READ_PRIV,
members: vec![
UUID_IDM_HP_ACCOUNT_WRITE_PRIV
],
pub static ref BUILTIN_GROUP_ACCOUNT_POLICY_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_account_policy_admins",
description: "Builtin Account Policy Administration Group.",
uuid: UUID_IDM_ACCOUNT_POLICY_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for granting elevated account write permissions over high privilege accounts.
pub static ref IDM_HP_ACCOUNT_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_manage_priv",
description: "Builtin IDM Group for granting elevated account write and lifecycle permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated account write permissions over high privilege accounts.
pub static ref IDM_HP_ACCOUNT_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_write_priv",
description: "Builtin IDM Group for granting elevated account write permissions over high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
members: vec![
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
],
/// Builtin IDM Group for managing posix/unix attributes on groups and users.
pub static ref BUILTIN_GROUP_UNIX_ADMINS: BuiltinGroup = BuiltinGroup {
name: "idm_unix_admins",
description: "Builtin Unix Administration Group.",
uuid: UUID_IDM_UNIX_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// Builtin IDM Group for granting account unix extend permissions for high privilege accounts.
pub static ref IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_account_unix_extend_priv",
description: "Builtin IDM Group for granting account UNIX extend permissions for high privilege accounts.",
uuid: UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
/// Builtin IDM Group for granting elevated group write and lifecycle permissions.
pub static ref IDM_GROUP_ADMINS_V1: BuiltinGroup = BuiltinGroup {
name: "idm_group_admins",
description: "Builtin IDM Group for granting elevated group write and lifecycle permissions.",
uuid: UUID_IDM_GROUP_ADMINS,
entry_managed_by: Some(UUID_IDM_ADMINS),
members: vec![UUID_IDM_ADMINS],
..Default::default()
};
/// * Schema write manager
pub static ref IDM_SCHEMA_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_schema_manage_priv",
description: "Builtin IDM Group for granting elevated schema write and management permissions.",
uuid: UUID_IDM_SCHEMA_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
/// Self-write of mail
pub static ref IDM_PEOPLE_SELF_WRITE_MAIL_V1: BuiltinGroup = BuiltinGroup {
name: "idm_people_self_write_mail",
description: "Builtin IDM Group for people accounts to update their own mail.",
uuid: UUID_IDM_PEOPLE_SELF_WRITE_MAIL,
members: Vec::new(),
..Default::default()
};
/// ACP read/write manager
pub static ref IDM_ACP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_acp_manage_priv",
description: "Builtin IDM Group for granting control over all access control profile modifications.",
uuid: UUID_IDM_ACP_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups.
pub static ref IDM_HP_GROUP_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_manage_priv",
description: "Builtin IDM Group for granting elevated group write and lifecycle privileges for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting elevated group write privileges for high privilege groups.
pub static ref IDM_HP_GROUP_WRITE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_write_priv",
description: "Builtin IDM Group for granting elevated group write privileges for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_WRITE_PRIV,
members: vec![
UUID_IDM_HP_GROUP_MANAGE_PRIV,
],
..Default::default()
};
}
// at some point vs code just gives up on syntax highlighting inside lazy_static...
lazy_static! {
/// Builtin IDM Group for granting unix group extension permissions for high privilege groups.
pub static ref IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_group_unix_extend_priv",
description: "Builtin IDM Group for granting unix group extension permissions for high privilege groups.",
uuid: UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for granting local domain administration rights and trust administration rights
pub static ref DOMAIN_ADMINS: BuiltinGroup = BuiltinGroup {
name: "domain_admins",
description: "Builtin IDM Group for granting local domain administration rights and trust administration rights.",
uuid: UUID_DOMAIN_ADMINS,
members: vec![
UUID_ADMIN,
],
..Default::default()
};
/// Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.
pub static ref IDM_HP_OAUTH2_MANAGE_PRIV_V1: BuiltinGroup = BuiltinGroup {
name: "idm_hp_oauth2_manage_priv",
description: "Builtin IDM Group for managing oauth2 resource server integrations to this authentication domain.",
uuid: UUID_IDM_HP_OAUTH2_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
/// Builtin IDM Group for allowing migrations of service accounts into persons
pub static ref IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_hp_service_account_into_person_migrate_priv",
description:"Builtin IDM Group for allowing migrations of service accounts into persons",
uuid: UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
pub static ref IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_hp_sync_account_manage_priv",
description: "Builtin IDM Group for managing synchronisation from external identity sources",
uuid: UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
members: vec![
UUID_SYSTEM_ADMINS,
],
..Default::default()
};
pub static ref IDM_ALL_PERSONS: BuiltinGroup = BuiltinGroup {
name: "idm_all_persons",
description: "Builtin IDM dynamic group containing all persons.",
@ -438,6 +271,7 @@ lazy_static! {
// Enforce this is a system protected object
(Attribute::Class, EntryClass::System.to_value()),
],
..Default::default()
};
pub static ref IDM_ALL_ACCOUNTS: BuiltinGroup = BuiltinGroup {
@ -455,6 +289,7 @@ lazy_static! {
// Enforce this is a system protected object
(Attribute::Class, EntryClass::System.to_value()),
],
..Default::default()
};
@ -462,6 +297,7 @@ lazy_static! {
name: "idm_ui_enable_experimental_features",
description: "Members of this group will have access to experimental web UI features.",
uuid: UUID_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES,
entry_managed_by: Some(UUID_IDM_ADMINS),
extra_attributes: vec![
(Attribute::GrantUiHint, Value::UiHint(UiHint::ExperimentalFeatures))
],
@ -469,10 +305,11 @@ lazy_static! {
};
/// Members of this group will have access to read the mail attribute of all persons and service accounts.
pub static ref IDM_ACCOUNT_MAIL_READ_PRIV: BuiltinGroup = BuiltinGroup {
name: "idm_account_mail_read_priv",
pub static ref IDM_ACCOUNT_MAIL_READ: BuiltinGroup = BuiltinGroup {
name: "idm_account_mail_read",
description: "Members of this group will have access to read the mail attribute of all persons and service accounts.",
uuid: UUID_IDM_ACCOUNT_MAIL_READ_PRIV,
entry_managed_by: Some(UUID_IDM_ACCESS_CONTROL_ADMINS),
uuid: UUID_IDM_ACCOUNT_MAIL_READ,
..Default::default()
};
@ -480,41 +317,29 @@ lazy_static! {
pub static ref IDM_HIGH_PRIVILEGE_V1: BuiltinGroup = BuiltinGroup {
name: "idm_high_privilege",
uuid: UUID_IDM_HIGH_PRIVILEGE,
entry_managed_by: Some(UUID_IDM_ACCESS_CONTROL_ADMINS),
description: "Builtin IDM provided groups with high levels of access that should be audited and limited in modification.",
members: vec![
UUID_IDM_ADMINS,
UUID_IDM_PEOPLE_READ_PRIV,
UUID_IDM_PEOPLE_WRITE_PRIV,
UUID_IDM_GROUP_WRITE_PRIV,
UUID_IDM_ACCOUNT_READ_PRIV,
UUID_IDM_ACCOUNT_WRITE_PRIV,
UUID_IDM_RADIUS_SERVERS,
UUID_IDM_HP_ACCOUNT_READ_PRIV,
UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
UUID_IDM_SCHEMA_MANAGE_PRIV,
UUID_IDM_ACP_MANAGE_PRIV,
UUID_IDM_HP_GROUP_WRITE_PRIV,
UUID_IDM_PEOPLE_MANAGE_PRIV,
UUID_IDM_ACCOUNT_MANAGE_PRIV,
UUID_IDM_GROUP_MANAGE_PRIV,
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
UUID_IDM_HP_GROUP_MANAGE_PRIV,
UUID_SYSTEM_ADMINS,
UUID_IDM_ADMINS,
UUID_DOMAIN_ADMINS,
UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
UUID_IDM_PEOPLE_EXTEND_PRIV,
UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
UUID_IDM_HP_OAUTH2_MANAGE_PRIV,
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
UUID_IDM_SERVICE_DESK,
UUID_IDM_RECYCLE_BIN_ADMINS,
UUID_IDM_SCHEMA_ADMINS,
UUID_IDM_ACCESS_CONTROL_ADMINS,
UUID_IDM_OAUTH2_ADMINS,
UUID_IDM_RADIUS_ADMINS,
UUID_IDM_ACCOUNT_POLICY_ADMINS,
UUID_IDM_RADIUS_SERVERS,
UUID_IDM_GROUP_ADMINS,
UUID_IDM_UNIX_ADMINS,
UUID_IDM_PEOPLE_PII_READ,
UUID_IDM_PEOPLE_ADMINS,
UUID_IDM_PEOPLE_ON_BOARDING,
UUID_IDM_SERVICE_ACCOUNT_ADMINS,
UUID_IDM_HIGH_PRIVILEGE,
],
dyngroup: false,
dyngroup_filter: None,
extra_attributes: Vec::new(),
..Default::default()
};
}
@ -522,46 +347,30 @@ lazy_static! {
pub fn idm_builtin_non_admin_groups() -> Vec<&'static BuiltinGroup> {
// Create any system default schema entries.
vec![
&BUILTIN_GROUP_DOMAIN_ADMINS,
&BUILTIN_GROUP_SCHEMA_ADMINS,
&BUILTIN_GROUP_ACCESS_CONTROL_ADMINS,
&BUILTIN_GROUP_UNIX_ADMINS,
&BUILTIN_GROUP_RECYCLE_BIN_ADMINS,
&BUILTIN_GROUP_SERVICE_DESK,
&BUILTIN_GROUP_OAUTH2_ADMINS,
&BUILTIN_GROUP_RADIUS_SERVICE_ADMINS,
&BUILTIN_GROUP_ACCOUNT_POLICY_ADMINS,
&BUILTIN_GROUP_PEOPLE_ADMINS,
&BUILTIN_GROUP_PEOPLE_PII_READ,
&BUILTIN_GROUP_PEOPLE_ON_BOARDING,
&BUILTIN_GROUP_SERVICE_ACCOUNT_ADMINS,
&IDM_GROUP_ADMINS_V1,
&IDM_ALL_PERSONS,
&IDM_ALL_ACCOUNTS,
&IDM_PEOPLE_MANAGE_PRIV_V1,
&IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
&IDM_PEOPLE_EXTEND_PRIV_V1,
&IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1,
&IDM_PEOPLE_WRITE_PRIV_V1,
&IDM_PEOPLE_READ_PRIV_V1,
&IDM_HP_PEOPLE_EXTEND_PRIV_V1,
&IDM_HP_PEOPLE_WRITE_PRIV_V1,
&IDM_HP_PEOPLE_READ_PRIV_V1,
&IDM_GROUP_MANAGE_PRIV_V1,
&IDM_GROUP_WRITE_PRIV_V1,
&IDM_GROUP_UNIX_EXTEND_PRIV_V1,
&IDM_ACCOUNT_MANAGE_PRIV_V1,
&IDM_ACCOUNT_WRITE_PRIV_V1,
&IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1,
&IDM_ACCOUNT_READ_PRIV_V1,
&IDM_RADIUS_SECRET_WRITE_PRIV_V1,
&IDM_RADIUS_SECRET_READ_PRIV_V1,
&IDM_RADIUS_SERVERS_V1,
&IDM_PEOPLE_SELF_WRITE_MAIL_V1,
// Write deps on read, so write must be added first.
&IDM_HP_ACCOUNT_MANAGE_PRIV_V1,
&IDM_HP_ACCOUNT_WRITE_PRIV_V1,
&IDM_HP_ACCOUNT_READ_PRIV_V1,
&IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1,
&IDM_SCHEMA_MANAGE_PRIV_V1,
&IDM_HP_GROUP_MANAGE_PRIV_V1,
&IDM_HP_GROUP_WRITE_PRIV_V1,
&IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1,
&IDM_ACP_MANAGE_PRIV_V1,
&DOMAIN_ADMINS,
&IDM_HP_OAUTH2_MANAGE_PRIV_V1,
&IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
&IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
// All members must exist before we write HP
&IDM_HIGH_PRIVILEGE_V1,
// other things
&IDM_UI_ENABLE_EXPERIMENTAL_FEATURES,
&IDM_ACCOUNT_MAIL_READ_PRIV,
&IDM_ACCOUNT_MAIL_READ,
]
}

View file

@ -44,12 +44,13 @@ pub const SYSTEM_INDEX_VERSION: i64 = 30;
pub type DomainVersion = u32;
pub const DOMAIN_LEVEL_1: DomainVersion = 1;
pub const DOMAIN_LEVEL_2: DomainVersion = 2;
// The minimum supported domain functional level
pub const DOMAIN_MIN_LEVEL: DomainVersion = DOMAIN_LEVEL_1;
pub const DOMAIN_MIN_LEVEL: DomainVersion = DOMAIN_LEVEL_2;
// The target supported domain functional level
pub const DOMAIN_TGT_LEVEL: DomainVersion = DOMAIN_LEVEL_1;
pub const DOMAIN_TGT_LEVEL: DomainVersion = DOMAIN_LEVEL_2;
// The maximum supported domain functional level
pub const DOMAIN_MAX_LEVEL: DomainVersion = DOMAIN_LEVEL_1;
pub const DOMAIN_MAX_LEVEL: DomainVersion = DOMAIN_LEVEL_2;
// On test builds, define to 60 seconds
#[cfg(test)]

View file

@ -6,7 +6,7 @@ use uuid::{uuid, Uuid};
pub const STR_UUID_ADMIN: &str = "00000000-0000-0000-0000-000000000000";
pub const UUID_ADMIN: Uuid = uuid!("00000000-0000-0000-0000-000000000000");
pub const UUID_IDM_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000001");
pub const UUID_IDM_PEOPLE_READ_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000002");
pub const UUID_IDM_PEOPLE_PII_READ: Uuid = uuid!("00000000-0000-0000-0000-000000000002");
pub const UUID_IDM_PEOPLE_WRITE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000003");
pub const UUID_IDM_GROUP_WRITE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000004");
pub const UUID_IDM_ACCOUNT_READ_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000005");
@ -14,17 +14,17 @@ pub const UUID_IDM_ACCOUNT_WRITE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000
pub const UUID_IDM_RADIUS_SERVERS: Uuid = uuid!("00000000-0000-0000-0000-000000000007");
pub const UUID_IDM_HP_ACCOUNT_READ_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000008");
pub const UUID_IDM_HP_ACCOUNT_WRITE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000009");
pub const UUID_IDM_SCHEMA_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000010");
pub const UUID_IDM_ACP_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000011");
pub const UUID_IDM_SCHEMA_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000010");
pub const UUID_IDM_ACCESS_CONTROL_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000011");
pub const UUID_IDM_HP_GROUP_WRITE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000012");
pub const UUID_IDM_PEOPLE_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000013");
pub const UUID_IDM_PEOPLE_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000013");
pub const UUID_IDM_ACCOUNT_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000014");
pub const UUID_IDM_GROUP_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000015");
pub const UUID_IDM_GROUP_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000015");
pub const UUID_IDM_HP_ACCOUNT_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000016");
pub const UUID_IDM_HP_GROUP_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000017");
pub const UUID_IDM_ADMIN: Uuid = uuid!("00000000-0000-0000-0000-000000000018");
pub const STR_UUID_SYSTEM_ADMINS: &str = "00000000-0000-0000-0000-000000000000";
pub const STR_UUID_SYSTEM_ADMINS: &str = "00000000-0000-0000-0000-000000000019";
pub const UUID_SYSTEM_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000019");
pub const UUID_DOMAIN_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000020");
pub const UUID_IDM_ACCOUNT_UNIX_EXTEND_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000021");
@ -35,7 +35,7 @@ pub const UUID_IDM_PEOPLE_EXTEND_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000
pub const UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV: Uuid =
uuid!("00000000-0000-0000-0000-000000000025");
pub const UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000026");
pub const UUID_IDM_HP_OAUTH2_MANAGE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000027");
pub const UUID_IDM_OAUTH2_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000027");
pub const UUID_IDM_HP_PEOPLE_READ_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000028");
pub const UUID_IDM_HP_PEOPLE_WRITE_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000029");
pub const UUID_IDM_HP_PEOPLE_EXTEND_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000030");
@ -43,22 +43,29 @@ pub const UUID_IDM_HP_PEOPLE_EXTEND_PRIV: Uuid = uuid!("00000000-0000-0000-0000-
pub const UUID_IDM_RADIUS_SECRET_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-000000000032");
pub const UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-000000000031");
pub const UUID_IDM_PEOPLE_SELF_WRITE_MAIL_PRIV: Uuid =
uuid!("00000000-0000-0000-0000-000000000033");
pub const UUID_IDM_PEOPLE_SELF_WRITE_MAIL: Uuid = uuid!("00000000-0000-0000-0000-000000000033");
pub const UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV: Uuid =
uuid!("00000000-0000-0000-0000-000000000034");
pub const UUID_IDM_ALL_PERSONS: Uuid = uuid!("00000000-0000-0000-0000-000000000035");
pub const STR_UUID_IDM_ALL_ACCOUNTS: &str = "00000000-0000-0000-0000-000000000036";
pub const UUID_IDM_ALL_ACCOUNTS: Uuid = uuid!("00000000-0000-0000-0000-000000000036");
pub const UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV: Uuid =
uuid!("00000000-0000-0000-0000-000000000037");
pub const UUID_IDM_UI_ENABLE_EXPERIMENTAL_FEATURES: Uuid =
uuid!("00000000-0000-0000-0000-000000000038");
pub const UUID_IDM_ACCOUNT_MAIL_READ_PRIV: Uuid = uuid!("00000000-0000-0000-0000-000000000039");
pub const UUID_IDM_ACCOUNT_MAIL_READ: Uuid = uuid!("00000000-0000-0000-0000-000000000039");
pub const UUID_IDM_GROUP_ACCOUNT_POLICY_MANAGE_PRIV: Uuid =
uuid!("00000000-0000-0000-0000-000000000040");
pub const UUID_IDM_SERVICE_DESK: Uuid = uuid!("00000000-0000-0000-0000-000000000041");
pub const UUID_IDM_RECYCLE_BIN_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000042");
pub const UUID_IDM_RADIUS_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000043");
pub const UUID_IDM_UNIX_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000044");
pub const UUID_IDM_PEOPLE_ON_BOARDING: Uuid = uuid!("00000000-0000-0000-0000-000000000045");
pub const UUID_IDM_SERVICE_ACCOUNT_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000046");
pub const UUID_IDM_ACCOUNT_POLICY_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000047");
//
pub const UUID_IDM_HIGH_PRIVILEGE: Uuid = uuid!("00000000-0000-0000-0000-000000001000");
@ -272,42 +279,42 @@ pub const UUID_DOMAIN_INFO: Uuid = uuid!("00000000-0000-0000-0000-ffffff000025")
// Access controls
// skip 00 / 01 - see system info
pub const UUID_IDM_ADMINS_ACP_RECYCLE_SEARCH_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000002");
pub const UUID_IDM_ADMINS_ACP_REVIVE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000003");
pub const UUID_IDM_SELF_ACP_READ_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000004");
pub const UUID_IDM_ALL_ACP_READ_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000006");
pub const UUID_IDM_ACP_PEOPLE_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000007");
pub const UUID_IDM_ACP_RECYCLE_BIN_SEARCH_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000002");
pub const UUID_IDM_ACP_RECYCLE_BIN_REVIVE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000003");
pub const UUID_IDM_ACP_SELF_READ_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000004");
pub const UUID_IDM_ACP_ALL_ACCOUNTS_POSIX_READ_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000006");
pub const UUID_IDM_ACP_PEOPLE_PII_READ_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000007");
pub const UUID_IDM_ACP_PEOPLE_WRITE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000008");
pub const UUID_IDM_ACP_GROUP_WRITE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000009");
pub const UUID_IDM_ACP_ACCOUNT_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000010");
pub const UUID_IDM_ACP_ACCOUNT_WRITE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000011");
pub const UUID_IDM_ACP_ACCOUNT_MANAGE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000012");
pub const UUID_IDM_ACP_PEOPLE_MANAGE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000013");
pub const UUID_IDM_ACP_PEOPLE_PII_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000013");
pub const UUID_IDM_ACP_RADIUS_SERVERS_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000014");
pub const UUID_IDM_ACP_HP_ACCOUNT_READ_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000015");
pub const UUID_IDM_ACP_HP_ACCOUNT_WRITE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000016");
pub const UUID_IDM_ACP_HP_GROUP_WRITE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000017");
pub const UUID_IDM_ACP_SCHEMA_WRITE_ATTRS_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000018");
pub const UUID_IDM_ACP_ACP_MANAGE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000019");
pub const UUID_IDM_ACP_SCHEMA_WRITE_CLASSES_PRIV_V1: Uuid =
pub const UUID_IDM_ACP_SCHEMA_WRITE_ATTRS_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000018");
pub const UUID_IDM_ACP_ACP_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000019");
pub const UUID_IDM_ACP_SCHEMA_WRITE_CLASSES_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000020");
pub const UUID_IDM_SELF_ACP_WRITE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000021");
pub const UUID_IDM_ACP_GROUP_MANAGE_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000022");
pub const UUID_IDM_ACP_SELF_WRITE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000021");
pub const UUID_IDM_ACP_GROUP_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000022");
pub const UUID_IDM_ACP_HP_ACCOUNT_MANAGE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000023");
pub const UUID_IDM_ACP_HP_GROUP_MANAGE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000024");
// Skip 25 - see domain info.
pub const UUID_IDM_ACP_DOMAIN_ADMIN_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000026");
pub const UUID_IDM_ACP_DOMAIN_ADMIN_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000026");
pub const STR_UUID_SYSTEM_CONFIG: &str = "00000000-0000-0000-0000-ffffff000027";
pub const UUID_SYSTEM_CONFIG: Uuid = uuid!("00000000-0000-0000-0000-ffffff000027");
pub const UUID_IDM_ACP_SYSTEM_CONFIG_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000028");
pub const UUID_IDM_ACP_SYSTEM_CONFIG_ACCOUNT_POLICY_MANAGE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000028");
pub const UUID_IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000029");
pub const UUID_IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1: Uuid =
@ -319,8 +326,7 @@ pub const UUID_IDM_HP_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000033");
pub const UUID_IDM_HP_ACP_GROUP_UNIX_EXTEND_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000034");
pub const UUID_IDM_HP_ACP_OAUTH2_MANAGE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000035");
pub const UUID_IDM_ACP_OAUTH2_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000035");
pub const UUID_IDM_ACP_HP_PEOPLE_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000036");
pub const UUID_IDM_ACP_HP_PEOPLE_WRITE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000037");
@ -330,18 +336,50 @@ pub const UUID_IDM_ACP_RADIUS_SECRET_READ_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000039");
pub const UUID_IDM_ACP_RADIUS_SECRET_WRITE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000040");
pub const UUID_IDM_PEOPLE_SELF_ACP_WRITE_MAIL_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000041");
pub const UUID_IDM_ACP_PEOPLE_SELF_WRITE_MAIL: Uuid = uuid!("00000000-0000-0000-0000-ffffff000041");
pub const UUID_IDM_HP_ACP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000042");
pub const UUID_IDM_ACP_OAUTH2_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000043");
pub const UUID_IDM_HP_ACP_SYNC_ACCOUNT_MANAGE_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000044");
pub const UUID_IDM_ACP_ACCOUNT_MAIL_READ_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000045");
pub const UUID_IDM_ACCOUNT_SELF_ACP_WRITE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000046");
pub const UUID_IDM_ACP_ACCOUNT_MAIL_READ_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000045");
pub const UUID_IDM_ACP_ACCOUNT_SELF_WRITE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000046");
pub const UUID_IDM_ACP_SYSTEM_CONFIG_SESSION_EXP_PRIV_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000047");
pub const UUID_IDM_ACP_GROUP_ENTRY_MANAGED_BY_MODIFY: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000048");
pub const UUID_IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000049");
pub const UUID_IDM_ACP_GROUP_ENTRY_MANAGER_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000050");
pub const UUID_IDM_ACP_SELF_NAME_WRITE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000051");
pub const UUID_IDM_ACP_GROUP_READ: Uuid = uuid!("00000000-0000-0000-0000-ffffff000052");
pub const UUID_IDM_ACP_PEOPLE_READ_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000053");
pub const UUID_IDM_ACP_PEOPLE_CREATE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000054");
pub const UUID_IDM_ACP_PEOPLE_DELETE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000055");
pub const UUID_IDM_ACP_PEOPLE_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000056");
pub const UUID_IDM_ACP_PEOPLE_CREDENTIAL_RESET_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000057");
pub const UUID_IDM_ACP_HP_PEOPLE_CREDENTIAL_RESET_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000058");
pub const UUID_IDM_ACP_SERVICE_ACCOUNT_CREATE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000059");
pub const UUID_IDM_ACP_SERVICE_ACCOUNT_DELETE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000060");
pub const UUID_IDM_ACP_SERVICE_ACCOUNT_ENTRY_MANAGER_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000061");
pub const UUID_IDM_ACP_SERVICE_ACCOUNT_ENTRY_MANAGED_BY_MODIFY: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000062");
pub const UUID_IDM_ACP_HP_SERVICE_ACCOUNT_ENTRY_MANAGED_BY_MODIFY: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000063");
pub const UUID_IDM_ACP_SERVICE_ACCOUNT_MANAGE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000064");
pub const UUID_IDM_ACP_SYNC_ACCOUNT_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000065");
pub const UUID_IDM_ACP_RADIUS_SECRET_MANAGE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000066");
pub const UUID_IDM_ACP_HP_GROUP_UNIX_MANAGE_V1: Uuid =
uuid!("00000000-0000-0000-0000-ffffff000067");
pub const UUID_IDM_ACP_GROUP_UNIX_MANAGE_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000068");
pub const UUID_IDM_ACP_ACCOUNT_UNIX_EXTEND_V1: Uuid = uuid!("00000000-0000-0000-0000-ffffff000069");
// End of system ranges
pub const UUID_DOES_NOT_EXIST: Uuid = uuid!("00000000-0000-0000-0000-fffffffffffe");

View file

@ -2149,8 +2149,8 @@ impl<STATE> Entry<EntryValid, STATE> {
if !missing_must.is_empty() {
admin_warn!(
"Validation error, the following required (must) attributes are missing - {:?}",
missing_must
"Validation error, the following required ({}) (must) attributes are missing - {:?}",
self.get_display_id(), missing_must
);
// We if are in the recycle bin, we don't hard error here. This can occur when
// a migration occurs and we delete an acp, and then the related group. Because
@ -2235,8 +2235,11 @@ impl<STATE> Entry<EntryValid, STATE> {
}
None => {
admin_error!(
"{} - not found in the list of valid attributes for this set of classes - valid attributes are {:?}",
"{} {} - not found in the list of valid attributes for this set of classes {:?} - valid attributes are {:?}",
attr_name.to_string(),
self.get_display_id(),
entry_classes.iter().collect::<Vec<_>>(),
may.keys().collect::<Vec<_>>()
);
Err(SchemaError::AttributeNotValidForClass(
@ -2935,9 +2938,9 @@ impl<VALID, STATE> Entry<VALID, STATE> {
// valid, we still have strict typing checks between the filter -> entry to guarantee
// they should be functional. We'll never match something that isn't syntactially valid.
#[inline(always)]
#[instrument(level = "trace", name = "entry::entry_match_no_index", skip(self))]
/// Test if the following filter applies to and matches this entry.
pub fn entry_match_no_index(&self, filter: &Filter<FilterValidResolved>) -> bool {
let _entered = trace_span!("entry::entry_match_no_index").entered();
self.entry_match_no_index_inner(filter.to_inner())
}

View file

@ -1074,7 +1074,7 @@ mod tests {
let me = ModifyEvent::new_internal_invalid(
filter!(f_eq(
Attribute::Name,
PartialValue::new_iname(IDM_PEOPLE_READ_PRIV_V1.name)
PartialValue::new_iname(BUILTIN_GROUP_PEOPLE_PII_READ.name)
)),
ModifyList::new_list(vec![Modify::Present(
Attribute::Member.into(),

View file

@ -171,13 +171,13 @@ fn enforce_unique<VALID, STATE>(
while let Some(cand_query) = queue.pop_front() {
let filt_in = filter!(f_or(cand_query.to_vec()));
let conflict_cand = qs.internal_exists(filt_in).map_err(|e| {
let conflict_cand = qs.internal_search(filt_in).map_err(|e| {
admin_error!("internal exists error {:?}", e);
e
})?;
// A conflict was found!
if conflict_cand {
if let Some(conflict_cand_zero) = conflict_cand.get(0) {
if cand_query.len() >= 2 {
// Continue to split to isolate.
let mid = cand_query.len() / 2;
@ -187,7 +187,7 @@ fn enforce_unique<VALID, STATE>(
// Continue!
} else {
// Report this as a failing query.
error!(cand_filters = ?cand_query, "The following filter conditions failed to assert uniqueness");
error!(cand_filters = ?cand_query, conflicting_with = %conflict_cand_zero.get_display_id(), "The following filter conditions failed to assert uniqueness");
}
}
}

View file

@ -109,11 +109,14 @@ pub(super) fn apply_modify_access<'a>(
match &acm.target_condition {
AccessControlTargetCondition::Scope(f_res) => {
if !entry.entry_match_no_index(f_res) {
debug!(entry = ?entry.get_display_id(), acm = %acm.acp.acp.name, "entry DOES NOT match acs");
return None;
}
}
};
debug!(entry = ?entry.get_display_id(), acs = %acm.acp.acp.name, "acs applied to entry");
Some(acm.acp)
})
.collect();

View file

@ -115,6 +115,35 @@ impl QueryServer {
if system_info_version < 16 {
write_txn.migrate_15_to_16()?;
}
if system_info_version < 17 {
write_txn.migrate_16_to_17()?;
}
}
// This is the start of domain info related migrations which we will need in future
// to handle replication. Due to the access control rework, and the addition of "managed by"
// syntax, we need to ensure both node "fence" replication from each other. We do this
// by changing domain infos to be incompatible during this phase.
let domain_info_version = match write_txn.internal_search_uuid(UUID_DOMAIN_INFO) {
Ok(e) => Ok(e.get_ava_single_uint32(Attribute::Version).unwrap_or(0)),
Err(OperationError::NoMatchingEntries) => Ok(0),
Err(r) => Err(r),
}?;
admin_debug!(?domain_info_version);
if domain_info_version < DOMAIN_TGT_LEVEL {
write_txn
.internal_modify_uuid(
UUID_DOMAIN_INFO,
&ModifyList::new_purge_and_set(
Attribute::Version,
Value::new_uint32(DOMAIN_TGT_LEVEL),
),
)
.map(|()| {
warn!("Domain level has been raised to {}", DOMAIN_TGT_LEVEL);
})?;
}
// Reload if anything in migrations requires it.
@ -514,6 +543,106 @@ impl<'a> QueryServerWriteTransaction<'a> {
// Complete
}
#[instrument(level = "info", skip_all)]
/// This migration will:
/// * ensure that all access controls have the needed group receiver type
/// * delete legacy entries that are no longer needed.
pub fn migrate_16_to_17(&mut self) -> Result<(), OperationError> {
admin_warn!("starting 16 to 17 migration.");
let filter = filter!(f_and!([
f_or!([
f_pres(Attribute::AcpReceiverGroup),
f_pres(Attribute::AcpTargetScope),
]),
f_eq(
Attribute::Class,
EntryClass::AccessControlProfile.to_partialvalue()
)
]));
// Delete the incorrectly added "member" attr.
let modlist = ModifyList::new_list(vec![
Modify::Present(
Attribute::Class.into(),
EntryClass::AccessControlReceiverGroup.to_value(),
),
Modify::Present(
Attribute::Class.into(),
EntryClass::AccessControlTargetScope.to_value(),
),
]);
self.internal_modify(&filter, &modlist)?;
let delete_entries = [
UUID_IDM_ACP_OAUTH2_READ_PRIV_V1,
UUID_IDM_ACP_RADIUS_SECRET_READ_PRIV_V1,
UUID_IDM_ACP_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
UUID_IDM_ACP_SYSTEM_CONFIG_SESSION_EXP_PRIV_V1,
UUID_IDM_ACP_HP_GROUP_WRITE_PRIV_V1,
UUID_IDM_ACP_HP_GROUP_MANAGE_PRIV_V1,
UUID_IDM_ACP_HP_PEOPLE_WRITE_PRIV_V1,
UUID_IDM_ACP_ACCOUNT_READ_PRIV_V1,
UUID_IDM_ACP_ACCOUNT_WRITE_PRIV_V1,
UUID_IDM_ACP_ACCOUNT_MANAGE_PRIV_V1,
UUID_IDM_ACP_HP_ACCOUNT_READ_PRIV_V1,
UUID_IDM_ACP_HP_ACCOUNT_WRITE_PRIV_V1,
UUID_IDM_ACP_GROUP_WRITE_PRIV_V1,
UUID_IDM_ACP_HP_PEOPLE_EXTEND_PRIV_V1,
UUID_IDM_ACP_PEOPLE_EXTEND_PRIV_V1,
UUID_IDM_ACP_HP_ACCOUNT_MANAGE_PRIV_V1,
UUID_IDM_HP_ACP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_V1,
UUID_IDM_HP_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1,
UUID_IDM_HP_ACP_SYNC_ACCOUNT_MANAGE_PRIV_V1,
UUID_IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1,
UUID_IDM_ACP_RADIUS_SECRET_WRITE_PRIV_V1,
UUID_IDM_HP_ACP_GROUP_UNIX_EXTEND_PRIV_V1,
UUID_IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1,
UUID_IDM_ACP_HP_PEOPLE_READ_PRIV_V1,
UUID_IDM_ACP_PEOPLE_WRITE_PRIV_V1,
UUID_IDM_HP_SYNC_ACCOUNT_MANAGE_PRIV,
UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1,
UUID_IDM_RADIUS_SECRET_READ_PRIV_V1,
UUID_IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV,
UUID_IDM_PEOPLE_EXTEND_PRIV,
UUID_IDM_HP_PEOPLE_EXTEND_PRIV,
UUID_IDM_HP_GROUP_MANAGE_PRIV,
UUID_IDM_HP_GROUP_WRITE_PRIV,
UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV,
UUID_IDM_GROUP_ACCOUNT_POLICY_MANAGE_PRIV,
UUID_IDM_HP_GROUP_UNIX_EXTEND_PRIV,
UUID_IDM_GROUP_WRITE_PRIV,
UUID_IDM_GROUP_UNIX_EXTEND_PRIV,
UUID_IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV,
UUID_IDM_ACCOUNT_UNIX_EXTEND_PRIV,
UUID_IDM_PEOPLE_WRITE_PRIV,
UUID_IDM_HP_PEOPLE_READ_PRIV,
UUID_IDM_HP_PEOPLE_WRITE_PRIV,
UUID_IDM_PEOPLE_WRITE_PRIV,
UUID_IDM_ACCOUNT_READ_PRIV,
UUID_IDM_ACCOUNT_MANAGE_PRIV,
UUID_IDM_ACCOUNT_WRITE_PRIV,
UUID_IDM_HP_ACCOUNT_READ_PRIV,
UUID_IDM_HP_ACCOUNT_MANAGE_PRIV,
UUID_IDM_HP_ACCOUNT_WRITE_PRIV,
];
let res: Result<(), _> = delete_entries
.into_iter()
.try_for_each(|entry_uuid| self.internal_delete_uuid_if_exists(entry_uuid));
if res.is_ok() {
admin_debug!("initialise_idm -> result Ok!");
} else {
admin_error!(?res, "initialise_idm p3 -> result");
}
debug_assert!(res.is_ok());
res?;
self.changed_schema = true;
self.changed_acp = true;
Ok(())
}
#[instrument(level = "info", skip_all)]
pub fn initialise_schema_core(&mut self) -> Result<(), OperationError> {
admin_debug!("initialise_schema_core -> start ...");
@ -678,6 +807,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
// The domain info now exists, we should be able to do these migrations as they will
// cause SPN regenerations to occur
// Delete entries that no longer need to exist.
// TODO: Shouldn't this be a migration?
// Check the admin object exists (migrations).
// Create the default idm_admin group.
let admin_entries: Vec<EntryInitNew> = idm_builtin_admin_entries()?;
@ -704,49 +835,46 @@ impl<'a> QueryServerWriteTransaction<'a> {
let idm_entries: Vec<BuiltinAcp> = vec![
// Built in access controls.
IDM_ADMINS_ACP_RECYCLE_SEARCH_V1.clone(),
IDM_ADMINS_ACP_REVIVE_V1.clone(),
IDM_ALL_ACP_READ_V1.clone(),
IDM_SELF_ACP_READ_V1.clone(),
IDM_SELF_ACP_WRITE_V1.clone(),
E_IDM_PEOPLE_SELF_ACP_WRITE_MAIL_PRIV_V1.clone(),
IDM_ACP_PEOPLE_READ_PRIV_V1.clone(),
IDM_ACP_PEOPLE_WRITE_PRIV_V1.clone(),
IDM_ACP_PEOPLE_MANAGE_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_READ_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_WRITE_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_MANAGE_PRIV_V1.clone(),
IDM_ACP_HP_ACCOUNT_READ_PRIV_V1.clone(),
IDM_ACP_HP_ACCOUNT_WRITE_PRIV_V1.clone(),
IDM_ACP_HP_ACCOUNT_MANAGE_PRIV_V1.clone(),
IDM_ACP_GROUP_WRITE_PRIV_V1.clone(),
IDM_ACP_GROUP_MANAGE_PRIV_V1.clone(),
IDM_ACP_HP_GROUP_WRITE_PRIV_V1.clone(),
IDM_ACP_HP_GROUP_MANAGE_PRIV_V1.clone(),
IDM_ACP_SCHEMA_WRITE_ATTRS_PRIV_V1.clone(),
IDM_ACP_SCHEMA_WRITE_CLASSES_PRIV_V1.clone(),
IDM_ACP_ACP_MANAGE_PRIV_V1.clone(),
IDM_ACP_RECYCLE_BIN_SEARCH_V1.clone(),
IDM_ACP_RECYCLE_BIN_REVIVE_V1.clone(),
IDM_ACP_SCHEMA_WRITE_ATTRS_V1.clone(),
IDM_ACP_SCHEMA_WRITE_CLASSES_V1.clone(),
IDM_ACP_ACP_MANAGE_V1.clone(),
IDM_ACP_GROUP_ENTRY_MANAGED_BY_MODIFY_V1.clone(),
IDM_ACP_GROUP_ENTRY_MANAGER_V1.clone(),
IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_V1.clone(),
IDM_ACP_OAUTH2_MANAGE_V1.clone(),
IDM_ACP_DOMAIN_ADMIN_V1.clone(),
IDM_ACP_SYNC_ACCOUNT_MANAGE_V1.clone(),
IDM_ACP_RADIUS_SERVERS_V1.clone(),
IDM_ACP_DOMAIN_ADMIN_PRIV_V1.clone(),
IDM_ACP_SYSTEM_CONFIG_PRIV_V1.clone(),
IDM_ACP_SYSTEM_CONFIG_SESSION_EXP_PRIV_V1.clone(),
IDM_ACP_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1.clone(),
IDM_ACP_PEOPLE_EXTEND_PRIV_V1.clone(),
IDM_ACP_HP_PEOPLE_READ_PRIV_V1.clone(),
IDM_ACP_HP_PEOPLE_WRITE_PRIV_V1.clone(),
IDM_ACP_HP_PEOPLE_EXTEND_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1.clone(),
E_IDM_HP_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1.clone(),
IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1.clone(),
E_IDM_HP_ACP_GROUP_UNIX_EXTEND_PRIV_V1.clone(),
E_IDM_HP_ACP_OAUTH2_MANAGE_PRIV_V1.clone(),
IDM_ACP_RADIUS_SECRET_READ_PRIV_V1.clone(),
IDM_ACP_RADIUS_SECRET_WRITE_PRIV_V1.clone(),
E_IDM_HP_ACP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_V1.clone(),
E_IDM_HP_ACP_SYNC_ACCOUNT_MANAGE_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_MAIL_READ_PRIV_V1.clone(),
IDM_ACCOUNT_SELF_ACP_WRITE_V1.clone(),
IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_PRIV_V1.clone(),
IDM_ACP_RADIUS_SECRET_MANAGE_V1.clone(),
IDM_ACP_PEOPLE_SELF_WRITE_MAIL_V1.clone(),
IDM_ACP_SELF_READ_V1.clone(),
IDM_ACP_SELF_WRITE_V1.clone(),
IDM_ACP_ACCOUNT_SELF_WRITE_V1.clone(),
IDM_ACP_SELF_NAME_WRITE_V1.clone(),
IDM_ACP_ALL_ACCOUNTS_POSIX_READ_V1.clone(),
IDM_ACP_ACCOUNT_MAIL_READ_V1.clone(),
IDM_ACP_SYSTEM_CONFIG_ACCOUNT_POLICY_MANAGE_V1.clone(),
IDM_ACP_GROUP_UNIX_MANAGE_V1.clone(),
IDM_ACP_HP_GROUP_UNIX_MANAGE_V1.clone(),
IDM_ACP_GROUP_READ_V1.clone(),
IDM_ACP_GROUP_MANAGE_V1.clone(),
IDM_ACP_ACCOUNT_UNIX_EXTEND_V1.clone(),
IDM_ACP_PEOPLE_PII_READ_V1.clone(),
IDM_ACP_PEOPLE_PII_MANAGE_V1.clone(),
IDM_ACP_PEOPLE_CREATE_V1.clone(),
IDM_ACP_PEOPLE_READ_V1.clone(),
IDM_ACP_PEOPLE_MANAGE_V1.clone(),
IDM_ACP_PEOPLE_DELETE_V1.clone(),
IDM_ACP_PEOPLE_CREDENTIAL_RESET_V1.clone(),
IDM_ACP_HP_PEOPLE_CREDENTIAL_RESET_V1.clone(),
IDM_ACP_SERVICE_ACCOUNT_CREATE_V1.clone(),
IDM_ACP_SERVICE_ACCOUNT_DELETE_V1.clone(),
IDM_ACP_SERVICE_ACCOUNT_ENTRY_MANAGER_V1.clone(),
IDM_ACP_SERVICE_ACCOUNT_ENTRY_MANAGED_BY_MODIFY_V1.clone(),
IDM_ACP_HP_SERVICE_ACCOUNT_ENTRY_MANAGED_BY_MODIFY_V1.clone(),
IDM_ACP_SERVICE_ACCOUNT_MANAGE_V1.clone(),
];
let res: Result<(), _> = idm_entries
@ -760,21 +888,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
debug_assert!(res.is_ok());
res?;
// Delete entries that no longer need to exist.
// TODO: Shouldn't this be a migration?
let delete_entries: [Uuid; 1] = [UUID_IDM_ACP_OAUTH2_READ_PRIV_V1];
let res: Result<(), _> = delete_entries
.into_iter()
.try_for_each(|entry_uuid| self.internal_delete_uuid_if_exists(entry_uuid));
if res.is_ok() {
admin_debug!("initialise_idm -> result Ok!");
} else {
admin_error!(?res, "initialise_idm p3 -> result");
}
debug_assert!(res.is_ok());
res?;
// Some attributes we don't want to stomp if they already exist. So we conditionally
// modify them.

View file

@ -18,10 +18,7 @@ use kanidm_client::{KanidmClient, KanidmClientBuilder};
use kanidm_proto::v1::{Filter, Modify, ModifyList};
use kanidmd_core::config::{Configuration, IntegrationTestConfig};
use kanidmd_core::{create_server_core, CoreHandle};
use kanidmd_lib::prelude::{
Attribute, BUILTIN_GROUP_IDM_ADMINS_V1, IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
IDM_PEOPLE_EXTEND_PRIV_V1,
};
use kanidmd_lib::prelude::{Attribute, BUILTIN_GROUP_IDM_ADMINS_V1};
use tokio::task;
pub const ADMIN_TEST_USER: &str = "admin";
@ -116,7 +113,7 @@ pub async fn create_user(rsclient: &KanidmClient, id: &str, group_name: &str) {
{
#[allow(clippy::panic)]
rsclient
.idm_group_create(group_name)
.idm_group_create(group_name, None)
.await
.unwrap_or_else(|_| panic!("Failed to create group {}", group_name));
}
@ -260,21 +257,6 @@ pub async fn is_attr_writable(rsclient: &KanidmClient, id: &str, attr: Attribute
}
pub async fn login_account(rsclient: &KanidmClient, id: &str) {
#[allow(clippy::expect_used)]
rsclient
.idm_group_add_members(
IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1.name,
&[ADMIN_TEST_USER],
)
.await
.expect("Failed to add user to idm_people_account_password_import_priv");
#[allow(clippy::expect_used)]
rsclient
.idm_group_add_members(IDM_PEOPLE_EXTEND_PRIV_V1.name, &[ADMIN_TEST_USER])
.await
.expect("Failed to add user to idm_people_extend_priv");
#[allow(clippy::expect_used)]
rsclient
.idm_person_account_primary_credential_set_password(id, NOT_ADMIN_TEST_PASSWORD)

View file

@ -1,751 +0,0 @@
#![deny(warnings)]
use lazy_static::lazy_static;
use std::collections::HashSet;
use kanidm_client::KanidmClient;
use kanidm_proto::constants::APPLICATION_JSON;
use kanidmd_lib::prelude::*;
use kanidmd_testkit::*;
use reqwest::header::CONTENT_TYPE;
static USER_READABLE_ATTRS: [Attribute; 9] = [
Attribute::Name,
Attribute::Spn,
Attribute::DisplayName,
Attribute::Class,
Attribute::MemberOf,
Attribute::Uuid,
Attribute::GidNumber,
Attribute::LoginShell,
Attribute::SshPublicKey,
];
static SELF_WRITEABLE_ATTRS: [Attribute; 7] = [
Attribute::Name,
Attribute::DisplayName,
Attribute::LegalName,
Attribute::RadiusSecret,
Attribute::SshPublicKey,
Attribute::UnixPassword,
// needs to be last
Attribute::PrimaryCredential,
];
lazy_static! {
static ref DEFAULT_HP_GROUP_NAMES: [&'static str; 24] = [
BUILTIN_GROUP_IDM_ADMINS_V1.name,
BUILTIN_GROUP_SYSTEM_ADMINS_V1.name,
IDM_PEOPLE_MANAGE_PRIV_V1.name,
IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1.name,
IDM_PEOPLE_EXTEND_PRIV_V1.name,
IDM_PEOPLE_WRITE_PRIV_V1.name,
IDM_PEOPLE_READ_PRIV_V1.name,
IDM_GROUP_MANAGE_PRIV_V1.name,
IDM_GROUP_WRITE_PRIV_V1.name,
IDM_ACCOUNT_MANAGE_PRIV_V1.name,
IDM_ACCOUNT_WRITE_PRIV_V1.name,
IDM_ACCOUNT_READ_PRIV_V1.name,
IDM_RADIUS_SERVERS_V1.name,
IDM_HP_ACCOUNT_MANAGE_PRIV_V1.name,
IDM_HP_ACCOUNT_WRITE_PRIV_V1.name,
IDM_HP_ACCOUNT_READ_PRIV_V1.name,
IDM_HP_ACCOUNT_UNIX_EXTEND_PRIV_V1.name,
IDM_SCHEMA_MANAGE_PRIV_V1.name,
IDM_HP_GROUP_MANAGE_PRIV_V1.name,
IDM_HP_GROUP_WRITE_PRIV_V1.name,
IDM_HP_GROUP_UNIX_EXTEND_PRIV_V1.name,
IDM_ACP_MANAGE_PRIV_V1.name,
DOMAIN_ADMINS.name,
IDM_HIGH_PRIVILEGE_V1.name,
];
static ref DEFAULT_NOT_HP_GROUP_NAMES: [&'static str; 2] = [
IDM_ACCOUNT_UNIX_EXTEND_PRIV_V1.name,
IDM_GROUP_UNIX_EXTEND_PRIV_V1.name,
];
}
// Users
// - Read to all self attributes (within security constraints).
// - Write to a limited set of self attributes, such as:
// name, displayname, legalname, ssh-keys, credentials etc.
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_users(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user_with_all_attrs(&rsclient, "self_account", Some("self_group")).await;
create_user_with_all_attrs(&rsclient, "other_account", Some("other_group")).await;
login_account(&rsclient, "self_account").await;
test_read_attrs(&rsclient, "self_account", &USER_READABLE_ATTRS, true).await;
test_read_attrs(&rsclient, "other_account", &USER_READABLE_ATTRS, true).await;
static GROUP_READABLE_ATTRS: [Attribute; 5] = [
Attribute::Class,
Attribute::Name,
Attribute::Spn,
Attribute::Uuid,
Attribute::Member,
];
test_read_attrs(&rsclient, "self_group", &GROUP_READABLE_ATTRS, true).await;
test_read_attrs(&rsclient, "other_group", &GROUP_READABLE_ATTRS, true).await;
static USER_SENSITIVE_ATTRS: [Attribute; 2] = [Attribute::LegalName, Attribute::Mail];
test_read_attrs(&rsclient, "other_account", &USER_SENSITIVE_ATTRS, false).await;
static SELF_READABLE_ATTRS: [Attribute; 1] = [Attribute::RadiusSecret];
test_read_attrs(&rsclient, "self_account", &SELF_READABLE_ATTRS, true).await;
test_read_attrs(&rsclient, "other_account", &SELF_READABLE_ATTRS, false).await;
test_write_attrs(&rsclient, "self_account", &SELF_WRITEABLE_ATTRS, true).await;
test_write_attrs(&rsclient, "other_account", &SELF_WRITEABLE_ATTRS, false).await;
static NON_SELF_WRITEABLE_ATTRS: [Attribute; 5] = [
Attribute::Spn,
Attribute::Class,
Attribute::MemberOf,
Attribute::GidNumber,
Attribute::Uuid,
];
test_write_attrs(&rsclient, "self_account", &NON_SELF_WRITEABLE_ATTRS, false).await;
}
// Account Managers
// read and write to accounts, including write credentials but NOT private data (see people manager)
// ability to lock and unlock accounts, excluding high access members.
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_account_managers(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user(
&rsclient,
"account_manager",
IDM_ACCOUNT_MANAGE_PRIV_V1.name,
)
.await;
create_user_with_all_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, Some("test_group")).await;
login_account(&rsclient, "account_manager").await;
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&USER_READABLE_ATTRS,
true,
)
.await;
static ACCOUNT_MANAGER_ATTRS: [Attribute; 5] = [
Attribute::Name,
Attribute::DisplayName,
Attribute::PrimaryCredential,
Attribute::SshPublicKey,
Attribute::Mail,
];
test_write_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&ACCOUNT_MANAGER_ATTRS,
true,
)
.await;
static PRIVATE_DATA_ATTRS: [Attribute; 1] = [Attribute::LegalName];
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PRIVATE_DATA_ATTRS,
false,
)
.await;
test_write_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PRIVATE_DATA_ATTRS,
false,
)
.await;
// TODO #59: lock and _unlock, except high access members
}
// Group Managers
// read all groups
// write group but not high access
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_group_managers(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user(&rsclient, "group_manager", IDM_GROUP_MANAGE_PRIV_V1.name).await;
// create test user without creating new groups
create_user(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
BUILTIN_GROUP_IDM_ADMINS_V1.name,
)
.await;
login_account(&rsclient, "group_manager").await;
let default_group_names: HashSet<String> =
[&DEFAULT_HP_GROUP_NAMES[..], &DEFAULT_NOT_HP_GROUP_NAMES[..]]
.concat()
.iter()
.map(ToString::to_string)
.collect();
let groups = rsclient.idm_group_list().await.unwrap();
let group_names: HashSet<String> = groups
.iter()
.map(|entry| {
entry
.attrs
.get(Attribute::Name.as_ref())
.unwrap()
.first()
.unwrap()
})
.cloned()
.collect();
assert!(default_group_names.is_subset(&group_names));
test_modify_group(&rsclient, &(*DEFAULT_HP_GROUP_NAMES), false).await;
test_modify_group(&rsclient, &(*DEFAULT_NOT_HP_GROUP_NAMES), true).await;
rsclient.idm_group_create("test_group").await.unwrap();
rsclient
.idm_group_add_members("test_group", &[NOT_ADMIN_TEST_USERNAME])
.await
.unwrap();
assert!(
is_attr_writable(&rsclient, "test_group", Attribute::Description)
.await
.unwrap()
);
}
// Admins
// read and write access control entries.
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_access_control_entries(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
static ACP_COMMON_ATTRS: [Attribute; 4] = [
Attribute::Name,
Attribute::Description,
Attribute::AcpReceiverGroup,
Attribute::AcpTargetScope,
];
let acp_entries = vec![
IDM_ADMINS_ACP_RECYCLE_SEARCH_V1.clone(),
IDM_ADMINS_ACP_REVIVE_V1.clone(),
IDM_SELF_ACP_READ_V1.clone(),
IDM_SELF_ACP_WRITE_V1.clone(),
IDM_ALL_ACP_READ_V1.clone(),
IDM_ACP_PEOPLE_READ_PRIV_V1.clone(),
IDM_ACP_PEOPLE_WRITE_PRIV_V1.clone(),
IDM_ACP_PEOPLE_MANAGE_PRIV_V1.clone(),
IDM_ACP_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1.clone(),
IDM_ACP_PEOPLE_EXTEND_PRIV_V1.clone(),
IDM_ACP_GROUP_WRITE_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_READ_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_WRITE_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_MANAGE_PRIV_V1.clone(),
IDM_ACP_RADIUS_SERVERS_V1.clone(),
IDM_ACP_HP_ACCOUNT_READ_PRIV_V1.clone(),
IDM_ACP_HP_ACCOUNT_WRITE_PRIV_V1.clone(),
IDM_ACP_HP_GROUP_WRITE_PRIV_V1.clone(),
IDM_ACP_SCHEMA_WRITE_ATTRS_PRIV_V1.clone(),
IDM_ACP_ACP_MANAGE_PRIV_V1.clone(),
IDM_ACP_SCHEMA_WRITE_CLASSES_PRIV_V1.clone(),
IDM_ACP_GROUP_MANAGE_PRIV_V1.clone(),
IDM_ACP_HP_ACCOUNT_MANAGE_PRIV_V1.clone(),
IDM_ACP_HP_GROUP_MANAGE_PRIV_V1.clone(),
IDM_ACP_DOMAIN_ADMIN_PRIV_V1.clone(),
IDM_ACP_SYSTEM_CONFIG_PRIV_V1.clone(),
IDM_ACP_ACCOUNT_UNIX_EXTEND_PRIV_V1.clone(),
IDM_ACP_GROUP_UNIX_EXTEND_PRIV_V1.clone(),
];
for entry in acp_entries.iter() {
test_read_attrs(&rsclient, entry.name, &ACP_COMMON_ATTRS, true).await;
test_write_attrs(&rsclient, entry.name, &ACP_COMMON_ATTRS, true).await;
}
}
// read schema entries.
// TODO #252: write schema entries
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_schema_entries(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
let default_classnames: HashSet<String> = [
EntryClass::AccessControlCreate,
EntryClass::AccessControlDelete,
EntryClass::AccessControlModify,
EntryClass::AccessControlProfile,
EntryClass::AccessControlSearch,
EntryClass::AttributeType,
EntryClass::ClassType,
EntryClass::ExtensibleObject,
EntryClass::MemberOf,
EntryClass::Object,
EntryClass::Recycled,
EntryClass::System,
EntryClass::SystemInfo,
EntryClass::Tombstone,
EntryClass::Person,
EntryClass::Group,
EntryClass::Account,
EntryClass::DomainInfo,
EntryClass::PosixAccount,
EntryClass::PosixGroup,
EntryClass::SystemConfig,
]
.into_iter()
.map(|e| e.into())
.collect();
let classtype_entries = rsclient.idm_schema_classtype_list().await.unwrap();
let classnames: HashSet<String> = classtype_entries
.iter()
.map(|entry| {
entry
.attrs
.get(Attribute::ClassName.as_ref())
.unwrap()
.first()
.unwrap()
})
.cloned()
.collect();
println!("{:?}", classnames);
assert!(default_classnames.is_subset(&classnames));
// TODO: this could probably just iterate on the enum?
let default_attributenames: HashSet<String> = [
Attribute::AcpCreateAttr,
Attribute::AcpCreateClass,
Attribute::AcpEnable,
Attribute::AcpModifyClass,
Attribute::AcpModifyPresentAttr,
Attribute::AcpModifyRemovedAttr,
Attribute::AcpReceiverGroup,
Attribute::AcpSearchAttr,
Attribute::AcpTargetScope,
Attribute::AttributeName,
Attribute::Claim,
Attribute::Class,
Attribute::ClassName,
Attribute::Description,
Attribute::DirectMemberOf,
Attribute::Domain,
Attribute::Index,
Attribute::LastModifiedCid,
Attribute::May,
Attribute::Member,
Attribute::MemberOf,
Attribute::MultiValue,
Attribute::Must,
Attribute::Name,
Attribute::PasswordImport,
Attribute::Phantom,
Attribute::Spn,
Attribute::Syntax,
Attribute::SystemMay,
Attribute::SystemMust,
Attribute::Unique,
Attribute::Uuid,
Attribute::Version,
Attribute::DisplayName,
Attribute::LegalName,
Attribute::Mail,
Attribute::SshPublicKey,
Attribute::PrimaryCredential,
Attribute::RadiusSecret,
Attribute::DomainName,
Attribute::DomainDisplayName,
Attribute::DomainUuid,
Attribute::DomainSsid,
Attribute::GidNumber,
Attribute::BadlistPassword,
Attribute::AuthSessionExpiry,
Attribute::PrivilegeExpiry,
Attribute::LoginShell,
Attribute::UnixPassword,
Attribute::NsUniqueId,
]
.iter()
.map(|a| a.as_ref().to_string())
.collect();
let attributename_entries = rsclient.idm_schema_attributetype_list().await.unwrap();
println!("{:?}", attributename_entries);
let attributenames = attributename_entries
.iter()
.map(|entry| {
entry
.attrs
.get(Attribute::AttributeName.as_ref())
.unwrap()
.first()
.unwrap()
})
.cloned()
.collect();
assert!(default_attributenames.is_subset(&attributenames));
}
// modify all groups including high access groups.
// create new accounts (to bootstrap the system).
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_group_entries(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user(&rsclient, NOT_ADMIN_TEST_USERNAME, "test_group").await;
let default_group_names =
[&DEFAULT_HP_GROUP_NAMES[..], &DEFAULT_NOT_HP_GROUP_NAMES[..]].concat();
test_modify_group(&rsclient, &default_group_names, true).await;
}
// modify high access accounts as an escalation for security sensitive accounts.
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_ha_accounts(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
static MAIN_ATTRS: [Attribute; 3] = [
Attribute::Name,
Attribute::DisplayName,
Attribute::PrimaryCredential,
];
test_write_attrs(&rsclient, BUILTIN_ACCOUNT_IDM_ADMIN.name, &MAIN_ATTRS, true).await;
}
// recover from the recycle bin
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_recycle_accounts(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user(&rsclient, NOT_ADMIN_TEST_USERNAME, "test_group").await;
rsclient
.idm_person_account_delete(NOT_ADMIN_TEST_USERNAME)
.await
.unwrap();
rsclient
.recycle_bin_revive(NOT_ADMIN_TEST_USERNAME)
.await
.unwrap();
let acc = rsclient
.idm_person_account_get(NOT_ADMIN_TEST_USERNAME)
.await
.unwrap();
assert!(acc.is_some());
}
// People Managers
// read private or sensitive data of persons, IE legalName
// write private or sensitive data of persons, IE legalName
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_people_managers(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user(
&rsclient,
"read_people_manager",
IDM_PEOPLE_READ_PRIV_V1.name,
)
.await;
create_user_with_all_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, Some("test_group")).await;
static PEOPLE_MANAGER_ATTRS: [Attribute; 2] = [Attribute::LegalName, Attribute::Mail];
static TECHNICAL_ATTRS: [Attribute; 3] = [
Attribute::PrimaryCredential,
Attribute::RadiusSecret,
Attribute::UnixPassword,
];
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PEOPLE_MANAGER_ATTRS,
true,
)
.await;
login_account(&rsclient, "read_people_manager").await;
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PEOPLE_MANAGER_ATTRS,
true,
)
.await;
test_read_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, &TECHNICAL_ATTRS, false).await;
test_write_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PEOPLE_MANAGER_ATTRS,
false,
)
.await;
test_write_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, &TECHNICAL_ATTRS, false).await;
let _ = rsclient.logout();
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
.unwrap();
create_user(
&rsclient,
"write_people_manager",
IDM_PEOPLE_WRITE_PRIV_V1.name,
)
.await;
login_account(&rsclient, "write_people_manager").await;
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PEOPLE_MANAGER_ATTRS,
true,
)
.await;
test_read_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, &TECHNICAL_ATTRS, false).await;
test_write_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&PEOPLE_MANAGER_ATTRS,
true,
)
.await;
test_write_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, &TECHNICAL_ATTRS, false).await;
}
// Anonymous Clients + Everyone Else
// read memberof, unix attrs, name, displayname, class
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_anonymous_entry(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user_with_all_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, Some("test_group")).await;
rsclient
.idm_group_add_members("test_group", &["anonymous"])
.await
.unwrap();
add_all_attrs(&rsclient, "anonymous", "test_group", None).await;
let _ = rsclient.logout();
rsclient.auth_anonymous().await.unwrap();
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&USER_READABLE_ATTRS,
true,
)
.await;
test_read_attrs(&rsclient, "anonymous", &USER_READABLE_ATTRS, true).await;
test_write_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&SELF_WRITEABLE_ATTRS,
false,
)
.await;
test_write_attrs(&rsclient, "anonymous", &SELF_WRITEABLE_ATTRS, false).await;
}
// RADIUS Servers
// Read radius credentials
// Read other needed attributes to fulfil radius functions.
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_radius_servers(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
create_user(&rsclient, "radius_server", IDM_RADIUS_SERVERS_V1.name).await;
create_user_with_all_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, Some("test_group")).await;
login_account(&rsclient, "radius_server").await;
static RADIUS_NECESSARY_ATTRS: [Attribute; 4] = [
Attribute::Name,
Attribute::Spn,
Attribute::Uuid,
Attribute::RadiusSecret,
];
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&USER_READABLE_ATTRS,
true,
)
.await;
test_read_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&RADIUS_NECESSARY_ATTRS,
true,
)
.await;
test_write_attrs(
&rsclient,
NOT_ADMIN_TEST_USERNAME,
&RADIUS_NECESSARY_ATTRS,
false,
)
.await;
}
#[kanidmd_testkit::test]
async fn test_self_write_mail_priv_people(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
// test and other, each can write to themselves, but not each other
create_user_with_all_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, None).await;
create_user_with_all_attrs(&rsclient, "other", None).await;
rsclient
.idm_group_add_members(
IDM_PEOPLE_SELF_WRITE_MAIL_PRIV_V1.name,
&["other", NOT_ADMIN_TEST_USERNAME],
)
.await
.unwrap();
// a non-person, they can't write to themselves even with the priv
create_user(&rsclient, "nonperson", "nonperson_group").await;
login_account(&rsclient, NOT_ADMIN_TEST_USERNAME).await;
// can write to own mail
test_write_attrs(&rsclient, NOT_ADMIN_TEST_USERNAME, &[Attribute::Mail], true).await;
// not someone elses
test_write_attrs(&rsclient, "other", &[Attribute::Mail], false).await;
// but they can write to theirs
login_account_via_admin(&rsclient, "other").await;
test_write_attrs(&rsclient, "other", &[Attribute::Mail], true).await;
login_account_via_admin(&rsclient, "nonperson").await;
test_write_attrs(&rsclient, "nonperson", &[Attribute::Mail], false).await;
}
#[kanidmd_testkit::test]
async fn test_https_robots_txt(rsclient: KanidmClient) {
// We need to do manual reqwests here.
let response = match reqwest::get(rsclient.make_url("/robots.txt")).await {
Ok(value) => value,
Err(error) => {
panic!(
"Failed to query {:?} : {:#?}",
rsclient.make_url("/robots.txt"),
error
);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 200);
eprintln!(
"csp headers: {:#?}",
response
.headers()
.get(http::header::CONTENT_SECURITY_POLICY)
);
assert_ne!(
response
.headers()
.get(http::header::CONTENT_SECURITY_POLICY),
None
);
eprintln!("{}", response.text().await.unwrap());
}
/// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
#[kanidmd_testkit::test]
async fn test_v1_raw_delete(rsclient: KanidmClient) {
// We need to do manual reqwests here.
let client = reqwest::ClientBuilder::new()
.danger_accept_invalid_certs(true)
.build()
.unwrap();
let post_body = serde_json::json!({"filter": "self"}).to_string();
let response = match client
.post(rsclient.make_url("/v1/raw/delete"))
.header(CONTENT_TYPE, APPLICATION_JSON)
.body(post_body)
.send()
.await
{
Ok(value) => value,
Err(error) => {
panic!(
"Failed to query {:?} : {:#?}",
rsclient.make_url("/v1/raw/delete"),
error
);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 401);
let body = response.text().await.unwrap();
eprintln!("{}", body);
}
/// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
#[kanidmd_testkit::test]
async fn test_v1_raw_logout(rsclient: KanidmClient) {
// We need to do manual reqwests here.
let client = reqwest::ClientBuilder::new()
.danger_accept_invalid_certs(true)
.build()
.unwrap();
let response = match client.get(rsclient.make_url("/v1/logout")).send().await {
Ok(value) => value,
Err(error) => {
panic!(
"Failed to query {:?} : {:#?}",
rsclient.make_url("/v1/logout"),
error
);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 401);
let body = response.text().await.unwrap();
eprintln!("{}", body);
}
/// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
#[kanidmd_testkit::test]
async fn test_status_endpoint(rsclient: KanidmClient) {
// We need to do manual reqwests here.
let client = reqwest::ClientBuilder::new()
.danger_accept_invalid_certs(true)
.build()
.unwrap();
let response = match client.get(rsclient.make_url("/status")).send().await {
Ok(value) => value,
Err(error) => {
panic!(
"Failed to query {:?} : {:#?}",
rsclient.make_url("/status"),
error
);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 200);
let body = response.text().await.unwrap();
eprintln!("{}", body);
assert!(body.contains("true") == true);
}

View file

@ -5,16 +5,11 @@ use kanidm_proto::{
v1::Entry,
};
use kanidmd_lib::prelude::{
Attribute, BUILTIN_GROUP_IDM_ADMINS_V1, IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
IDM_PEOPLE_MANAGE_PRIV_V1,
};
use kanidmd_lib::prelude::Attribute;
use kanidmd_testkit::ADMIN_TEST_PASSWORD;
use reqwest::StatusCode;
static UNIVERSAL_PW: &'static str = "eicieY7ahchaoCh0eeTa";
static UNIVERSAL_PW_HASH: &'static str =
"pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=";
static USER_A_NAME: &'static str = "valid_user_a";
@ -272,23 +267,6 @@ async fn setup_server(rsclient: &KanidmClient) {
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
assert!(res.is_ok());
// To enable the admin to actually make some of these changes, we have
// to make them a people admin. NOT recommended in production!
rsclient
.idm_group_add_members(IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1.name, &["admin"])
.await
.unwrap();
rsclient
.idm_group_add_members(IDM_PEOPLE_MANAGE_PRIV_V1.name, &["admin"])
.await
.unwrap();
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &["admin"])
.await
.unwrap();
}
async fn create_user(rsclient: &KanidmClient, user: &str) -> String {
@ -306,10 +284,12 @@ async fn create_user(rsclient: &KanidmClient, user: &str) -> String {
let res = rsclient.create(vec![e.clone()]).await;
assert!(res.is_ok());
rsclient
.idm_person_account_primary_credential_import_password(user, UNIVERSAL_PW_HASH)
.idm_person_account_primary_credential_set_password(user, UNIVERSAL_PW)
.await
.unwrap();
let r = rsclient
.idm_person_account_get_attr(user, Attribute::Uuid.as_ref())
.await

View file

@ -10,7 +10,7 @@ use kanidm_proto::oauth2::{
AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AccessTokenRequest,
AccessTokenResponse, AuthorisationResponse, GrantTypeReq, OidcDiscoveryResponse,
};
use kanidmd_lib::prelude::{Attribute, BUILTIN_GROUP_IDM_ADMINS_V1, IDM_ALL_ACCOUNTS};
use kanidmd_lib::prelude::{Attribute, IDM_ALL_ACCOUNTS};
use oauth2_ext::PkceCodeChallenge;
use reqwest::header::{HeaderValue, CONTENT_TYPE};
use reqwest::StatusCode;
@ -66,11 +66,6 @@ async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
.expect("Failed to create oauth2 config");
// Extend the admin account with extended details for openid claims.
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &["admin"])
.await
.unwrap();
rsclient
.idm_person_account_create("oauth_test", "oauth_test")
.await
@ -429,11 +424,6 @@ async fn test_oauth2_openid_public_flow(rsclient: KanidmClient) {
.expect("Failed to create oauth2 config");
// Extend the admin account with extended details for openid claims.
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &["admin"])
.await
.unwrap();
rsclient
.idm_person_account_create("oauth_test", "oauth_test")
.await

View file

@ -6,13 +6,11 @@ use kanidm_proto::constants::KSESSIONID;
use kanidm_proto::internal::ImageValue;
use kanidm_proto::v1::{
ApiToken, AuthCredential, AuthIssueSession, AuthMech, AuthRequest, AuthResponse, AuthState,
AuthStep, CURegState, CredentialDetailType, Entry, Filter, Modify, ModifyList, UatPurpose,
UserAuthToken,
AuthStep, CURegState, Entry, Filter, Modify, ModifyList, UatPurpose, UserAuthToken,
};
use kanidmd_lib::credential::totp::Totp;
use kanidmd_lib::prelude::{
Attribute, BUILTIN_GROUP_IDM_ADMINS_V1, BUILTIN_GROUP_SYSTEM_ADMINS_V1,
IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1,
};
use tracing::{debug, trace};
@ -53,29 +51,6 @@ async fn test_server_create(rsclient: KanidmClient) {
assert!(res.is_ok());
}
#[kanidmd_testkit::test]
async fn test_server_modify(rsclient: KanidmClient) {
// Build a self mod.
let f = Filter::SelfUuid;
let m = ModifyList::new_list(vec![
Modify::Purged(Attribute::DisplayName.to_string()),
Modify::Present(Attribute::DisplayName.to_string(), "test".to_string()),
]);
// Not logged in - should fail!
let res = rsclient.modify(f.clone(), m.clone()).await;
assert!(res.is_err());
let a_res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
assert!(a_res.is_ok());
let res = rsclient.modify(f, m).await;
println!("{:?}", res);
assert!(res.is_ok());
}
#[kanidmd_testkit::test]
async fn test_server_whoami_anonymous(rsclient: KanidmClient) {
// First show we are un-authenticated.
@ -181,7 +156,10 @@ async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
assert!(!g_list.is_empty());
// Create a new group
rsclient.idm_group_create("demo_group").await.unwrap();
rsclient
.idm_group_create("demo_group", Some(BUILTIN_GROUP_IDM_ADMINS_V1.name))
.await
.unwrap();
// List again, ensure one more.
let g_list_2 = rsclient.idm_group_list().await.unwrap();
@ -246,7 +224,13 @@ async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
.await
.unwrap();
println!("{:?}", members);
assert!(members == Some(vec!["idm_admin@localhost".to_string()]));
assert!(
members
== Some(vec![
"admin@localhost".to_string(),
"idm_admin@localhost".to_string()
])
);
}
#[kanidmd_testkit::test]
@ -552,7 +536,10 @@ async fn test_server_rest_posix_lifecycle(rsclient: KanidmClient) {
// Create a group
// Extend the group with posix attrs
rsclient.idm_group_create("posix_group").await.unwrap();
rsclient
.idm_group_create("posix_group", Some(BUILTIN_GROUP_IDM_ADMINS_V1.name))
.await
.unwrap();
rsclient
.idm_group_add_members("posix_group", &["posix_account"])
.await
@ -784,67 +771,6 @@ async fn test_server_rest_recycle_lifecycle(rsclient: KanidmClient) {
assert!(acc.is_some());
}
#[kanidmd_testkit::test]
async fn test_server_rest_account_import_password(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
assert!(res.is_ok());
// To enable the admin to actually make some of these changes, we have
// to make them a password import admin. NOT recommended in production!
rsclient
.idm_group_add_members(IDM_PEOPLE_ACCOUNT_PASSWORD_IMPORT_PRIV_V1.name, &["admin"])
.await
.unwrap();
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &["admin"])
.await
.unwrap();
// Create a new person
rsclient
.idm_person_account_create("demo_account", "Deeeeemo")
.await
.unwrap();
// Attempt to import a bad password
let r = rsclient
.idm_person_account_primary_credential_import_password("demo_account", "password")
.await;
assert!(r.is_err());
// Import a good password
// eicieY7ahchaoCh0eeTa
// pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=
rsclient
.idm_person_account_primary_credential_import_password(
"demo_account",
"pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w=",
)
.await
.unwrap();
// Now show we can auth with it
// "reset" the client.
let _ = rsclient.logout();
let res = rsclient
.auth_simple_password("demo_account", "eicieY7ahchaoCh0eeTa")
.await;
assert!(res.is_ok());
// And that the account can self read the cred status.
let cred_state = rsclient
.idm_person_account_get_credential_status("demo_account")
.await
.unwrap();
if let Some(cred) = cred_state.creds.get(0) {
assert!(cred.type_ == CredentialDetailType::Password)
} else {
assert!(false);
}
}
#[kanidmd_testkit::test]
async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
let res = rsclient
@ -852,6 +778,11 @@ async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
.await;
assert!(res.is_ok());
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &["admin"])
.await
.unwrap();
// List, there are non.
let initial_configs = rsclient
.idm_oauth2_rs_list()
@ -1119,6 +1050,23 @@ async fn test_server_credential_update_session_pw(rsclient: KanidmClient) {
.auth_simple_password("demo_account", "eicieY7ahchaoCh0eeTa")
.await;
assert!(res.is_ok());
// Get privs
let res = rsclient
.reauth_simple_password("eicieY7ahchaoCh0eeTa")
.await;
assert!(res.is_ok());
// Build a self mod.
let f = Filter::SelfUuid;
let m = ModifyList::new_list(vec![
Modify::Purged(Attribute::DisplayName.to_string()),
Modify::Present(Attribute::DisplayName.to_string(), "test".to_string()),
]);
let res = rsclient.modify(f, m).await;
println!("{:?}", res);
assert!(res.is_ok());
}
#[kanidmd_testkit::test]
@ -1341,12 +1289,6 @@ async fn setup_demo_account_password(
.await
.expect("Failed to authenticate as admin");
// Not recommended in production!
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &["admin"])
.await
.expect("Failed to add admin to idm_admins");
rsclient
.idm_person_account_create("demo_account", "Deeeeemo")
.await
@ -1417,14 +1359,12 @@ async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
let test_service_account_username = "test_service";
// Not recommended in production!
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &[ADMIN_TEST_USER])
.await
.unwrap();
rsclient
.idm_service_account_create(test_service_account_username, "Test Service")
.idm_service_account_create(
test_service_account_username,
"Test Service",
BUILTIN_GROUP_IDM_ADMINS_V1.name,
)
.await
.expect("Failed to create service account");
@ -1539,7 +1479,7 @@ async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
// because you have to set *something*
assert!(rsclient
.idm_service_account_update(test_service_account_username, None, None, None)
.idm_service_account_update(test_service_account_username, None, None, None, None)
.await
.is_err());
@ -1549,6 +1489,7 @@ async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
test_service_account_username,
None,
Some(&format!("{}displayzzzz", test_service_account_username)),
None,
Some(&[format!("{}@example.crabs", test_service_account_username)]),
)
.await
@ -1598,12 +1539,6 @@ async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
.await;
assert!(res.is_ok());
// Not recommended in production!
rsclient
.idm_group_add_members(BUILTIN_GROUP_IDM_ADMINS_V1.name, &[ADMIN_TEST_USER])
.await
.unwrap();
rsclient
.idm_person_account_create("demo_account", "Deeeeemo")
.await

View file

@ -225,7 +225,7 @@ function makeMutClosure(arg0, arg1, dtor, f) {
return real;
}
function __wbg_adapter_48(arg0, arg1) {
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0c62d2840bb83f65(arg0, arg1);
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hde72e8f1b6402df0(arg0, arg1);
}
let stack_pointer = 128;
@ -1141,20 +1141,20 @@ function __wbg_get_imports() {
const ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper1150 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 572, __wbg_adapter_48);
imports.wbg.__wbindgen_closure_wrapper930 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 527, __wbg_adapter_48);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper3558 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1660, __wbg_adapter_51);
imports.wbg.__wbindgen_closure_wrapper3569 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1662, __wbg_adapter_51);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper3751 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1707, __wbg_adapter_54);
imports.wbg.__wbindgen_closure_wrapper3762 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1709, __wbg_adapter_54);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper3835 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1738, __wbg_adapter_57);
imports.wbg.__wbindgen_closure_wrapper3846 = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, 1740, __wbg_adapter_57);
return addHeapObject(ret);
};

View file

@ -384,6 +384,7 @@ impl CredentialResetApp {
CUExtPortal::None => html! { <></> },
CUExtPortal::Hidden => html! {
<>
<hr class="my-4" />
<p>{ "This account is externally managed. Some features may not be available." }</p>
</>
},
@ -391,6 +392,7 @@ impl CredentialResetApp {
let url_str = url.as_str().to_string();
html! {
<>
<hr class="my-4" />
<p>{ "This account is externally managed. Some features may not be available." }</p>
<a href={ url_str } >{ "Visit the external account portal" }</a>
</>
@ -468,7 +470,6 @@ impl CredentialResetApp {
<div class="row g-3">
<form class="needs-validation" novalidate=true>
<hr class="my-4" />
{ ext_cred_portal_html }
@ -738,7 +739,7 @@ impl CredentialResetApp {
let cb = self.cb.clone();
match attested_passkeys_state {
CUCredState::Modifiable | CUCredState::DeleteOnly => {
CUCredState::Modifiable => {
html! {
<>
<hr class="my-4" />
@ -756,16 +757,34 @@ impl CredentialResetApp {
)
}
{
if attested_passkeys_state == CUCredState::Modifiable {
html! { <PasskeyModalApp token={ token.clone() } cb={ cb } class={ PasskeyClass::Attested } allowed_devices={ Some(attested_passkeys_allowed_devices.to_vec()) } /> }
} else {
html! { <></> }
}
}
<PasskeyModalApp token={ token.clone() } cb={ cb } class={ PasskeyClass::Attested } allowed_devices={ Some(attested_passkeys_allowed_devices.to_vec()) } />
</>
}
}
CUCredState::DeleteOnly => {
if attested_passkeys.is_empty() {
html! { <></> }
} else {
html! {
<>
<hr class="my-4" />
<h4>{"Attested Passkeys"}</h4>
{ for attested_passkeys.iter()
.map(|detail|
PasskeyRemoveModalApp::render_button(&detail.tag, detail.uuid)
)
}
{ for attested_passkeys.iter()
.map(|detail|
html! { <PasskeyRemoveModalApp token={ token.clone() } tag={ detail.tag.clone() } uuid={ detail.uuid } cb={ cb.clone() } class={ PasskeyClass::Attested } /> }
)
}
</>
}
}
}
CUCredState::AccessDeny | CUCredState::PolicyDeny => {
// Don't display anything.
html! { <></> }

View file

@ -53,7 +53,10 @@ RUN \
--target-dir="/usr/src/kanidm/target/" \
--features="${KANIDM_FEATURES}" \
--release && \
cargo install --force fido-mds-tool \
cargo install \
--git https://github.com/kanidm/webauthn-rs.git \
--rev 5f4db4172f8e22aedc68c282d177e98db2b1892f \
--force fido-mds-tool \
--target-dir="/usr/src/kanidm/target/" && \
sccache -s

View file

@ -8,7 +8,7 @@ impl GroupOpt {
match self {
GroupOpt::List(copt) => copt.debug,
GroupOpt::Get(gcopt) => gcopt.copt.debug,
GroupOpt::Create(gcopt) => gcopt.copt.debug,
GroupOpt::SetEntryManagedBy { copt, .. } | GroupOpt::Create { copt, .. } => copt.debug,
GroupOpt::Delete(gcopt) => gcopt.copt.debug,
GroupOpt::ListMembers(gcopt) => gcopt.copt.debug,
GroupOpt::AddMembers(gcopt) => gcopt.copt.debug,
@ -58,13 +58,20 @@ impl GroupOpt {
Err(e) => handle_client_error(e, gcopt.copt.output_mode),
}
}
GroupOpt::Create(gcopt) => {
let client = gcopt.copt.to_client(OpType::Write).await;
match client.idm_group_create(gcopt.name.as_str()).await {
GroupOpt::Create {
copt,
name,
entry_managed_by,
} => {
let client = copt.to_client(OpType::Write).await;
match client
.idm_group_create(name.as_str(), entry_managed_by.as_deref())
.await
{
Err(err) => {
error!("Error -> {:?}", err)
}
Ok(_) => println!("Successfully created group '{}'", gcopt.name.as_str()),
Ok(_) => println!("Successfully created group '{}'", name.as_str()),
}
}
GroupOpt::Delete(gcopt) => {
@ -124,7 +131,6 @@ impl GroupOpt {
Ok(_) => println!("Successfully removed members from {}", gcopt.name.as_str()),
}
}
GroupOpt::SetMembers(gcopt) => {
let client = gcopt.copt.to_client(OpType::Write).await;
let new_members: Vec<&str> = gcopt.members.iter().map(String::as_str).collect();
@ -137,6 +143,21 @@ impl GroupOpt {
Ok(_) => println!("Successfully set members for group {}", gcopt.name.as_str()),
}
}
GroupOpt::SetEntryManagedBy {
name,
entry_managed_by,
copt,
} => {
let client = copt.to_client(OpType::Write).await;
match client
.idm_group_set_entry_managed_by(name.as_str(), entry_managed_by.as_str())
.await
{
Err(e) => handle_client_error(e, copt.output_mode),
Ok(_) => println!("Successfully set members for group {}", name.as_str()),
}
}
GroupOpt::Posix { commands } => match commands {
GroupPosix::Show(gcopt) => {
let client = gcopt.copt.to_client(OpType::Read).await;

View file

@ -38,7 +38,7 @@ impl ServiceAccountOpt {
ServiceAccountOpt::Get(aopt) => aopt.copt.debug,
ServiceAccountOpt::Update(aopt) => aopt.copt.debug,
ServiceAccountOpt::Delete(aopt) => aopt.copt.debug,
ServiceAccountOpt::Create(aopt) => aopt.copt.debug,
ServiceAccountOpt::Create { copt, .. } => copt.debug,
ServiceAccountOpt::Validity { commands } => match commands {
AccountValidity::Show(ano) => ano.copt.debug,
AccountValidity::ExpireAt(ano) => ano.copt.debug,
@ -301,6 +301,7 @@ impl ServiceAccountOpt {
aopt.aopts.account_id.as_str(),
aopt.newname.as_deref(),
aopt.displayname.as_deref(),
aopt.entry_managed_by.as_deref(),
aopt.mail.as_deref(),
)
.await
@ -349,16 +350,22 @@ impl ServiceAccountOpt {
}
};
}
ServiceAccountOpt::Create(acopt) => {
let client = acopt.copt.to_client(OpType::Write).await;
ServiceAccountOpt::Create {
aopts,
copt,
display_name,
entry_managed_by,
} => {
let client = copt.to_client(OpType::Write).await;
if let Err(e) = client
.idm_service_account_create(
acopt.aopts.account_id.as_str(),
acopt.display_name.as_str(),
aopts.account_id.as_str(),
display_name.as_str(),
entry_managed_by.as_str(),
)
.await
{
handle_client_error(e, acopt.copt.output_mode)
handle_client_error(e, copt.output_mode)
}
}
ServiceAccountOpt::Validity { commands } => match commands {

View file

@ -209,7 +209,14 @@ pub enum GroupOpt {
Get(Named),
/// Create a new group
#[clap(name = "create")]
Create(Named),
Create {
/// The name of the group
name: String,
/// Optional name/spn of a group that have entry manager rights over this group.
entry_managed_by: Option<String>,
#[clap(flatten)]
copt: CommonOpt,
},
/// Delete a group
#[clap(name = "delete")]
Delete(Named),
@ -220,6 +227,16 @@ pub enum GroupOpt {
/// set operation.
#[clap(name = "set-members")]
SetMembers(GroupNamedMembers),
/// Set a new entry-managed-by for this group.
#[clap(name = "set-entry-manager")]
SetEntryManagedBy {
/// The name of the group
name: String,
/// Optional name/spn of a group that have entry manager rights over this group.
entry_managed_by: String,
#[clap(flatten)]
copt: CommonOpt,
},
/// Delete all members of a group.
#[clap(name = "purge-members")]
PurgeMembers(Named),
@ -345,7 +362,6 @@ pub enum AccountCredential {
#[clap(flatten)]
copt: CommonOpt,
/// Optionally set how many seconds the reset token should be valid for.
#[clap(long = "ttl")]
ttl: Option<u32>,
},
}
@ -571,6 +587,12 @@ pub struct ServiceAccountUpdateOpt {
help = "Set the display name for the service account."
)]
displayname: Option<String>,
#[clap(
long,
short = 'e',
help = "Set the entry manager for the service account."
)]
entry_managed_by: Option<String>,
#[clap(
long,
short,
@ -621,7 +643,16 @@ pub enum ServiceAccountOpt {
Get(AccountNamedOpt),
/// Create a new service account
#[clap(name = "create")]
Create(AccountCreateOpt),
Create {
#[clap(flatten)]
aopts: AccountCommonOpt,
#[clap(name = "display-name")]
display_name: String,
#[clap(name = "entry-managed-by")]
entry_managed_by: String,
#[clap(flatten)]
copt: CommonOpt,
},
/// Update a specific service account's attributes
#[clap(name = "update")]
Update(ServiceAccountUpdateOpt),

View file

@ -160,7 +160,7 @@ impl KaniHttpServer {
}
Entity::Group(g) => {
self.client
.idm_group_create(&g.name)
.idm_group_create(&g.name, None)
.await
.map(|_| ())
.or_else(|e| {

View file

@ -158,12 +158,6 @@ async fn test_fixture(rsclient: KanidmClient) {
debug!("auth_simple_password res: {:?}", res);
trace!("{:?}", &res);
assert!(res.is_ok());
// Not recommended in production!
rsclient
.idm_group_add_members("idm_admins", &["admin"])
.await
.unwrap();
// Create a new account
rsclient
.idm_person_account_create("testaccount1", "Posix Demo Account")
@ -188,7 +182,7 @@ async fn test_fixture(rsclient: KanidmClient) {
.unwrap();
// Setup a group
rsclient.idm_group_create("testgroup1").await.unwrap();
rsclient.idm_group_create("testgroup1", None).await.unwrap();
rsclient
.idm_group_add_members("testgroup1", &["testaccount1"])
.await
@ -199,14 +193,20 @@ async fn test_fixture(rsclient: KanidmClient) {
.unwrap();
// Setup the allowed group
rsclient.idm_group_create("allowed_group").await.unwrap();
rsclient
.idm_group_create("allowed_group", None)
.await
.unwrap();
rsclient
.idm_group_unix_extend("allowed_group", Some(20002))
.await
.unwrap();
// Setup a group that is masked by nxset, but allowed in overrides
rsclient.idm_group_create("masked_group").await.unwrap();
rsclient
.idm_group_create("masked_group", None)
.await
.unwrap();
rsclient
.idm_group_unix_extend("masked_group", Some(20003))
.await