Refactor of value and addition of base types for business attributes ()

This commit is contained in:
Firstyear 2021-12-16 10:13:03 +10:00 committed by GitHub
parent 68072b0420
commit 42df4bf1a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1542 additions and 1099 deletions

211
Cargo.lock generated
View file

@ -87,9 +87,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.45"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
checksum = "62e1f47f7dc0422027a4e370dd4548d4d66b26782e513e98dca1e689e058a80e"
[[package]]
name = "anymap"
@ -169,18 +169,16 @@ dependencies = [
[[package]]
name = "async-h1"
version = "2.3.2"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc5142de15b549749cce62923a50714b0d7b77f5090ced141599e78899865451"
checksum = "8101020758a4fc3a7c326cb42aa99e9fa77cbfb76987c128ad956406fe1f70a7"
dependencies = [
"async-channel",
"async-dup",
"async-std",
"byte-pool",
"futures-core",
"http-types",
"httparse",
"lazy_static",
"log",
"pin-project",
]
@ -428,9 +426,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "0.19.5"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
dependencies = [
"funty",
"radium",
@ -544,16 +542,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "byte-pool"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8c7230ddbb427b1094d477d821a99f3f54d36333178eeb806e279bcdcecf0ca"
dependencies = [
"crossbeam-queue",
"stable_deref_trait",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
@ -822,7 +810,7 @@ dependencies = [
"clap",
"criterion-plot",
"csv",
"itertools",
"itertools 0.10.1",
"lazy_static",
"num-traits",
"oorandom",
@ -844,7 +832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"itertools",
"itertools 0.10.1",
]
[[package]]
@ -1294,9 +1282,9 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futures"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e"
dependencies = [
"futures-channel",
"futures-core",
@ -1309,9 +1297,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
dependencies = [
"futures-core",
"futures-sink",
@ -1319,15 +1307,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
[[package]]
name = "futures-executor"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97"
dependencies = [
"futures-core",
"futures-task",
@ -1336,9 +1324,9 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11"
[[package]]
name = "futures-lite"
@ -1357,12 +1345,10 @@ dependencies = [
[[package]]
name = "futures-macro"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd"
dependencies = [
"autocfg",
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
@ -1370,23 +1356,22 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
[[package]]
name = "futures-task"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
[[package]]
name = "futures-util"
version = "0.3.17"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
dependencies = [
"autocfg",
"futures-channel",
"futures-core",
"futures-io",
@ -1396,8 +1381,6 @@ dependencies = [
"memchr",
"pin-project-lite 0.2.7",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
"slab",
]
@ -1666,9 +1649,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
[[package]]
name = "httpdate"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "humantime"
@ -1678,9 +1661,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "0.14.14"
version = "0.14.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
dependencies = [
"bytes",
"futures-channel",
@ -1741,6 +1724,12 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "if_chain"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
[[package]]
name = "indent_write"
version = "2.2.0"
@ -1778,6 +1767,15 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.10.1"
@ -2058,9 +2056,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.107"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
[[package]]
name = "libm"
@ -2109,6 +2107,12 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.5"
@ -2137,6 +2141,15 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "matchers"
version = "0.0.1"
@ -2250,6 +2263,7 @@ version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"lexical-core",
"memchr",
"version_check 0.9.3",
]
@ -2387,6 +2401,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "oncemutex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2"
[[package]]
name = "oorandom"
version = "11.1.3"
@ -2427,9 +2447,9 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-sys"
version = "0.9.70"
version = "0.9.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf"
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
dependencies = [
"autocfg",
"cc",
@ -2546,6 +2566,26 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "phonenumber"
version = "0.3.1+8.12.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261a014e5f5e048bf2c6f1a72fa5e4c223009dc5f296a385b95fe19b464608f"
dependencies = [
"bincode",
"either",
"fnv",
"itertools 0.9.0",
"lazy_static",
"nom 5.1.2",
"quick-xml",
"regex",
"regex-cache",
"serde",
"serde_derive",
"thiserror",
]
[[package]]
name = "pin-project"
version = "1.0.8"
@ -2688,12 +2728,6 @@ version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "1.0.32"
@ -2705,9 +2739,9 @@ dependencies = [
[[package]]
name = "psl-types"
version = "2.0.7"
version = "2.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66b398073e7cdd6f05934389a8f5961e3aabfa66675b6f440df4e2c793d51a4f"
checksum = "01e985332847890fc9ff26986900c036c8b3fde8da6a31d8ca315cc116405b8c"
[[package]]
name = "publicsuffix"
@ -2736,6 +2770,15 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quick-xml"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cc440ee4802a86e357165021e3e255a9143724da31db1e2ea540214c96a0f82"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.10"
@ -2917,6 +2960,18 @@ dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-cache"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7b62d69743b8b94f353b6b7c3deb4c5582828328bcb8d5fedf214373808793"
dependencies = [
"lru-cache",
"oncemutex",
"regex",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
@ -3166,9 +3221,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.70"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3"
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
dependencies = [
"itoa",
"ryu",
@ -3339,12 +3394,6 @@ dependencies = [
"sha2 0.8.2",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "standback"
version = "0.2.17"
@ -3666,9 +3715,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.13.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
dependencies = [
"autocfg",
"bytes",
@ -3686,9 +3735,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095"
checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
dependencies = [
"proc-macro2",
"quote",
@ -3926,11 +3975,29 @@ checksum = "6d0f08911ab0fee2c5009580f04615fa868898ee57de10692a45da0c3bcc3e5e"
dependencies = [
"idna",
"lazy_static",
"phonenumber",
"regex",
"serde",
"serde_derive",
"serde_json",
"url",
"validator_derive",
"validator_types",
]
[[package]]
name = "validator_derive"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d85135714dba11a1bd0b3eb1744169266f1a38977bf4e3ff5e2e1acb8c2b7eee"
dependencies = [
"if_chain",
"lazy_static",
"proc-macro-error",
"proc-macro2",
"quote",
"regex",
"syn",
"validator_types",
]
@ -4318,7 +4385,7 @@ dependencies = [
"chrono",
"derive_builder",
"fancy-regex",
"itertools",
"itertools 0.10.1",
"lazy_static",
"quick-error",
"regex",

View file

@ -1400,6 +1400,7 @@ impl KanidmAsyncClient {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn idm_oauth2_rs_update(
&self,
id: &str,

View file

@ -907,6 +907,7 @@ impl KanidmClient {
tokio_block_on(self.asclient.idm_oauth2_rs_get(id))
}
#[allow(clippy::too_many_arguments)]
pub fn idm_oauth2_rs_update(
&self,
id: &str,

View file

@ -1,3 +1,5 @@
#![allow(dead_code)]
use std::env;
use std::path::PathBuf;
@ -16,8 +18,7 @@ fn main() {
let comp_dir = PathBuf::from(outdir)
.ancestors()
.skip(2)
.next()
.nth(2)
.map(|p| p.join("completions"))
.expect("Unable to process completions path");

View file

@ -115,11 +115,11 @@ pub fn write_tokens(tokens: &BTreeMap<String, String>) -> Result<(), ()> {
}
/// An interactive dialog to choose from given options
fn get_index_choice_dialoguer(msg: &str, options: &Vec<String>) -> usize {
fn get_index_choice_dialoguer(msg: &str, options: &[String]) -> usize {
let user_select = Select::with_theme(&ColorfulTheme::default())
.with_prompt(msg)
.default(0)
.items(&options)
.items(options)
.interact();
let selection = match user_select {
@ -238,7 +238,7 @@ impl LoginOpt {
options.push(val.to_string());
}
let msg = "Please choose how you want to authenticate:";
let selection = get_index_choice_dialoguer(&msg, &options);
let selection = get_index_choice_dialoguer(msg, &options);
#[allow(clippy::expect_used)]
mechs
@ -276,7 +276,7 @@ impl LoginOpt {
options.push(val.to_string());
}
let msg = "Please choose what credential to provide:";
let selection = get_index_choice_dialoguer(&msg, &options);
let selection = get_index_choice_dialoguer(msg, &options);
#[allow(clippy::expect_used)]
allowed

View file

@ -1,3 +1,5 @@
#![allow(dead_code)]
#[macro_use]
extern crate serde_derive;
@ -25,8 +27,7 @@ fn main() {
let comp_dir = PathBuf::from(outdir)
.ancestors()
.skip(2)
.next()
.nth(2)
.map(|p| p.join("completions"))
.expect("Unable to process completions path");

View file

@ -69,7 +69,6 @@ time = { version = "0.2", features = ["serde", "std"] }
hashbrown = "0.11"
concread = "^0.2.16"
smolset = "1.3"
# concread = { version = "^0.2.9", path = "../../concread" }
# concread = { version = "^0.2.9", features = ["simd_support"] }
sshkeys = "^0.3.1"
@ -81,7 +80,6 @@ zxcvbn = "2.0"
base64 = "0.13"
idlset = { version = "^0.2" }
# idlset = { version = "^0.2", path = "../../idlset" }
ldap3_server = "0.1"
webauthn-rs = "0.3"
@ -91,7 +89,7 @@ users = "0.11"
smartstring = { version = "0.2", features = ["serde"] }
validator = { version = "0.14" }
validator = { version = "0.14", features = ["phone"] }
touch = "0.0.1"
filetime = "0.2"

View file

@ -1,3 +1,5 @@
#![allow(dead_code)]
#[macro_use]
extern crate serde_derive;
@ -39,8 +41,7 @@ fn main() {
// We want to get to /Volumes/ramdisk/rs/debug/completions
let comp_dir = PathBuf::from(outdir)
.ancestors()
.skip(2)
.next()
.nth(2)
.map(|p| p.join("completions"))
.expect("Unable to process completions path");

View file

@ -287,6 +287,9 @@ impl AccessControlModify {
#[derive(Debug, Clone)]
struct AccessControlProfile {
name: String,
// Currently we retrieve this but don't use it. We could depending on how we change
// the acp update routine.
#[allow(dead_code)]
uuid: Uuid,
receiver: Filter<FilterValid>,
targetscope: Filter<FilterValid>,

View file

@ -1159,7 +1159,13 @@ impl QueryServerWriteV1 {
let ml = ModifyList::new_append(
"oauth2_rs_scope_map",
Value::new_oauthscopemap(group_uuid, scopes.into_iter().collect()),
Value::new_oauthscopemap(group_uuid, scopes.into_iter().collect()).ok_or_else(
|| {
OperationError::InvalidAttribute(
"Invalid Oauth Scope Map syntax".to_string(),
)
},
)?,
);
let mdf = match ModifyEvent::from_internal_parts(

View file

@ -95,6 +95,12 @@ pub enum DbCredTypeV1 {
// PwWnVer,
}
// We have to allow this as serde expects &T for the fn sig.
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_false(b: &bool) -> bool {
!b
}
fn dbcred_type_default_pw() -> DbCredTypeV1 {
DbCredTypeV1::Pw
}
@ -134,6 +140,31 @@ pub struct DbValueTaggedStringV1 {
#[derive(Serialize, Deserialize, Debug)]
pub struct DbValueEmailAddressV1 {
pub d: String,
#[serde(skip_serializing_if = "is_false", default)]
pub p: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DbValuePhoneNumberV1 {
pub d: String,
#[serde(skip_serializing_if = "is_false", default)]
pub p: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct DbValueAddressV1 {
#[serde(rename = "f")]
pub formatted: String,
#[serde(rename = "s")]
pub street_address: String,
#[serde(rename = "l")]
pub locality: String,
#[serde(rename = "r")]
pub region: String,
#[serde(rename = "p")]
pub postal_code: String,
#[serde(rename = "c")]
pub country: String,
}
#[derive(Serialize, Deserialize, Debug)]
@ -182,6 +213,10 @@ pub enum DbValueV1 {
DateTime(String),
#[serde(rename = "EM")]
EmailAddress(DbValueEmailAddressV1),
#[serde(rename = "PN")]
PhoneNumber(DbValuePhoneNumberV1),
#[serde(rename = "AD")]
Address(DbValueAddressV1),
#[serde(rename = "UR")]
Url(Url),
#[serde(rename = "OS")]
@ -190,6 +225,10 @@ pub enum DbValueV1 {
OauthScopeMap(DbValueOauthScopeMapV1),
#[serde(rename = "E2")]
PrivateBinary(Vec<u8>),
#[serde(rename = "PB")]
PublicBinary(String, Vec<u8>),
#[serde(rename = "RS")]
RestrictedString(String),
}
#[cfg(test)]

View file

@ -117,7 +117,7 @@ pub trait IdlSqliteTransaction {
spanned!("be::idl_sqlite::get_identry", {
self.get_identry_raw(idl)?
.into_iter()
.map(|ide| ide.into_entry().map(|e| Arc::new(e)))
.map(|ide| ide.into_entry().map(Arc::new))
.collect()
})
}
@ -288,9 +288,10 @@ pub trait IdlSqliteTransaction {
let spn: Option<Value> = match spn_raw {
Some(d) => {
let dbv = serde_cbor::from_slice(d.as_slice()).map_err(serde_cbor_error)?;
let spn = Value::from_db_valuev1(dbv)
.map_err(|_| OperationError::CorruptedIndex("uuid2spn".to_string()))?;
Some(spn)
ValueSet::from_db_valuev1_iter(std::iter::once(dbv))
.map_err(|_| OperationError::CorruptedIndex("uuid2spn".to_string()))
.map(|vs| vs.to_value_single())?
}
None => None,
};

View file

@ -111,20 +111,24 @@ pub fn to_tide_response<T: Serialize>(
})
}
Err(e) => {
let sc = match &e {
let mut res = match &e {
OperationError::NotAuthenticated | OperationError::SessionExpired => {
tide::StatusCode::Unauthorized
// https://datatracker.ietf.org/doc/html/rfc7235#section-4.1
let mut res = tide::Response::new(tide::StatusCode::Unauthorized);
res.insert_header("WWW-Authenticate", "Bearer");
res
}
OperationError::SystemProtectedObject | OperationError::AccessDenied => {
tide::StatusCode::Forbidden
tide::Response::new(tide::StatusCode::Forbidden)
}
OperationError::NoMatchingEntries => {
tide::Response::new(tide::StatusCode::NotFound)
}
OperationError::NoMatchingEntries => tide::StatusCode::NotFound,
OperationError::EmptyRequest | OperationError::SchemaViolation(_) => {
tide::StatusCode::BadRequest
tide::Response::new(tide::StatusCode::BadRequest)
}
_ => tide::StatusCode::InternalServerError,
_ => tide::Response::new(tide::StatusCode::InternalServerError),
};
let mut res = tide::Response::new(sc);
tide::Body::from_json(&e).map(|b| {
res.set_body(b);
res
@ -162,14 +166,9 @@ async fn index_view(_req: tide::Request<AppState>) -> tide::Result {
Ok(res)
}
#[derive(Default)]
struct NoCacheMiddleware;
impl Default for NoCacheMiddleware {
fn default() -> Self {
NoCacheMiddleware {}
}
}
#[async_trait::async_trait]
impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for NoCacheMiddleware {
async fn handle(
@ -184,14 +183,9 @@ impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for NoCacheMi
}
}
#[derive(Default)]
struct CacheableMiddleware;
impl Default for CacheableMiddleware {
fn default() -> Self {
CacheableMiddleware {}
}
}
#[async_trait::async_trait]
impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for CacheableMiddleware {
async fn handle(
@ -205,14 +199,9 @@ impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for Cacheable
}
}
#[derive(Default)]
struct StaticContentMiddleware;
impl Default for StaticContentMiddleware {
fn default() -> Self {
StaticContentMiddleware {}
}
}
#[async_trait::async_trait]
impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for StaticContentMiddleware {
async fn handle(
@ -226,14 +215,9 @@ impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for StaticCon
}
}
#[derive(Default)]
struct StrictResponseMiddleware;
impl Default for StrictResponseMiddleware {
fn default() -> Self {
StrictResponseMiddleware {}
}
}
#[async_trait::async_trait]
impl<State: Clone + Send + Sync + 'static> tide::Middleware<State> for StrictResponseMiddleware {
async fn handle(

View file

@ -170,8 +170,9 @@ pub async fn oauth2_id_delete(req: tide::Request<AppState>) -> tide::Result {
// * Client Identifier A) oauth2_authorise_get
// * User authenticates B) normal kanidm auth flow
// * Authorization Code C) oauth2_authorise_permit_get
// * Authorization Code/
// Access Token D/E) oauth2_token_post
// oauth2_authorise_reject_get
// * Authorization Code / Access Token
// D/E) oauth2_token_post
//
// These functions appear stateless, but the state is managed through encrypted
// tokens transmitted in the responses of this flow. This is because in a HA setup
@ -208,7 +209,7 @@ async fn oauth2_authorise(
let uat = req.get_current_uat();
let (eventid, hvalue) = req.new_eventid();
let mut redir_url = auth_req.redirect_uri.clone();
// let mut redir_url = auth_req.redirect_uri.clone();
let res = req
.state()
@ -227,38 +228,29 @@ async fn oauth2_authorise(
res
})
}
/*
If the request fails due to a missing, invalid, or mismatching
redirection URI, or if the client identifier is missing or invalid,
the authorization server SHOULD inform the resource owner of the
error and MUST NOT automatically redirect the user-agent to the
invalid redirection URI.
*/
Err(Oauth2Error::InvalidClientId) => Ok(tide::Response::new(tide::StatusCode::BadRequest)),
Err(Oauth2Error::InvalidOrigin) => Ok(tide::Response::new(tide::StatusCode::BadRequest)),
Err(Oauth2Error::AuthenticationRequired) => {
// This will trigger our ui to auth and retry.
Ok(tide::Response::new(tide::StatusCode::Unauthorized))
let mut res = tide::Response::new(tide::StatusCode::Unauthorized);
res.insert_header("WWW-Authenticate", "Bearer");
Ok(res)
}
/*
RFC - If the request fails due to a missing, invalid, or mismatching
redirection URI, or if the client identifier is missing or invalid,
the authorization server SHOULD inform the resource owner of the
error and MUST NOT automatically redirect the user-agent to the
invalid redirection URI.
*/
// To further this, it appears that a malicious client configuration can set a phishing
// site as the redirect URL, and then use that to trigger certain types of attacks. Instead
// we do NOT redirect in an error condition, and just render the error ourselves.
Err(e) => {
admin_error!(
"Unable to authorise - Error ID: {} error: {}",
&hvalue,
&e.to_string()
);
redir_url
.query_pairs_mut()
.clear()
.append_pair(
"error_description",
&format!("Unable to authorise - Error ID: {}", hvalue),
)
.append_pair("error", &e.to_string());
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
// Return an error, explaining why it was denied.
let mut res = tide::Response::new(302);
res.insert_header("Location", redir_url.as_str());
Ok(res)
Ok(tide::Response::new(tide::StatusCode::BadRequest))
}
}
.map(|mut res| {
@ -321,7 +313,7 @@ async fn oauth2_authorise_permit(
redirect_uri
.query_pairs_mut()
.clear()
.append_pair("state", &state.to_string())
.append_pair("state", &state)
.append_pair("code", &code);
res.insert_header("Location", redirect_uri.as_str());
// I think the client server needs this
@ -333,6 +325,10 @@ async fn oauth2_authorise_permit(
// that we should NOT redirect to the calling application
// and we need to handle that locally somehow.
// This needs to be better!
//
// Turns out this instinct was correct:
// https://www.proofpoint.com/us/blog/cloud-security/microsoft-and-github-oauth-implementation-vulnerabilities-lead-redirection
// Possible to use this with a malicious client configuration to phish / spam.
tide::Response::new(500)
}
};
@ -449,7 +445,6 @@ pub async fn oauth2_token_post(mut req: tide::Request<AppState>) -> tide::Result
})
}
Err(Oauth2Error::AuthenticationRequired) => {
// This will trigger our ui to auth and retry.
Ok(tide::Response::new(tide::StatusCode::Unauthorized))
}
Err(e) => {

View file

@ -70,9 +70,7 @@ fn setup_backend_vacuum(
config.db_arc_size,
);
let be = Backend::new(cfg, idxmeta, vacuum);
// debug!
be
Backend::new(cfg, idxmeta, vacuum)
}
// TODO #54: We could move most of the be/schema/qs setup and startup
@ -99,7 +97,7 @@ fn setup_qs_idms(
// We generate a SINGLE idms only!
let (idms, idms_delayed) = IdmServer::new(query_server.clone(), config.origin.clone())?;
let (idms, idms_delayed) = IdmServer::new(query_server.clone(), &config.origin)?;
Ok((query_server, idms, idms_delayed))
}

View file

@ -1278,12 +1278,11 @@ impl Entry<EntrySealed, EntryCommitted> {
// Skip anything empty as new VS can't deal with it.
.filter(|(_k, vs)| !vs.is_empty())
.map(|(k, vs)| {
let vv: Result<Option<ValueSet>, ()> =
vs.into_iter().map(Value::from_db_valuev1).collect();
let vv: Result<ValueSet, _> = ValueSet::from_db_valuev1_iter(vs.into_iter());
match vv {
Ok(Some(vv)) => Ok((k, vv)),
_ => {
admin_error!(value = ?k, "from_dbentry failed");
Ok(vv) => Ok((k, vv)),
Err(e) => {
admin_error!(?e, value = ?k, "from_dbentry failed");
Err(())
}
}

View file

@ -94,6 +94,8 @@ pub(crate) struct Account {
pub name: String,
pub displayname: String,
pub uuid: Uuid,
// We want to allow this so that in the future we can populate this into oauth2 tokens
#[allow(dead_code)]
pub groups: Vec<Group>,
pub primary: Option<Credential>,
pub valid_from: Option<OffsetDateTime>,

View file

@ -10,7 +10,7 @@ use crate::idm::server::{IdmServerProxyReadTransaction, IdmServerTransaction};
use crate::prelude::*;
use crate::value::OAUTHSCOPE_RE;
pub use compact_jwt::{JwkKeySet, OidcToken};
use compact_jwt::{JwsSigner, JwsValidator, OidcClaims, OidcSubject};
use compact_jwt::{JwsSigner, OidcClaims, OidcSubject};
use concread::cowcell::*;
use fernet::Fernet;
use hashbrown::HashMap;
@ -172,7 +172,7 @@ pub struct Oauth2RS {
// Our internal exchange encryption material for this rs.
token_fernet: Fernet,
jws_signer: JwsSigner,
jws_validator: JwsValidator,
// jws_validator: JwsValidator,
// Some clients, especially openid ones don't do pkce. SIGH.
// Can we enforce nonce in this case?
enable_pkce: bool,
@ -301,13 +301,13 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
let scope_maps = ent
.get_ava_as_oauthscopemaps("oauth2_rs_scope_map")
.cloned()
.unwrap_or_else(|| BTreeMap::new());
.unwrap_or_else(BTreeMap::new);
trace!("implicit_scopes");
let implicit_scopes = ent
.get_ava_as_oauthscopes("oauth2_rs_implicit_scopes")
.map(|iter| iter.map(str::to_string).collect())
.unwrap_or_else(|| Vec::new());
.unwrap_or_else(Vec::new);
trace!("oauth2_jwt_legacy_crypto_enable");
let jws_signer = if ent.get_ava_single_bool("oauth2_jwt_legacy_crypto_enable").unwrap_or(false) {
@ -334,10 +334,12 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
})?
};
/*
let jws_validator = jws_signer.get_validator().map_err(|e| {
admin_error!(err = ?e, "Unable to load JwsValidator from JwsSigner");
OperationError::CryptographyError
})?;
*/
let enable_pkce = ent
.get_ava_single_bool("oauth2_allow_insecure_client_disable_pkce")
@ -371,7 +373,7 @@ impl<'a> Oauth2ResourceServersWriteTransaction<'a> {
authz_secret,
token_fernet,
jws_signer,
jws_validator,
// jws_validator,
enable_pkce,
iss: self.inner.origin.clone(),
authorization_endpoint,
@ -453,14 +455,12 @@ impl Oauth2ResourceServersReadTransaction {
return Err(Oauth2Error::InvalidRequest);
}
Some(pkce_request.code_challenge.clone())
} else if o2rs.enable_pkce {
security_error!(?o2rs.name, "No PKCE code challenge was provided with client in enforced PKCE mode.");
return Err(Oauth2Error::InvalidRequest);
} else {
if o2rs.enable_pkce {
security_error!(?o2rs.name, "No PKCE code challenge was provided with client in enforced PKCE mode.");
return Err(Oauth2Error::InvalidRequest);
} else {
security_info!(?o2rs.name, "Insecure client configuration - pkce is not enforced.");
None
}
security_info!(?o2rs.name, "Insecure client configuration - pkce is not enforced.");
None
};
// TODO: https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters
@ -766,11 +766,11 @@ impl Oauth2ResourceServersReadTransaction {
);
return Err(Oauth2Error::InvalidRequest);
}
} else {
if o2rs.enable_pkce {
security_info!("PKCE code verification failed - no code challenge present in PKCE enforced mode");
return Err(Oauth2Error::InvalidRequest);
}
} else if o2rs.enable_pkce {
security_info!(
"PKCE code verification failed - no code challenge present in PKCE enforced mode"
);
return Err(Oauth2Error::InvalidRequest);
}
// Validate the redirect_uri is the same as the original.
@ -999,7 +999,7 @@ impl Oauth2ResourceServersReadTransaction {
let token: Oauth2TokenType = o2rs
.token_fernet
.decrypt(&client_authz)
.decrypt(client_authz)
.map_err(|_| {
admin_error!("Failed to decrypt token introspection request");
Oauth2Error::InvalidRequest
@ -1056,8 +1056,8 @@ impl Oauth2ResourceServersReadTransaction {
// Map from displayname
name: Some(account.displayname.clone()),
// Map from spn
preferred_username: Some(account.spn.clone()),
scopes: at.scopes.clone(),
preferred_username: Some(account.spn),
scopes: at.scopes,
..Default::default()
},
claims: Default::default(),
@ -1282,11 +1282,15 @@ mod tests {
"oauth2_rs_origin",
Value::new_url_s("https://demo.example.com").unwrap()
),
("oauth2_rs_implicit_scopes", Value::new_oauthscope("openid")),
(
"oauth2_rs_implicit_scopes",
Value::new_oauthscope("openid").expect("invalid oauthscope")
),
// System admins
(
"oauth2_rs_scope_map",
Value::new_oauthscopemap(UUID_SYSTEM_ADMINS, btreeset!["read".to_string()])
.expect("invalid oauthscope")
),
(
"oauth2_allow_insecure_client_disable_pkce",

View file

@ -145,7 +145,7 @@ impl IdmServer {
// TODO: Make number of authsessions configurable!!!
pub fn new(
qs: QueryServer,
origin: String,
origin: &str,
// ct: Duration,
) -> Result<(IdmServer, IdmServerDelayed), OperationError> {
// This is calculated back from:
@ -171,7 +171,7 @@ impl IdmServer {
};
// Check that it gels with our origin.
let origin_url = Url::parse(origin.as_str())
let origin_url = Url::parse(origin)
.map_err(|_e| {
admin_error!("Unable to parse origin URL - refusing to start. You must correct the value for origin. {:?}", origin);
OperationError::InvalidState

View file

@ -4,9 +4,11 @@
#![recursion_limit = "512"]
#![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
// #![deny(clippy::panic)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
@ -45,8 +47,8 @@ pub mod identity;
mod interval;
pub(crate) mod ldap;
mod modify;
pub mod value;
pub mod valueset;
pub(crate) mod value;
pub(crate) mod valueset;
#[macro_use]
mod plugins;
mod access;

View file

@ -188,7 +188,7 @@ macro_rules! run_idm_test_inner {
let test_server = setup_test!();
let (test_idm_server, mut idms_delayed) =
IdmServer::new(test_server.clone(), "https://idm.example.com".to_string())
IdmServer::new(test_server.clone(), "https://idm.example.com")
.expect("Failed to setup idms");
$test_fn(&test_server, &test_idm_server, &mut idms_delayed);

View file

@ -60,6 +60,8 @@ impl Modify {
#[derive(Debug, Default)]
pub struct ModifyList<VALID> {
// This is never read, it's just used for state machine enforcement.
#[allow(dead_code)]
valid: VALID,
// The order of this list matters. Each change must be done in order.
mods: Vec<Modify>,

View file

@ -18,13 +18,13 @@ pub struct AttrUnique;
fn get_cand_attr_set<VALID, STATE>(
cand: &[Entry<VALID, STATE>],
attr: &str,
) -> Result<BTreeMap<PartialValue, PartialValue>, OperationError> {
let mut cand_attr: BTreeMap<PartialValue, PartialValue> = BTreeMap::new();
) -> Result<BTreeMap<PartialValue, Uuid>, OperationError> {
let mut cand_attr: BTreeMap<PartialValue, Uuid> = BTreeMap::new();
cand.iter()
.try_for_each(|e| {
let uuid = match e.get_ava_single("uuid") {
Some(v) => v.to_partialvalue(),
let uuid = match e.get_ava_single_uuid("uuid") {
Some(v) => *v,
None => {
return Err(OperationError::InvalidEntryState);
}
@ -33,8 +33,8 @@ fn get_cand_attr_set<VALID, STATE>(
//for each value in the ava.
e.get_ava_set(attr)
.map(|vs| {
vs.to_partialvalue_iter().try_for_each(|v| {
match cand_attr.insert(v, uuid.clone()) {
vs.to_partialvalue_iter()
.try_for_each(|v| match cand_attr.insert(v, uuid) {
None => Ok(()),
Some(vr) => {
admin_error!(
@ -47,8 +47,7 @@ fn get_cand_attr_set<VALID, STATE>(
"ava already exists".to_string(),
)))
}
}
})
})
})
.unwrap_or(Ok(()))
})
@ -86,7 +85,10 @@ fn enforce_unique<STATE>(
.map(|(v, uuid)| {
// and[ attr eq k, andnot [ uuid eq v ]]
// Basically this says where name but also not self.
f_and(vec![FC::Eq(attr, v), f_andnot(FC::Eq("uuid", uuid))])
f_and(vec![
FC::Eq(attr, v),
f_andnot(FC::Eq("uuid", PartialValue::new_uuid(uuid))),
])
})
.collect()
));

View file

@ -1,6 +1,7 @@
use crate::plugins::Plugin;
use hashbrown::HashSet;
use std::collections::BTreeSet;
use std::iter::once;
use crate::event::{CreateEvent, ModifyEvent};
use crate::modify::Modify;
@ -57,9 +58,9 @@ impl Plugin for Base {
match entry.get_ava_set("uuid").map(|s| s.len()) {
None => {
// Generate
let ava_uuid = btreeset![Value::new_uuid(Uuid::new_v4())];
let ava_uuid = Value::new_uuid(Uuid::new_v4());
trace!("Setting temporary UUID {:?} to entry", ava_uuid);
entry.set_ava("uuid", ava_uuid);
entry.set_ava("uuid", once(ava_uuid));
}
Some(1) => {
// Do nothing

View file

@ -10,6 +10,7 @@ use crate::event::{CreateEvent, ModifyEvent};
use crate::prelude::*;
use bundy::hs512::HS512;
use kanidm_proto::v1::OperationError;
use std::iter::once;
use tracing::trace;
lazy_static! {
@ -35,12 +36,12 @@ impl Plugin for Domain {
{
// We always set this, because the DB uuid is authorative.
let u = Value::new_uuid(qs.get_domain_uuid());
e.set_ava("domain_uuid", btreeset![u]);
e.set_ava("domain_uuid", once(u));
trace!("plugin_domain: Applying uuid transform");
// We only apply this if one isn't provided.
if !e.attribute_pres("domain_name") {
let n = Value::new_iname("example.com");
e.set_ava("domain_name", btreeset![n]);
e.set_ava("domain_name", once(n));
trace!("plugin_domain: Applying domain_name transform");
}
if !e.attribute_pres("domain_token_key") {
@ -50,7 +51,7 @@ impl Plugin for Domain {
admin_error!(err = ?e, "Failed to generate domain_token_key");
OperationError::InvalidState
})?;
e.set_ava("domain_token_key", btreeset![k]);
e.set_ava("domain_token_key", once(k));
trace!("plugin_domain: Applying domain_token_key transform");
}
trace!(?e);
@ -77,7 +78,7 @@ impl Plugin for Domain {
admin_error!(err = ?e, "Failed to generate domain_token_key");
OperationError::InvalidState
})?;
e.set_ava("domain_token_key", btreeset![k]);
e.set_ava("domain_token_key", once(k));
trace!("plugin_domain: Applying domain_token_key transform");
}
trace!(?e);

View file

@ -5,6 +5,7 @@ use crate::event::{CreateEvent, ModifyEvent};
use crate::plugins::Plugin;
use crate::prelude::*;
use crate::utils::uuid_to_gid_u32;
use std::iter::once;
/// Systemd dynamic units allocate between 6118465519, most distros allocate
/// system uids from 0 - 1000, and many others give user ids between 1000 to
@ -45,7 +46,7 @@ fn apply_gidnumber<T: Clone>(e: &mut Entry<EntryInvalid, T>) -> Result<(), Opera
let gid_v = Value::new_uint32(gid);
admin_info!("Generated {} for {:?}", gid, u_ref);
e.set_ava("gidnumber", btreeset![gid_v]);
e.set_ava("gidnumber", once(gid_v));
Ok(())
} else if let Some(gid) = e.get_ava_single_uint32("gidnumber") {
// If they provided us with a gid number, ensure it's in a safe range.

View file

@ -99,7 +99,10 @@ mod tests {
"oauth2_rs_origin",
Value::new_url_s("https://demo.example.com").unwrap()
),
("oauth2_rs_implicit_scopes", Value::new_oauthscope("read"))
(
"oauth2_rs_implicit_scopes",
Value::new_oauthscope("read").expect("Invalid scope")
)
);
let create = vec![e];
@ -134,7 +137,10 @@ mod tests {
"oauth2_rs_origin",
Value::new_url_s("https://demo.example.com").unwrap()
),
("oauth2_rs_implicit_scopes", Value::new_oauthscope("read")),
(
"oauth2_rs_implicit_scopes",
Value::new_oauthscope("read").expect("Invalid scope")
),
("oauth2_rs_basic_secret", Value::new_utf8s("12345")),
("oauth2_rs_token_key", Value::new_secret_str("12345"))
);

View file

@ -5,6 +5,7 @@ use crate::plugins::Plugin;
use crate::prelude::*;
use kanidm_proto::v1::PluginError;
use std::convert::TryFrom;
use std::iter::once;
pub struct PasswordImport {}
@ -49,7 +50,7 @@ impl Plugin for PasswordImport {
// just set it then!
let c = Credential::new_from_password(pw);
e.set_ava("primary_credential",
btreeset![Value::new_credential("primary", c)]);
once(Value::new_credential("primary", c)));
Ok(())
}
}
@ -94,7 +95,7 @@ impl Plugin for PasswordImport {
let c = c.update_password(pw);
e.set_ava(
"primary_credential",
btreeset![Value::new_credential("primary", c)],
once(Value::new_credential("primary", c)),
);
Ok(())
}
@ -103,7 +104,7 @@ impl Plugin for PasswordImport {
let c = Credential::new_from_password(pw);
e.set_ava(
"primary_credential",
btreeset![Value::new_credential("primary", c)],
once(Value::new_credential("primary", c)),
);
Ok(())
}

View file

@ -715,13 +715,17 @@ mod tests {
"oauth2_rs_origin",
Value::new_url_s("https://demo.example.com").unwrap()
),
("oauth2_rs_implicit_scopes", Value::new_oauthscope("test")),
(
"oauth2_rs_implicit_scopes",
Value::new_oauthscope("test").expect("Invalid scope")
),
(
"oauth2_rs_scope_map",
Value::new_oauthscopemap(
Uuid::parse_str("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid"),
btreeset!["read".to_string()]
)
.expect("Invalid scope")
)
);

View file

@ -9,6 +9,7 @@ use crate::event::{CreateEvent, ModifyEvent};
use crate::value::PartialValue;
// use crate::value::{PartialValue, Value};
use kanidm_proto::v1::{ConsistencyError, OperationError};
use std::iter::once;
use std::sync::Arc;
pub struct Spn {}
@ -70,7 +71,7 @@ impl Plugin for Spn {
e
})?;
trace!("plugin_spn: set spn to {:?}", spn);
e.set_ava("spn", btreeset![spn]);
e.set_ava("spn", once(spn));
}
}
Ok(())
@ -116,7 +117,7 @@ impl Plugin for Spn {
e
})?;
trace!("plugin_spn: set spn to {:?}", spn);
e.set_ava("spn", btreeset![spn]);
e.set_ava("spn", once(spn));
}
}
Ok(())

View file

@ -23,11 +23,8 @@ use kanidm_proto::v1::{ConsistencyError, OperationError, SchemaError};
use tracing::trace;
use hashbrown::{HashMap, HashSet};
use std::borrow::Borrow;
// use std::collections::BTreeSet;
use uuid::Uuid;
// use concread::cowcell::asynch::*;
use concread::cowcell::*;
// representations of schema that confines object types, classes
@ -203,25 +200,50 @@ impl SchemaAttribute {
if r {
Ok(())
} else {
trace!(?a, ?self, ?v, "validate_pv InvalidAttributeSyntax");
trace!(
?a,
?self,
?v,
"validate_partialvalue InvalidAttributeSyntax"
);
Err(SchemaError::InvalidAttributeSyntax(a.to_string()))
}
}
pub fn validate_value(&self, a: &str, v: &Value) -> Result<(), SchemaError> {
let r = v.validate();
if cfg!(test) {
assert!(r);
}
let r = v.validate()
&& match self.syntax {
SyntaxType::Boolean => v.is_bool(),
SyntaxType::SYNTAX_ID => v.is_syntax(),
SyntaxType::INDEX_ID => v.is_index(),
SyntaxType::Uuid => v.is_uuid(),
SyntaxType::REFERENCE_UUID => v.is_refer(),
SyntaxType::Utf8StringInsensitive => v.is_iutf8(),
SyntaxType::Utf8StringIname => v.is_iname(),
SyntaxType::UTF8STRING => v.is_utf8(),
SyntaxType::JSON_FILTER => v.is_json_filter(),
SyntaxType::Credential => v.is_credential(),
SyntaxType::SecretUtf8String => v.is_secret_string(),
SyntaxType::SshKey => v.is_sshkey(),
SyntaxType::SecurityPrincipalName => v.is_spn(),
SyntaxType::UINT32 => v.is_uint32(),
SyntaxType::Cid => v.is_cid(),
SyntaxType::NsUniqueId => v.is_nsuniqueid(),
SyntaxType::DateTime => v.is_datetime(),
SyntaxType::EmailAddress => v.is_email_address(),
SyntaxType::Url => v.is_url(),
SyntaxType::OauthScope => v.is_oauthscope(),
SyntaxType::OauthScopeMap => v.is_oauthscopemap() || v.is_refer(),
SyntaxType::PrivateBinary => v.is_privatebinary(),
};
if r {
let pv: &PartialValue = v.borrow();
self.validate_partialvalue(a, pv)
Ok(())
} else {
trace!(
?a,
?self,
?v,
"value validation failure - InvalidAttributeSyntax"
"validate_value failure - InvalidAttributeSyntax"
);
Err(SchemaError::InvalidAttributeSyntax(a.to_string()))
}
@ -260,7 +282,7 @@ impl SchemaAttribute {
SyntaxType::OauthScopeMap => ava.is_oauthscopemap(),
SyntaxType::PrivateBinary => ava.is_privatebinary(),
};
if valid {
if valid && ava.validate() {
Ok(())
} else {
admin_error!(?a, "validate_ava - InvalidAttributeSyntax");

View file

@ -463,7 +463,7 @@ pub trait QueryServerTransaction<'a> {
// all subsequent filter tests because it ... well, doesn't exist.
let un = self
.name_to_uuid( value)
.unwrap_or_else(|_| UUID_DOES_NOT_EXIST);
.unwrap_or(UUID_DOES_NOT_EXIST);
Some(Value::new_uuid(un))
})
// I think this is unreachable due to how the .or_else works.
@ -475,7 +475,7 @@ pub trait QueryServerTransaction<'a> {
.or_else(|| {
let un = self
.name_to_uuid( value)
.unwrap_or_else(|_| UUID_DOES_NOT_EXIST);
.unwrap_or(UUID_DOES_NOT_EXIST);
Some(Value::new_refer(un))
})
// I think this is unreachable due to how the .or_else works.
@ -490,13 +490,16 @@ pub trait QueryServerTransaction<'a> {
SyntaxType::UINT32 => Value::new_uint32_str(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid uint32 syntax".to_string())),
SyntaxType::Cid => Err(OperationError::InvalidAttribute("CIDs are generated and not able to be set.".to_string())),
SyntaxType::NsUniqueId => Ok(Value::new_nsuniqueid_s(value)),
SyntaxType::NsUniqueId => Value::new_nsuniqueid_s(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid NsUniqueId syntax".to_string())),
SyntaxType::DateTime => Value::new_datetime_s(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid DateTime (rfc3339) syntax".to_string())),
SyntaxType::EmailAddress => Ok(Value::new_email_address_s(value)),
SyntaxType::EmailAddress => Value::new_email_address_s(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid Email Address syntax".to_string())),
SyntaxType::Url => Value::new_url_s(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid Url (whatwg/url) syntax".to_string())),
SyntaxType::OauthScope => Ok(Value::new_oauthscope(value)),
SyntaxType::OauthScope => Value::new_oauthscope(value)
.ok_or_else(|| OperationError::InvalidAttribute("Invalid Oauth Scope syntax".to_string())),
SyntaxType::OauthScopeMap => Err(OperationError::InvalidAttribute("Oauth Scope Maps can not be supplied through modification - please use the IDM api".to_string())),
SyntaxType::PrivateBinary => Err(OperationError::InvalidAttribute("Private Binary Values can not be supplied through modification".to_string())),
}
@ -535,9 +538,7 @@ pub trait QueryServerTransaction<'a> {
// if the value is NOT found, we map to "does not exist" to allow
// the value to continue being evaluated, which of course, will fail
// all subsequent filter tests because it ... well, doesn't exist.
let un = self
.name_to_uuid(value)
.unwrap_or_else(|_| UUID_DOES_NOT_EXIST);
let un = self.name_to_uuid(value).unwrap_or(UUID_DOES_NOT_EXIST);
Some(PartialValue::new_uuid(un))
})
// I think this is unreachable due to how the .or_else works.
@ -561,9 +562,7 @@ pub trait QueryServerTransaction<'a> {
// See comments above.
PartialValue::new_refer_s(value)
.or_else(|| {
let un = self
.name_to_uuid(value)
.unwrap_or_else(|_| UUID_DOES_NOT_EXIST);
let un = self.name_to_uuid(value).unwrap_or(UUID_DOES_NOT_EXIST);
Some(PartialValue::new_refer(un))
})
// I think this is unreachable due to how the .or_else works.
@ -578,9 +577,7 @@ pub trait QueryServerTransaction<'a> {
// See comments above.
PartialValue::new_oauthscopemap_s(value)
.or_else(|| {
let un = self
.name_to_uuid(value)
.unwrap_or_else(|_| UUID_DOES_NOT_EXIST);
let un = self.name_to_uuid(value).unwrap_or(UUID_DOES_NOT_EXIST);
Some(PartialValue::new_oauthscopemap(un))
})
// I think this is unreachable due to how the .or_else works.
@ -854,11 +851,6 @@ impl<'a> QueryServerTransaction<'a> for QueryServerWriteTransaction<'a> {
}
}
#[derive(Clone, Debug)]
struct QueryServerMeta {
pub max_cid: Cid,
}
impl QueryServer {
pub fn new(be: Backend, schema: Schema) -> Self {
let (s_uuid, d_uuid) = {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -52,6 +52,7 @@ struct DbScanListIndex {
commonopts: CommonOpt,
}
/*
#[derive(Debug, StructOpt)]
struct DbScanGetIndex {
/// The name of the index to list
@ -61,6 +62,7 @@ struct DbScanGetIndex {
#[structopt(flatten)]
commonopts: CommonOpt,
}
*/
#[derive(Debug, StructOpt)]
struct DbScanGetId2Entry {

View file

@ -54,7 +54,7 @@ struct Record {
conn: i32,
etime: Duration,
ids: Vec<Uuid>,
nentries: u32,
_nentries: u32,
rtime: Duration,
op_type: RawOpType,
}
@ -176,7 +176,7 @@ impl TryFrom<RawRecord> for Record {
conn,
etime,
ids,
nentries,
_nentries: nentries,
rtime,
op_type,
})
@ -244,7 +244,6 @@ pub fn doit(input: &Path, output: &Path) {
// Before we can precreate, we need an idea to what each
// item is. Lets get all ids and see which ones ever did a bind.
// This means they are probably an account.
let accounts: HashSet<Uuid> = other
.iter()
.filter(|rec| rec.op_type == RawOpType::Bind)
@ -292,6 +291,7 @@ pub fn doit(input: &Path, output: &Path) {
let mut exists = precreate.clone();
// Consume all the remaining records into connection structures.
other.iter().for_each(|rec| {
debug!("{:?}", rec);
if let Some(c) = connections.get_mut(&rec.conn) {