mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
106 auth concurrency (#643)
This commit is contained in:
parent
f252d91e13
commit
fa610c6d88
84
Cargo.lock
generated
84
Cargo.lock
generated
|
@ -62,7 +62,7 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.4",
|
||||
"getrandom 0.2.5",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -87,9 +87,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.54"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a99269dff3bc004caa411f38845c20303f1e393ca2bd6581576fa3a7f59577d"
|
||||
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
|
@ -146,9 +146,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.0.2"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6"
|
||||
checksum = "c026b7e44f1316b567ee750fea85103f87fcb80792b860e979f221259796ca0a"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
|
@ -646,7 +646,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "concread"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/kanidm/concread.git#7ab828262e05aada2330ae325d95e75f97b8dc4e"
|
||||
source = "git+https://github.com/kanidm/concread.git#5681626deb73a0f2efd77effdd8cab2ebecbaca3"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"crossbeam",
|
||||
|
@ -1191,7 +1191,7 @@ checksum = "93804560e638370a8be6d59ce71ed803e55e230abdbf42598e666b41adda9b1f"
|
|||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"byteorder",
|
||||
"getrandom 0.2.4",
|
||||
"getrandom 0.2.5",
|
||||
"openssl",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -1381,9 +1381,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
|
@ -1750,9 +1750,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||
|
||||
[[package]]
|
||||
name = "idlset"
|
||||
version = "0.2.1"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "579210ffb32d97e1dc12f65d35c1da76e4bad18fa5a4280443544cefd3413b9f"
|
||||
checksum = "d1612d42a5e18df31a30916d2005ff41981c1d606b9180ef9bd1dbd919fa4eac"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
@ -1903,10 +1903,9 @@ dependencies = [
|
|||
"jemallocator",
|
||||
"kanidm_proto",
|
||||
"lazy_static",
|
||||
"ldap3_server",
|
||||
"ldap3_proto",
|
||||
"libc",
|
||||
"libsqlite3-sys",
|
||||
"num_cpus",
|
||||
"num_enum",
|
||||
"openssl",
|
||||
"profiles",
|
||||
|
@ -2075,6 +2074,17 @@ dependencies = [
|
|||
"nom 2.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ldap3_proto"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38792e250a5442c1af9a13c3e979796e96b494862d751a4172300b6f668d449c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"lber",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ldap3_server"
|
||||
version = "0.1.11"
|
||||
|
@ -2101,9 +2111,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.118"
|
||||
version = "0.2.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94"
|
||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||
|
||||
[[package]]
|
||||
name = "libnss"
|
||||
|
@ -2173,9 +2183,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "274353858935c992b13c0ca408752e2121da852d07dec7ce5f108c77dfa14d1f"
|
||||
checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
@ -2206,9 +2216,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
|||
|
||||
[[package]]
|
||||
name = "mathru"
|
||||
version = "0.11.1"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eb52272ccab6f72f5b857472cc93cffe203e15e6e83eac270ccefeb9c1ec54e"
|
||||
checksum = "708d5b0c8cb68b9ae6e6c9a112a97a6e4c1ed597271963473470604ff22ab595"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
@ -2399,7 +2409,7 @@ checksum = "80e47cfc4c0a1a519d9a025ebfbac3a2439d1b5cdf397d72dcb79b11d9920dab"
|
|||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"getrandom 0.2.4",
|
||||
"getrandom 0.2.5",
|
||||
"http",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
|
@ -2412,9 +2422,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "oncemutex"
|
||||
|
@ -2718,9 +2728,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dada8c9981fcf32929c3c0f0cd796a9284aca335565227ed88c83babb1d43dc"
|
||||
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"toml",
|
||||
|
@ -2906,7 +2916,7 @@ version = "0.6.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.4",
|
||||
"getrandom 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2945,9 +2955,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
@ -2958,7 +2968,7 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom 0.2.4",
|
||||
"getrandom 0.2.5",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
|
@ -3106,7 +3116,7 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver 1.0.5",
|
||||
"semver 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3175,7 +3185,7 @@ dependencies = [
|
|||
"futures-util",
|
||||
"kanidm",
|
||||
"kanidm_proto",
|
||||
"ldap3_server",
|
||||
"ldap3_proto",
|
||||
"libc",
|
||||
"openssl",
|
||||
"profiles",
|
||||
|
@ -3223,9 +3233,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
|
||||
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
|
@ -3421,9 +3431,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smartstring"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31aa6a31c0c2b21327ce875f7e8952322acfcfd0c27569a6e18a647281352c9b"
|
||||
checksum = "e714dff2b33f2321fdcd475b71cec79781a692d846f37f415fb395a1d2bcd48e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"static_assertions",
|
||||
|
@ -4010,7 +4020,7 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.4",
|
||||
"getrandom 0.2.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -4400,9 +4410,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.5.2"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006"
|
||||
checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
|
|
@ -62,19 +62,17 @@ time = { version = "0.2", features = ["serde", "std"] }
|
|||
hashbrown = { version = "0.11", features = ["serde", "inline-more", "ahash"] }
|
||||
concread = "^0.3"
|
||||
smolset = "1.3"
|
||||
# concread = { version = "^0.2.9", features = ["simd_support"] }
|
||||
|
||||
sshkeys = "^0.3.1"
|
||||
|
||||
# rpassword = "5.0"
|
||||
num_cpus = "1.10"
|
||||
|
||||
zxcvbn = "2.0"
|
||||
base64 = "0.13"
|
||||
|
||||
idlset = { version = "^0.2" }
|
||||
|
||||
ldap3_server = "0.1"
|
||||
# Needs to be ldap3_proto!
|
||||
ldap3_proto = "0.2.2"
|
||||
|
||||
webauthn-rs = "0.3"
|
||||
|
||||
libc = "0.2"
|
||||
|
@ -91,7 +89,6 @@ num_enum = "0.5"
|
|||
|
||||
|
||||
[features]
|
||||
# simd_support = [ "concread/simd_support" ]
|
||||
# default = [ "libsqlite3-sys/bundled", "openssl/vendored" ]
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -9,8 +9,7 @@ RUN zypper ar obs://devel:languages:rust devel:languages:rust && \
|
|||
zypper install -y \
|
||||
cargo \
|
||||
rust \
|
||||
gcc \
|
||||
clang lld \
|
||||
gcc clang lld \
|
||||
make automake autoconf \
|
||||
libopenssl-devel pam-devel \
|
||||
sqlite3-devel \
|
||||
|
|
|
@ -26,7 +26,7 @@ tokio = { version = "1", features = ["full"] }
|
|||
tokio-util = { version = "0.6", features = ["codec"] }
|
||||
tokio-openssl = "0.6"
|
||||
openssl = "0.10"
|
||||
ldap3_server = "0.1"
|
||||
ldap3_proto = "0.2.2"
|
||||
|
||||
bundy = "^0.1.1"
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use tokio_openssl::SslStream;
|
|||
|
||||
use futures_util::sink::SinkExt;
|
||||
use futures_util::stream::StreamExt;
|
||||
use ldap3_server::{proto::LdapMsg, LdapCodec};
|
||||
use ldap3_proto::{proto::LdapMsg, LdapCodec};
|
||||
use std::marker::Unpin;
|
||||
use std::net;
|
||||
use std::str::FromStr;
|
||||
|
|
|
@ -36,7 +36,7 @@ use std::fs;
|
|||
use std::path::{Path, PathBuf};
|
||||
use uuid::Uuid;
|
||||
|
||||
use ldap3_server::simple::*;
|
||||
use ldap3_proto::simple::*;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// ===========================================================
|
||||
|
|
|
@ -44,7 +44,8 @@ use crate::be::idl_arc_sqlite::{
|
|||
// Re-export this
|
||||
pub use crate::be::idl_sqlite::FsType;
|
||||
|
||||
const FILTER_SEARCH_TEST_THRESHOLD: usize = 2;
|
||||
// Currently disabled due to improvements in idlset for intersection handling.
|
||||
const FILTER_SEARCH_TEST_THRESHOLD: usize = 0;
|
||||
const FILTER_EXISTS_TEST_THRESHOLD: usize = 0;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -135,7 +135,12 @@ impl Configuration {
|
|||
let mut c = Configuration {
|
||||
address: String::from("127.0.0.1:8080"),
|
||||
ldapaddress: None,
|
||||
threads: num_cpus::get(),
|
||||
threads: std::thread::available_parallelism()
|
||||
.map(|t| t.get())
|
||||
.unwrap_or_else(|_e| {
|
||||
eprintln!("WARNING: Unable to read number of available CPUs, defaulting to 1");
|
||||
1
|
||||
}),
|
||||
db_path: String::from(""),
|
||||
db_fs_type: None,
|
||||
db_arc_size: None,
|
||||
|
|
|
@ -755,22 +755,22 @@ impl Credential {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn softlock_policy(&self) -> Option<CredSoftLockPolicy> {
|
||||
pub(crate) fn softlock_policy(&self) -> CredSoftLockPolicy {
|
||||
match &self.type_ {
|
||||
CredentialType::Password(_pw) | CredentialType::GeneratedPassword(_pw) => {
|
||||
Some(CredSoftLockPolicy::Password)
|
||||
CredSoftLockPolicy::Password
|
||||
}
|
||||
CredentialType::PasswordMfa(_pw, totp, wan, _) => {
|
||||
// For backup code, use totp/wan policy (whatever is available)
|
||||
if let Some(r_totp) = totp {
|
||||
Some(CredSoftLockPolicy::Totp(r_totp.step))
|
||||
CredSoftLockPolicy::Totp(r_totp.step)
|
||||
} else if !wan.is_empty() {
|
||||
Some(CredSoftLockPolicy::Webauthn)
|
||||
CredSoftLockPolicy::Webauthn
|
||||
} else {
|
||||
None
|
||||
CredSoftLockPolicy::Password
|
||||
}
|
||||
}
|
||||
CredentialType::Webauthn(_wan) => Some(CredSoftLockPolicy::Webauthn),
|
||||
CredentialType::Webauthn(_wan) => CredSoftLockPolicy::Webauthn,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ pub enum CredSoftLockPolicy {
|
|||
Password,
|
||||
Totp(u64),
|
||||
Webauthn,
|
||||
Unrestricted,
|
||||
}
|
||||
|
||||
impl CredSoftLockPolicy {
|
||||
|
@ -111,6 +112,10 @@ impl CredSoftLockPolicy {
|
|||
ct + Duration::from_secs(1),
|
||||
)
|
||||
}
|
||||
CredSoftLockPolicy::Unrestricted => {
|
||||
// No action needed
|
||||
LockState::Init
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ use crate::be::dbentry::{DbEntry, DbEntryV1, DbEntryVers};
|
|||
use crate::be::{IdxKey, IdxSlope};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use ldap3_server::simple::{LdapPartialAttribute, LdapSearchResultEntry};
|
||||
use ldap3_proto::simple::{LdapPartialAttribute, LdapSearchResultEntry};
|
||||
use smartstring::alias::String as AttrString;
|
||||
use std::collections::BTreeMap as Map;
|
||||
pub use std::collections::BTreeSet as Set;
|
||||
|
|
|
@ -31,7 +31,7 @@ use kanidm_proto::v1::{
|
|||
SearchRequest, SearchResponse, UserAuthToken, WhoamiResponse,
|
||||
};
|
||||
|
||||
use ldap3_server::simple::LdapFilter;
|
||||
use ldap3_proto::simple::LdapFilter;
|
||||
use std::collections::BTreeSet;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::value::{IndexType, PartialValue};
|
|||
use concread::arcache::ARCacheReadTxn;
|
||||
use kanidm_proto::v1::Filter as ProtoFilter;
|
||||
use kanidm_proto::v1::{OperationError, SchemaError};
|
||||
use ldap3_server::proto::{LdapFilter, LdapSubstringFilter};
|
||||
use ldap3_proto::proto::{LdapFilter, LdapSubstringFilter};
|
||||
// use smartstring::alias::String as AttrString;
|
||||
use serde::Deserialize;
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
|
@ -1332,7 +1332,7 @@ mod tests {
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use kanidm_proto::v1::Filter as ProtoFilter;
|
||||
use ldap3_server::simple::LdapFilter;
|
||||
use ldap3_proto::simple::LdapFilter;
|
||||
|
||||
#[test]
|
||||
fn test_filter_simple() {
|
||||
|
|
|
@ -238,17 +238,27 @@ impl Account {
|
|||
inputs
|
||||
}
|
||||
|
||||
pub fn primary_cred_uuid(&self) -> Uuid {
|
||||
match &self.primary {
|
||||
Some(cred) => cred.uuid,
|
||||
None => UUID_ANONYMOUS,
|
||||
pub fn primary_cred_uuid(&self) -> Option<Uuid> {
|
||||
self.primary.as_ref().map(|cred| cred.uuid).or_else(|| {
|
||||
if self.is_anonymous() {
|
||||
Some(UUID_ANONYMOUS)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn primary_cred_softlock_policy(&self) -> Option<CredSoftLockPolicy> {
|
||||
pub fn primary_cred_uuid_and_policy(&self) -> Option<(Uuid, CredSoftLockPolicy)> {
|
||||
self.primary
|
||||
.as_ref()
|
||||
.and_then(|cred| cred.softlock_policy())
|
||||
.map(|cred| (cred.uuid, cred.softlock_policy()))
|
||||
.or_else(|| {
|
||||
if self.is_anonymous() {
|
||||
Some((UUID_ANONYMOUS, CredSoftLockPolicy::Unrestricted))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
|
|
|
@ -66,6 +66,7 @@ use concread::{
|
|||
use rand::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tokio::sync::Mutex;
|
||||
use url::Url;
|
||||
|
||||
use webauthn_rs::Webauthn;
|
||||
|
@ -75,16 +76,17 @@ use super::event::{GenerateBackupCodeEvent, ReadBackupCodeEvent, RemoveBackupCod
|
|||
|
||||
use tracing::trace;
|
||||
|
||||
type AuthSessionMutex = Arc<Mutex<AuthSession>>;
|
||||
type CredSoftLockMutex = Arc<Mutex<CredSoftLock>>;
|
||||
|
||||
pub struct IdmServer {
|
||||
// There is a good reason to keep this single thread - it
|
||||
// means that limits to sessions can be easily applied and checked to
|
||||
// variaous accounts, and we have a good idea of how to structure the
|
||||
// in memory caches related to locking.
|
||||
session_ticket: Semaphore,
|
||||
sessions: BptreeMap<Uuid, AuthSession>,
|
||||
// Do we need a softlock ticket?
|
||||
softlock_ticket: Semaphore,
|
||||
softlocks: HashMap<Uuid, CredSoftLock>,
|
||||
sessions: BptreeMap<Uuid, AuthSessionMutex>,
|
||||
softlocks: HashMap<Uuid, CredSoftLockMutex>,
|
||||
/// A set of in progress MFA registrations
|
||||
mfareg_sessions: BptreeMap<Uuid, MfaRegSession>,
|
||||
/// Reference to the query server.
|
||||
|
@ -102,10 +104,9 @@ pub struct IdmServer {
|
|||
/// Contains methods that require writes, but in the context of writing to the idm in memory structures (maybe the query server too). This is things like authentication.
|
||||
pub struct IdmServerAuthTransaction<'a> {
|
||||
session_ticket: &'a Semaphore,
|
||||
sessions: &'a BptreeMap<Uuid, AuthSession>,
|
||||
sessions: &'a BptreeMap<Uuid, AuthSessionMutex>,
|
||||
softlocks: &'a HashMap<Uuid, CredSoftLockMutex>,
|
||||
|
||||
softlock_ticket: &'a Semaphore,
|
||||
softlocks: &'a HashMap<Uuid, CredSoftLock>,
|
||||
pub qs_read: QueryServerReadTransaction<'a>,
|
||||
/// Thread/Server ID
|
||||
sid: Sid,
|
||||
|
@ -220,7 +221,6 @@ impl IdmServer {
|
|||
IdmServer {
|
||||
session_ticket: Semaphore::new(1),
|
||||
sessions: BptreeMap::new(),
|
||||
softlock_ticket: Semaphore::new(1),
|
||||
softlocks: HashMap::new(),
|
||||
mfareg_sessions: BptreeMap::new(),
|
||||
qs,
|
||||
|
@ -245,15 +245,11 @@ impl IdmServer {
|
|||
let mut rng = StdRng::from_entropy();
|
||||
rng.fill(&mut sid);
|
||||
|
||||
// let session_ticket = self.session_ticket.acquire().await;
|
||||
let qs_read = self.qs.read_async().await;
|
||||
|
||||
IdmServerAuthTransaction {
|
||||
// _session_ticket: session_ticket,
|
||||
// sessions: self.sessions.write(),
|
||||
session_ticket: &self.session_ticket,
|
||||
sessions: &self.sessions,
|
||||
softlock_ticket: &self.softlock_ticket,
|
||||
softlocks: &self.softlocks,
|
||||
qs_read,
|
||||
sid,
|
||||
|
@ -526,7 +522,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
//
|
||||
// Check anything needed? Get the current auth-session-id from request
|
||||
// because it associates to the nonce's etc which were all cached.
|
||||
let euuid = self.qs_read.name_to_uuid(init.name.as_str())?; // I CAN'T TRACE WHERE AUDITSCOPE GOES :(((
|
||||
let euuid = self.qs_read.name_to_uuid(init.name.as_str())?;
|
||||
|
||||
// Get the first / single entry we expect here ....
|
||||
let entry = self.qs_read.internal_search_uuid(&euuid)?;
|
||||
|
@ -543,32 +539,54 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
// out of the session tree.
|
||||
let account = Account::try_from_entry_ro(entry.as_ref(), &mut self.qs_read)?;
|
||||
|
||||
// Intent to take both trees to write.
|
||||
let _session_ticket = self.session_ticket.acquire().await;
|
||||
|
||||
// Check the credential that the auth_session will attempt to
|
||||
// use.
|
||||
let is_valid = {
|
||||
let cred_uuid = account.primary_cred_uuid();
|
||||
//
|
||||
// NOTE: Very careful use of await here to avoid an issue with write.
|
||||
let maybe_slock_ref =
|
||||
account
|
||||
.primary_cred_uuid_and_policy()
|
||||
.map(|(cred_uuid, policy)| {
|
||||
// Acquire the softlock map
|
||||
let _softlock_ticket = self.softlock_ticket.acquire().await;
|
||||
//
|
||||
// We have no issue calling this with .write here, since we
|
||||
// already hold the session_ticket above.
|
||||
let mut softlock_write = self.softlocks.write();
|
||||
// Does it exist?
|
||||
let r = softlock_write
|
||||
.get_mut(&cred_uuid)
|
||||
.map(|slock| {
|
||||
// Apply the current time.
|
||||
slock.apply_time_step(ct);
|
||||
// Now check the results
|
||||
slock.is_valid()
|
||||
})
|
||||
.unwrap_or(true);
|
||||
let slock_ref: CredSoftLockMutex =
|
||||
if let Some(slock_ref) = softlock_write.get(&cred_uuid) {
|
||||
slock_ref.clone()
|
||||
} else {
|
||||
// Create if not exist, and the cred type supports softlocking.
|
||||
let slock = Arc::new(Mutex::new(CredSoftLock::new(policy)));
|
||||
softlock_write.insert(cred_uuid, slock.clone());
|
||||
slock
|
||||
};
|
||||
softlock_write.commit();
|
||||
r
|
||||
slock_ref
|
||||
});
|
||||
|
||||
let mut maybe_slock = if let Some(slock_ref) = maybe_slock_ref.as_ref() {
|
||||
Some(slock_ref.lock().await)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Need to as_mut here so that we hold the slock for the whole operation.
|
||||
let is_valid = if let Some(slock) = maybe_slock.as_mut() {
|
||||
slock.apply_time_step(ct);
|
||||
slock.is_valid()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let (auth_session, state) = if is_valid {
|
||||
AuthSession::new(account, self.webauthn, ct)
|
||||
} else {
|
||||
// it's softlocked, don't even bother.
|
||||
security_info!("Account is softlocked.");
|
||||
security_info!("Account is softlocked, or has no credentials associated.");
|
||||
(
|
||||
None,
|
||||
AuthState::Denied("Account is temporarily locked".to_string()),
|
||||
|
@ -577,14 +595,12 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
|
||||
match auth_session {
|
||||
Some(auth_session) => {
|
||||
// Now acquire the session tree for writing.
|
||||
let _session_ticket = self.session_ticket.acquire().await;
|
||||
let mut session_write = self.sessions.write();
|
||||
spanned!("idm::server::auth<Init> -> sessions", {
|
||||
if session_write.contains_key(&sessionid) {
|
||||
Err(OperationError::InvalidSessionState)
|
||||
} else {
|
||||
session_write.insert(sessionid, auth_session);
|
||||
session_write.insert(sessionid, Arc::new(Mutex::new(auth_session)));
|
||||
// Debugging: ensure we really inserted ...
|
||||
debug_assert!(session_write.get(&sessionid).is_some());
|
||||
Ok(())
|
||||
|
@ -612,34 +628,38 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
} // AuthEventStep::Init
|
||||
AuthEventStep::Begin(mech) => {
|
||||
// lperf_segment!("idm::server::auth<Begin>", || {
|
||||
let _session_ticket = self.session_ticket.acquire().await;
|
||||
let _softlock_ticket = self.softlock_ticket.acquire().await;
|
||||
// let _session_ticket = self.session_ticket.acquire().await;
|
||||
|
||||
let mut session_write = self.sessions.write();
|
||||
let session_read = self.sessions.read();
|
||||
// Do we have a session?
|
||||
let auth_session = session_write
|
||||
let auth_session_ref = session_read
|
||||
// Why is the session missing?
|
||||
.get_mut(&mech.sessionid)
|
||||
.get(&mech.sessionid)
|
||||
.map(|auth_session_ref| auth_session_ref.clone())
|
||||
.ok_or_else(|| {
|
||||
admin_error!("Invalid Session State (no present session uuid)");
|
||||
OperationError::InvalidSessionState
|
||||
})?;
|
||||
|
||||
let mut auth_session = auth_session_ref.lock().await;
|
||||
|
||||
let is_valid =
|
||||
if let Some(cred_uuid) = auth_session.get_account().primary_cred_uuid() {
|
||||
// From the auth_session, determine if the current account
|
||||
// credential that we are using has become softlocked or not.
|
||||
let mut softlock_write = self.softlocks.write();
|
||||
|
||||
let cred_uuid = auth_session.get_account().primary_cred_uuid();
|
||||
|
||||
let is_valid = softlock_write
|
||||
.get_mut(&cred_uuid)
|
||||
.map(|slock| {
|
||||
let softlock_read = self.softlocks.read();
|
||||
if let Some(slock_ref) = softlock_read.get(&cred_uuid) {
|
||||
let mut slock = slock_ref.lock().await;
|
||||
// Apply the current time.
|
||||
slock.apply_time_step(ct);
|
||||
// Now check the results
|
||||
slock.is_valid()
|
||||
})
|
||||
.unwrap_or(true);
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let r = if is_valid {
|
||||
// Indicate to the session which auth mech we now want to proceed with.
|
||||
|
@ -656,42 +676,61 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
delay,
|
||||
}
|
||||
});
|
||||
softlock_write.commit();
|
||||
session_write.commit();
|
||||
// softlock_write.commit();
|
||||
// session_write.commit();
|
||||
r
|
||||
} // End AuthEventStep::Mech
|
||||
AuthEventStep::Cred(creds) => {
|
||||
// lperf_segment!("idm::server::auth<Creds>", || {
|
||||
let _session_ticket = self.session_ticket.acquire().await;
|
||||
let _softlock_ticket = self.softlock_ticket.acquire().await;
|
||||
// let _session_ticket = self.session_ticket.acquire().await;
|
||||
|
||||
let mut session_write = self.sessions.write();
|
||||
let session_read = self.sessions.read();
|
||||
// Do we have a session?
|
||||
let auth_session = session_write
|
||||
let auth_session_ref = session_read
|
||||
// Why is the session missing?
|
||||
.get_mut(&creds.sessionid)
|
||||
.get(&creds.sessionid)
|
||||
.map(|auth_session_ref| auth_session_ref.clone())
|
||||
.ok_or_else(|| {
|
||||
admin_error!("Invalid Session State (no present session uuid)");
|
||||
OperationError::InvalidSessionState
|
||||
})?;
|
||||
|
||||
let mut auth_session = auth_session_ref.lock().await;
|
||||
|
||||
let maybe_slock_ref =
|
||||
auth_session
|
||||
.get_account()
|
||||
.primary_cred_uuid()
|
||||
.and_then(|cred_uuid| {
|
||||
let softlock_read = self.softlocks.read();
|
||||
|
||||
softlock_read.get(&cred_uuid).map(|s| s.clone())
|
||||
});
|
||||
|
||||
// From the auth_session, determine if the current account
|
||||
// credential that we are using has become softlocked or not.
|
||||
let mut softlock_write = self.softlocks.write();
|
||||
|
||||
let cred_uuid = auth_session.get_account().primary_cred_uuid();
|
||||
let maybe_slock = if let Some(s) = maybe_slock_ref.as_ref() {
|
||||
Some(s.lock().await)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let is_valid = softlock_write
|
||||
.get_mut(&cred_uuid)
|
||||
.map(|slock| {
|
||||
let maybe_valid = if let Some(mut slock) = maybe_slock {
|
||||
// Apply the current time.
|
||||
slock.apply_time_step(ct);
|
||||
// Now check the results
|
||||
slock.is_valid()
|
||||
})
|
||||
.unwrap_or(true);
|
||||
if slock.is_valid() {
|
||||
Some(slock)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let r = if is_valid {
|
||||
let r = match maybe_valid {
|
||||
Some(mut slock) => {
|
||||
// Process the credentials here as required.
|
||||
// Basically throw them at the auth_session and see what
|
||||
// falls out.
|
||||
|
@ -709,26 +748,17 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
// Inspect the result:
|
||||
// if it was a failure, we need to inc the softlock.
|
||||
if let AuthState::Denied(_) = &aus {
|
||||
if let Some(slock) = softlock_write.get_mut(&cred_uuid) {
|
||||
// Update it.
|
||||
slock.record_failure(ct);
|
||||
} else {
|
||||
// Create if not exist, and the cred type supports softlocking.
|
||||
if let Some(policy) =
|
||||
auth_session.get_account().primary_cred_softlock_policy()
|
||||
{
|
||||
let mut slock = CredSoftLock::new(policy);
|
||||
slock.record_failure(ct);
|
||||
softlock_write.insert(cred_uuid, slock);
|
||||
}
|
||||
}
|
||||
};
|
||||
aus
|
||||
})
|
||||
} else {
|
||||
}
|
||||
_ => {
|
||||
// Fail the session
|
||||
auth_session.end_session("Account is temporarily locked")
|
||||
}
|
||||
}
|
||||
.map(|aus| {
|
||||
// TODO: Change this william!
|
||||
// For now ...
|
||||
|
@ -740,8 +770,8 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
delay,
|
||||
}
|
||||
});
|
||||
softlock_write.commit();
|
||||
session_write.commit();
|
||||
// softlock_write.commit();
|
||||
// session_write.commit();
|
||||
r
|
||||
} // End AuthEventStep::Cred
|
||||
}
|
||||
|
@ -769,45 +799,53 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let _softlock_ticket = self.softlock_ticket.acquire().await;
|
||||
let maybe_slock_ref = match account.unix_cred_uuid_and_policy() {
|
||||
Some((cred_uuid, policy)) => {
|
||||
let softlock_read = self.softlocks.read();
|
||||
let slock_ref = match softlock_read.get(&cred_uuid) {
|
||||
Some(slock_ref) => slock_ref.clone(),
|
||||
None => {
|
||||
let _session_ticket = self.session_ticket.acquire().await;
|
||||
let mut softlock_write = self.softlocks.write();
|
||||
let slock = Arc::new(Mutex::new(CredSoftLock::new(policy)));
|
||||
softlock_write.insert(cred_uuid, slock.clone());
|
||||
softlock_write.commit();
|
||||
slock
|
||||
}
|
||||
};
|
||||
Some(slock_ref)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let cred_uuid = account.unix_cred_uuid();
|
||||
let is_valid = if let Some(cu) = cred_uuid.as_ref() {
|
||||
// Advanced and then check the softlock.
|
||||
softlock_write
|
||||
.get_mut(cu)
|
||||
.map(|slock| {
|
||||
let maybe_slock = if let Some(s) = maybe_slock_ref.as_ref() {
|
||||
Some(s.lock().await)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let maybe_valid = if let Some(mut slock) = maybe_slock {
|
||||
// Apply the current time.
|
||||
slock.apply_time_step(ct);
|
||||
// Now check the results
|
||||
slock.is_valid()
|
||||
})
|
||||
// No sl, it's valid.
|
||||
.unwrap_or(true)
|
||||
if slock.is_valid() {
|
||||
Some(slock)
|
||||
} else {
|
||||
// No cred id? It'll fail in verify ...
|
||||
true
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Validate the unix_pw - this checks the account/cred lock states.
|
||||
let res = if is_valid {
|
||||
let res = if let Some(mut slock) = maybe_valid {
|
||||
// Account is unlocked, can proceed.
|
||||
account
|
||||
.verify_unix_credential(uae.cleartext.as_str(), &self.async_tx, ct)
|
||||
.map(|res| {
|
||||
if res.is_none() {
|
||||
if let Some(cu) = cred_uuid.as_ref() {
|
||||
// Update the cred failure.
|
||||
if let Some(slock) = softlock_write.get_mut(cu) {
|
||||
// Update it.
|
||||
slock.record_failure(ct);
|
||||
} else if let Some(policy) = account.unix_cred_softlock_policy() {
|
||||
let mut slock = CredSoftLock::new(policy);
|
||||
slock.record_failure(ct);
|
||||
softlock_write.insert(*cu, slock);
|
||||
};
|
||||
}
|
||||
};
|
||||
res
|
||||
})
|
||||
|
@ -816,8 +854,6 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
security_info!("Account is softlocked.");
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
softlock_write.commit();
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -869,28 +905,45 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let _softlock_ticket = self.softlock_ticket.acquire().await;
|
||||
let maybe_slock_ref = match account.unix_cred_uuid_and_policy() {
|
||||
Some((cred_uuid, policy)) => {
|
||||
let softlock_read = self.softlocks.read();
|
||||
let slock_ref = match softlock_read.get(&cred_uuid) {
|
||||
Some(slock_ref) => slock_ref.clone(),
|
||||
None => {
|
||||
let _session_ticket = self.session_ticket.acquire().await;
|
||||
let mut softlock_write = self.softlocks.write();
|
||||
let slock = Arc::new(Mutex::new(CredSoftLock::new(policy)));
|
||||
softlock_write.insert(cred_uuid, slock.clone());
|
||||
softlock_write.commit();
|
||||
slock
|
||||
}
|
||||
};
|
||||
Some(slock_ref)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let cred_uuid = account.unix_cred_uuid();
|
||||
let is_valid = if let Some(cu) = cred_uuid.as_ref() {
|
||||
// Advanced and then check the softlock.
|
||||
softlock_write
|
||||
.get_mut(cu)
|
||||
.map(|slock| {
|
||||
let maybe_slock = if let Some(s) = maybe_slock_ref.as_ref() {
|
||||
Some(s.lock().await)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let maybe_valid = if let Some(mut slock) = maybe_slock {
|
||||
// Apply the current time.
|
||||
slock.apply_time_step(ct);
|
||||
// Now check the results
|
||||
slock.is_valid()
|
||||
})
|
||||
// No sl, it's valid.
|
||||
.unwrap_or(true)
|
||||
if slock.is_valid() {
|
||||
Some(slock)
|
||||
} else {
|
||||
// No cred id? It'll fail in verify ...
|
||||
true
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let res = if is_valid {
|
||||
let res = if let Some(mut slock) = maybe_valid {
|
||||
if account
|
||||
.verify_unix_credential(lae.cleartext.as_str(), &self.async_tx, ct)?
|
||||
.is_some()
|
||||
|
@ -927,17 +980,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
}))
|
||||
} else {
|
||||
// PW failure, update softlock.
|
||||
if let Some(cu) = cred_uuid.as_ref() {
|
||||
// Update the cred failure.
|
||||
if let Some(slock) = softlock_write.get_mut(cu) {
|
||||
// Update it.
|
||||
slock.record_failure(ct);
|
||||
} else if let Some(policy) = account.unix_cred_softlock_policy() {
|
||||
let mut slock = CredSoftLock::new(policy);
|
||||
slock.record_failure(ct);
|
||||
softlock_write.insert(*cu, slock);
|
||||
};
|
||||
};
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
|
@ -945,8 +988,6 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
security_info!("Account is softlocked.");
|
||||
Ok(None)
|
||||
};
|
||||
|
||||
softlock_write.commit();
|
||||
res
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,12 +166,10 @@ impl UnixUserAccount {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn unix_cred_uuid(&self) -> Option<Uuid> {
|
||||
self.cred.as_ref().map(|c| c.uuid)
|
||||
}
|
||||
|
||||
pub fn unix_cred_softlock_policy(&self) -> Option<CredSoftLockPolicy> {
|
||||
self.cred.as_ref().and_then(|cred| cred.softlock_policy())
|
||||
pub fn unix_cred_uuid_and_policy(&self) -> Option<(Uuid, CredSoftLockPolicy)> {
|
||||
self.cred
|
||||
.as_ref()
|
||||
.map(|cred| (cred.uuid, cred.softlock_policy()))
|
||||
}
|
||||
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::idm::server::{IdmServer, IdmServerTransaction};
|
|||
use crate::prelude::*;
|
||||
use async_std::task;
|
||||
use kanidm_proto::v1::{OperationError, UserAuthToken};
|
||||
use ldap3_server::simple::*;
|
||||
use ldap3_proto::simple::*;
|
||||
use regex::Regex;
|
||||
use std::collections::BTreeSet;
|
||||
use std::iter;
|
||||
|
@ -531,8 +531,8 @@ mod tests {
|
|||
use crate::ldap::LdapServer;
|
||||
use async_std::task;
|
||||
use hashbrown::HashSet;
|
||||
use ldap3_server::proto::{LdapFilter, LdapOp, LdapSearchScope};
|
||||
use ldap3_server::simple::*;
|
||||
use ldap3_proto::proto::{LdapFilter, LdapOp, LdapSearchScope};
|
||||
use ldap3_proto::simple::*;
|
||||
|
||||
const TEST_PASSWORD: &'static str = "ntaoeuntnaoeuhraohuercahu😍";
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.58.0
|
||||
1.59.0
|
||||
|
|
Loading…
Reference in a new issue