Compare commits

...

9 commits

Author SHA1 Message Date
alteriks f7b5aace65
Merge 48f7324080 into be4818e121 2025-04-24 12:15:43 +02:00
James Hodgkinson be4818e121
Update dependencies, fix a bunch of clippy lints () 2025-04-24 11:25:25 +10:00
Krzysztof Dajka 48f7324080 Merge branch 'master' of github.com:alteriks/kanidm 2025-02-11 11:50:55 +01:00
Krzysztof Dajka 791a182767 NEW: proxmox example docs
Add redirect URL to proxmox documentation

Update contributors list

Update examples/proxmox.md
2025-02-11 11:49:57 +01:00
alteriks 51a1e815b2
Merge branch 'master' into master 2025-02-11 09:55:56 +01:00
James Hodgkinson 399e1d71b8
Update examples/proxmox.md 2025-02-11 07:26:44 +10:00
Krzysztof Dajka 2c53ae77c5 Update contributors list 2024-12-05 09:54:51 +01:00
Krzysztof Dajka 3a3d3eb807 Add redirect URL to proxmox documentation 2024-12-05 09:54:21 +01:00
Krzysztof Dajka 6184d645d2 NEW: proxmox example 2024-12-04 21:42:34 +01:00
67 changed files with 848 additions and 583 deletions

View file

@ -1,6 +1,6 @@
## Author
- William Brown (Firstyear): william@blackhats.net.au
- William Brown (Firstyear): <william@blackhats.net.au>
## Contributors
@ -44,6 +44,7 @@
- adamcstephens
- Chris Olstrom (colstrom)
- Christopher-Robin (cebbinghaus)
- Krzysztof Dajka (alteriks)
- Fabian Kammel (datosh)
- Andris Raugulis (arthepsy)
- Jason (argonaut0)

779
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -118,15 +118,12 @@ codegen-units = 256
# webauthn-rs-proto = { path = "../webauthn-rs/webauthn-rs-proto" }
# sshkey-attest = { path = "../webauthn-rs/sshkey-attest" }
# kanidm-hsm-crypto = { path = "../hsm-crypto" }
# For BSD nss support
libnss = { git = "https://github.com/Firstyear/libnss-rs.git", branch = "20250207-freebsd" }
# Allow ssh keys to have comments with spaces.
sshkeys = { git = "https://github.com/Firstyear/rust-sshkeys.git", rev = "3a081cbf7480628223bcb96fc8aaa8c19109d007" }
[workspace.dependencies]
kanidmd_core = { path = "./server/core", version = "=1.6.0-dev" }
kanidmd_lib = { path = "./server/lib", version = "=1.6.0-dev" }
@ -143,7 +140,7 @@ kanidm_utils_users = { path = "./libs/users", version = "=1.6.0-dev" }
scim_proto = { path = "./libs/scim_proto", version = "=1.6.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.6.0-dev" }
anyhow = { version = "1.0.95" }
anyhow = { version = "1.0.98" }
argon2 = { version = "0.5.3", features = ["alloc"] }
askama = { version = "0.12.1", features = ["serde", "with-axum"] }
askama_axum = { version = "0.4.0" }
@ -164,7 +161,7 @@ base64 = "^0.22.1"
base64urlsafedata = "0.5.1"
bitflags = "^2.8.0"
bytes = "^1.9.0"
clap = { version = "^4.5.34", features = ["derive", "env"] }
clap = { version = "4.5.37", features = ["derive", "env"] }
clap_complete = "^4.5.42"
# Forced by saffron/cron
chrono = "^0.4.39"
@ -181,9 +178,9 @@ filetime = "^0.2.24"
fs4 = "^0.13.0"
futures = "^0.3.31"
futures-util = { version = "^0.3.30", features = ["sink"] }
gix = { version = "0.64.0", default-features = false }
gix = { version = "0.71.0", default-features = false }
haproxy-protocol = { version = "0.0.1" }
hashbrown = { version = "0.14.3", features = ["serde", "inline-more", "ahash"] }
hashbrown = { version = "0.15.2", features = ["serde", "inline-more"] }
hex = "^0.4.3"
http = "1.2.0"
http-body-util = "0.1"
@ -192,7 +189,7 @@ hyper = { version = "1.5.1", features = [
] } # hyper full includes client/server/http2
hyper-util = { version = "0.1.10", features = ["server", "tokio"] }
idlset = "^0.2.5"
image = { version = "0.24.9", default-features = false, features = [
image = { version = "0.25.6", default-features = false, features = [
"gif",
"jpeg",
"webp",
@ -205,16 +202,16 @@ lazy_static = "^1.5.0"
ldap3_client = "^0.5.2"
ldap3_proto = { version = "^0.5.2", features = ["serde"] }
libc = "^0.2.168"
libc = "0.2.172"
libnss = "^0.8.0"
libsqlite3-sys = "^0.25.2"
lodepng = "3.11.0"
lru = "^0.13.0"
mathru = "^0.13.0"
lru = "0.14.0"
mathru = "0.15.5"
md-5 = "0.10.6"
mimalloc = "0.1.43"
mimalloc = "0.1.46"
notify-debouncer-full = { version = "0.5" }
num_enum = "^0.5.11"
num_enum = "0.7.3"
oauth2_ext = { version = "^4.4.2", package = "oauth2", default-features = false }
openssl-sys = "^0.9"
openssl = "^0.10.72"
@ -236,11 +233,11 @@ tracing-core = "0.1.33"
peg = "0.8"
pkg-config = "^0.3.31"
prctl = "1.0.0"
proc-macro2 = "1.0.93"
qrcode = "^0.12.0"
proc-macro2 = "1.0.95"
qrcode = "0.14.1"
quote = "1"
rand = "^0.8.5"
rand_chacha = "0.3.1"
rand = "0.9.1"
rand_chacha = "0.9.0"
regex = "1.11.0"
reqwest = { version = "0.12.12", default-features = false, features = [
"cookies",
@ -250,13 +247,13 @@ reqwest = { version = "0.12.12", default-features = false, features = [
"rustls-tls-native-roots",
"rustls-tls-native-roots-no-provider",
] }
rusqlite = { version = "^0.28.0", features = ["array", "bundled"] }
rustls = { version = "0.23.21", default-features = false, features = [
rusqlite = { version = "0.35.0", features = ["array", "bundled"] }
rustls = { version = "0.23.26", default-features = false, features = [
"aws_lc_rs",
] }
sd-notify = "^0.4.5"
selinux = "^0.4.6"
selinux = "^0.5.1"
serde = "^1.0.217"
serde_cbor = { version = "0.12.0-dev", package = "serde_cbor_2" }
serde_json = "^1.0.137"
@ -264,13 +261,13 @@ serde_urlencoded = "^0.7.1"
serde_with = "3.12.0"
sha-crypt = "0.5.0"
sha2 = "0.10.8"
shellexpand = "^2.1.2"
shellexpand = "3.1.1"
smartstring = "^1.0.1"
smolset = "^1.3.1"
sshkey-attest = "^0.5.0"
sshkeys = "0.3.3"
svg = "0.13.1"
syn = { version = "2.0.96", features = ["full"] }
svg = "0.18.0"
syn = { version = "2.0.100", features = ["full"] }
tempfile = "3.15.0"
testkit-macros = { path = "./server/testkit-macros" }
time = { version = "^0.3.36", features = ["formatting", "local-offset"] }
@ -279,7 +276,7 @@ tokio = "^1.44.2"
tokio-openssl = "^0.6.5"
tokio-util = "^0.7.13"
toml = "^0.5.11"
toml = "^0.8.20"
tracing = { version = "^0.1.41", features = [
"max_level_trace",
"release_max_level_debug",
@ -306,6 +303,6 @@ walkdir = "2"
x509-cert = "0.2.5"
zxcvbn = "^2.2.2"
zxcvbn = "3.1.0"
nonempty = "0.8.1"
nonempty = "0.11.0"

Binary file not shown.

After

(image error) Size: 70 KiB

91
examples/proxmox.md Normal file
View file

@ -0,0 +1,91 @@
# Proxmox PVE/PBS
## Helpful links
- <https://pve.proxmox.com/wiki/User_Management>
- <https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pveum_openid>
## Proxmox OIDC limitation
As of December 2024, the OIDC implementation in Proxmox supports only authentication.
Authorization has to be done manually.
Mapping user to specific groups won't work yet (steps 2,3,4).
Patch for this feature exists, but it hasn't been tested extensively:
<https://lore.proxmox.com/pve-devel/20240901165512.687801-1-thomas@atskinner.net/>
See also:
<https://forum.proxmox.com/threads/openid-connect-default-group.103394/>
## On Kanidm
### 1. Create the proxmox resource server and configure the redirect URL
```bash
kanidm system oauth2 create proxmox "proxmox" https://yourproxmox.example.com
kanidm system oauth2 add-redirect-url "proxmox" https://yourproxmox.example.com
```
### 2. Create the appropriate group(s)
```bash
kanidm group create proxmox_users --name idm_admin
kanidm group create proxmox_admins --name idm_admin
```
### 3. Add the appropriate users to the group
```bash
kanidm group add-members proxmox_users user.name
kanidm group add-members proxmox_admins user.name
```
### 4. scope map
```bash
kanidm system oauth2 update-claim-map-join 'proxmox' 'proxmox_role' array
kanidm system oauth2 update-claim-map 'proxmox' 'proxmox_role' 'proxmox_admins' 'admin'
kanidm system oauth2 update-claim-map 'proxmox' 'proxmox_role' 'proxmox_users' 'user'
```
### 5. Add the scopes
```bash
kanidm system oauth2 update-scope-map proxmox proxmox_users email profile openid
```
### 6. Get the client secret
```bash
kanidm system oauth2 show-basic-secret proxmox
```
Copy the value that is returned.
## On proxmox server
### Using WebGUI
Go to <https://yourproxmox.example.com>
Select Datacenter->Realms->Add->OpenID Connect Server
![](media/kanidm_proxmox.png)
Issuer URL:
- <https://idm.example.com:8443/oauth2/openid/proxmox>
When kanidm is behind reverse proxy or when using docker port mapping:
- <https://idm.example.com/oauth2/openid/proxmox>
Realm: give some proper name or anything that's meaningful
Client ID: name given in step 1 (resource server)
Client Key: secret from step 6
Autocreate Users: Automatically create users if they do not exist. Users are stored in Proxmox Cluster File System (pmxcfs) - /etc/pve/user.cfg
### Using CLI
Login to proxmox node and execute:
```bash
pveum realm add kanidm --type openid --issuer-url https://idm.example.com/oauth2/openid/proxmox --client-id proxmox --client-key="secret from step 6" --username-claim username --scopes="email profile openid" --autocreate
```

View file

@ -834,9 +834,9 @@ impl TryFrom<&str> for Password {
impl Password {
fn bench_pbkdf2(pbkdf2_cost: usize) -> Option<Duration> {
let mut rng = rand::thread_rng();
let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.gen()).collect();
let input: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.gen()).collect();
let mut rng = rand::rng();
let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.random()).collect();
let input: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.random()).collect();
// This is 512 bits of output
let mut key: Vec<u8> = (0..PBKDF2_KEY_LEN).map(|_| 0).collect();
@ -855,9 +855,9 @@ impl Password {
}
fn bench_argon2id(params: Params) -> Option<Duration> {
let mut rng = rand::thread_rng();
let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
let input: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
let mut rng = rand::rng();
let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
let input: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
let mut key: Vec<u8> = (0..ARGON2_KEY_LEN).map(|_| 0).collect();
let argon = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
@ -873,8 +873,8 @@ impl Password {
pub fn new_pbkdf2(policy: &CryptoPolicy, cleartext: &str) -> Result<Self, CryptoError> {
let pbkdf2_cost = policy.pbkdf2_cost;
let mut rng = rand::thread_rng();
let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.gen()).collect();
let mut rng = rand::rng();
let salt: Vec<u8> = (0..PBKDF2_SALT_LEN).map(|_| rng.random()).collect();
let mut key: Vec<u8> = (0..PBKDF2_KEY_LEN).map(|_| 0).collect();
pbkdf2_hmac(
@ -897,8 +897,8 @@ impl Password {
let argon = Argon2::new(Algorithm::Argon2id, version, policy.argon2id_params.clone());
let mut rng = rand::thread_rng();
let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
let mut rng = rand::rng();
let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
let mut key: Vec<u8> = (0..ARGON2_KEY_LEN).map(|_| 0).collect();
argon
@ -925,8 +925,8 @@ impl Password {
let argon = Argon2::new(Algorithm::Argon2id, version, policy.argon2id_params.clone());
let mut rng = rand::thread_rng();
let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.gen()).collect();
let mut rng = rand::rng();
let salt: Vec<u8> = (0..ARGON2_SALT_LEN).map(|_| rng.random()).collect();
let mut check_key: Vec<u8> = (0..ARGON2_KEY_LEN).map(|_| 0).collect();
argon

View file

@ -77,7 +77,10 @@ pub fn apply_profile() {
.decode(contents)
.unwrap_or_else(|_| panic!("Failed to parse profile - {} - {}", profile, contents));
let profile_cfg: ProfileConfig = toml::from_slice(&data)
let data_str = String::from_utf8(data)
.unwrap_or_else(|_| panic!("Failed to read profile data to UTF-8 string - {}", profile));
let profile_cfg: ProfileConfig = toml::from_str(&data_str)
.unwrap_or_else(|_| panic!("Failed to parse profile - {} - {}", profile, contents));
// We have to setup for our pkg version to be passed into things correctly

View file

@ -2417,7 +2417,7 @@ mod tests {
let lims = Limits::unlimited();
let r = be.search(&lims, &filt);
assert!(r.expect("Search failed!").len() == 0);
assert!(r.expect("Search failed!").is_empty());
});
}

View file

@ -145,8 +145,8 @@ impl Totp {
// Create a new token with secure key and algo.
pub fn generate_secure(step: u64) -> Self {
let mut rng = rand::thread_rng();
let secret: Vec<u8> = (0..SECRET_SIZE_BYTES).map(|_| rng.gen()).collect();
let mut rng = rand::rng();
let secret: Vec<u8> = (0..SECRET_SIZE_BYTES).map(|_| rng.random()).collect();
let algo = TotpAlgo::Sha256;
let digits = TotpDigits::Six;
Totp {

View file

@ -17,6 +17,7 @@ use webauthn_rs::prelude::{
AttestedPasskey as AttestedPasskeyV4, AttestedPasskeyRegistration, CreationChallengeResponse,
Passkey as PasskeyV4, PasskeyRegistration, RegisterPublicKeyCredential, WebauthnError,
};
use zxcvbn::{zxcvbn, Score};
use crate::credential::totp::{Totp, TOTP_DEFAULT_STEP};
use crate::credential::{BackupCodes, Credential};
@ -1663,23 +1664,14 @@ impl IdmServerCredUpdateTransaction<'_> {
}
// does the password pass zxcvbn?
let entropy = zxcvbn::zxcvbn(cleartext, related_inputs).map_err(|e| {
admin_error!("zxcvbn check failure (password empty?) {:?}", e);
// Return some generic feedback when the password is this bad.
PasswordQuality::Feedback(vec![
PasswordFeedback::UseAFewWordsAvoidCommonPhrases,
PasswordFeedback::AddAnotherWordOrTwo,
PasswordFeedback::NoNeedForSymbolsDigitsOrUppercaseLetters,
])
})?;
let entropy = zxcvbn(cleartext, related_inputs);
// PW's should always be enforced as strong as possible.
if entropy.score() < 4 {
if entropy.score() < Score::Four {
// The password is too week as per:
// https://docs.rs/zxcvbn/2.0.0/zxcvbn/struct.Entropy.html
let feedback: zxcvbn::feedback::Feedback = entropy
.feedback()
.as_ref()
.ok_or(OperationError::InvalidState)
.cloned()
.map_err(|e| {
@ -3405,7 +3397,7 @@ mod tests {
assert!(
matches!(
c_status.mfaregstate,
MfaRegStateStatus::TotpNameTryAgain(ref val) if val == ""
MfaRegStateStatus::TotpNameTryAgain(ref val) if val.is_empty()
),
"{:?}",
c_status.mfaregstate

View file

@ -1209,7 +1209,7 @@ mod tests {
// Searching a malformed spn shouldn't cause the query to fail
let sr = SearchRequest {
msgid: 1,
base: format!("dc=example,dc=com"),
base: "dc=example,dc=com".to_string(),
scope: LdapSearchScope::Subtree,
filter: LdapFilter::Or(vec![
LdapFilter::Equality(Attribute::Name.to_string(), usr_name.to_string()),
@ -1232,7 +1232,7 @@ mod tests {
let sr = SearchRequest {
msgid: 1,
base: format!("dc=example,dc=com"),
base: "dc=example,dc=com".to_string(),
scope: LdapSearchScope::Subtree,
filter: LdapFilter::And(vec![
LdapFilter::Equality(Attribute::Name.to_string(), usr_name.to_string()),

View file

@ -2992,11 +2992,12 @@ fn validate_scopes(req_scopes: &BTreeSet<String>) -> Result<(), Oauth2Error> {
#[cfg(any(feature = "dev-oauth2-device-flow", test))]
#[allow(dead_code)]
fn gen_device_code() -> Result<[u8; 16], Oauth2Error> {
let mut rng = rand::thread_rng();
use rand::TryRngCore;
let mut rng = rand::rng();
let mut result = [0u8; 16];
// doing it here because of feature-shenanigans.
use rand::Rng;
if let Err(err) = rng.try_fill(&mut result) {
if let Err(err) = rng.try_fill_bytes(&mut result) {
error!("Failed to generate device code! {:?}", err);
return Err(Oauth2Error::ServerError(OperationError::Backend));
}
@ -3009,8 +3010,8 @@ fn gen_device_code() -> Result<[u8; 16], Oauth2Error> {
/// Returns (xxx-yyy-zzz, digits) where one's the human-facing code, the other is what we store in the DB.
fn gen_user_code() -> (String, u32) {
use rand::Rng;
let mut rng = rand::thread_rng();
let num: u32 = rng.gen_range(0..=999999999);
let mut rng = rand::rng();
let num: u32 = rng.random_range(0..=999999999);
let result = format!("{:09}", num);
(
format!("{}-{}-{}", &result[0..3], &result[3..6], &result[6..9]),
@ -3100,6 +3101,7 @@ mod tests {
$code_challenge:expr,
$scope:expr
) => {{
#[allow(clippy::unnecessary_to_owned)]
let scope: BTreeSet<String> = $scope.split(" ").map(|s| s.to_string()).collect();
let auth_req = AuthorisationRequest {
@ -7312,10 +7314,7 @@ mod tests {
&Url::parse(example_is_not_local)
.expect("Failed to parse example.com as a host?")
.host()
.expect(&format!(
"Couldn't get a host from {}",
example_is_not_local
))
.unwrap_or_else(|| panic!("Couldn't get a host from {}", example_is_not_local))
));
let test_urls = [

View file

@ -21,6 +21,7 @@ use tokio::sync::{Mutex, Semaphore};
use tracing::trace;
use url::Url;
use webauthn_rs::prelude::{Webauthn, WebauthnBuilder};
use zxcvbn::{zxcvbn, Score};
use super::event::ReadBackupCodeEvent;
use super::ldap::{LdapBoundToken, LdapSession};
@ -235,7 +236,7 @@ impl IdmServer {
let qs_read = self.qs.read().await?;
let mut sid = [0; 4];
let mut rng = StdRng::from_entropy();
let mut rng = StdRng::from_os_rng();
rng.fill(&mut sid);
Ok(IdmServerAuthTransaction {
@ -278,7 +279,7 @@ impl IdmServer {
let qs_write = self.qs.write(ts).await?;
let mut sid = [0; 4];
let mut rng = StdRng::from_entropy();
let mut rng = StdRng::from_os_rng();
rng.fill(&mut sid);
Ok(IdmServerProxyWriteTransaction {
@ -1657,18 +1658,14 @@ impl IdmServerProxyWriteTransaction<'_> {
// does the password pass zxcvbn?
let entropy = zxcvbn::zxcvbn(cleartext, related_inputs).map_err(|e| {
admin_error!("zxcvbn check failure (password empty?) {:?}", e);
OperationError::PasswordQuality(vec![PasswordFeedback::TooShort(PW_MIN_LENGTH)])
})?;
let entropy = zxcvbn(cleartext, related_inputs);
// Unix PW's are a single factor, so we enforce good pws
if entropy.score() < 4 {
if entropy.score() < Score::Four {
// The password is too week as per:
// https://docs.rs/zxcvbn/2.0.0/zxcvbn/struct.Entropy.html
let feedback: zxcvbn::feedback::Feedback = entropy
.feedback()
.as_ref()
.ok_or(OperationError::InvalidState)
.cloned()
.inspect_err(|err| {

View file

@ -217,9 +217,9 @@ impl EntryChangeState {
}
#[cfg(test)]
pub(crate) fn get_attr_cid(&self, attr: Attribute) -> Option<&Cid> {
pub(crate) fn get_attr_cid(&self, attr: &Attribute) -> Option<&Cid> {
match &self.st {
State::Live { at: _, changes } => changes.get(&attr),
State::Live { at: _, changes } => changes.get(attr),
State::Tombstone { at: _ } => None,
}
}

View file

@ -705,7 +705,7 @@ async fn test_repl_increment_basic_deleted_attr(server_a: &QueryServer, server_b
let e1_cs = e1.get_changestate();
let e2_cs = e2.get_changestate();
assert_eq!(e1_cs, e2_cs);
assert!(e1_cs.get_attr_cid(Attribute::Description).is_some());
assert!(e1_cs.get_attr_cid(&Attribute::Description).is_some());
server_b_txn.commit().expect("Failed to commit");
drop(server_a_txn);

View file

@ -186,7 +186,7 @@ mod tests {
match desc {
ScimValueKanidm::String(gdesc) if gdesc == "Group Description" => {}
_ => assert!(false),
_ => unreachable!("Expected a string"),
};
// null removes attr
@ -201,7 +201,7 @@ mod tests {
.expect("Failed to resolve data type");
let updated_entry = server_txn.scim_put(put_event).expect("Failed to put");
assert!(updated_entry.attrs.get(&Attribute::Description).is_none());
assert!(!updated_entry.attrs.contains_key(&Attribute::Description));
// set one
let put = ScimEntryPutKanidm {
@ -234,7 +234,7 @@ mod tests {
value: "extra_1@example.com".to_string(),
}));
}
_ => assert!(false),
_ => unreachable!("Expected 1 member"),
};
// set many
@ -285,7 +285,7 @@ mod tests {
value: "extra_3@example.com".to_string(),
}));
}
_ => assert!(false),
_ => unreachable!("Expected 3 members"),
};
// set many with a removal
@ -333,7 +333,7 @@ mod tests {
value: "extra_2@example.com".to_string(),
}));
}
_ => assert!(false),
_ => unreachable!("Expected 2 members"),
};
// empty set removes attr
@ -348,6 +348,6 @@ mod tests {
.expect("Failed to resolve data type");
let updated_entry = server_txn.scim_put(put_event).expect("Failed to put");
assert!(updated_entry.attrs.get(&Attribute::Member).is_none());
assert!(!updated_entry.attrs.contains_key(&Attribute::Member));
}
}

View file

@ -4,12 +4,19 @@ use crate::schema::Schema;
pub struct TestConfiguration {
pub domain_level: DomainVersion,
// This is literally here to make clippy happy, just leave it alone!
// if you don't believe me then remove it and run 'cargo clippy --all-targets' it'll complain
// about "struct update has no effect, all the fields in the struct have already been specified"
// because the domain_level was set, then we ..Default::default() the "rest"
#[allow(dead_code)]
pub ignore_this_field: bool,
}
impl Default for TestConfiguration {
fn default() -> Self {
TestConfiguration {
domain_level: DOMAIN_TGT_LEVEL,
ignore_this_field: false,
}
}
}

View file

@ -2,8 +2,8 @@
use crate::prelude::*;
use hashbrown::HashSet;
use rand::distributions::{Distribution, Uniform};
use rand::{thread_rng, Rng};
use rand::distr::{Distribution, Uniform};
use rand::{rng, Rng};
use std::ops::Range;
#[derive(Debug)]
@ -35,7 +35,7 @@ pub fn uuid_from_duration(d: Duration, sid: Sid) -> Uuid {
}
pub(crate) fn password_from_random_len(len: u32) -> String {
thread_rng()
rng()
.sample_iter(&DistinctAlpha)
.take(len as usize)
.collect::<String>()
@ -52,7 +52,7 @@ pub fn backup_code_from_random() -> HashSet<String> {
pub fn readable_password_from_random() -> String {
// 2^112 bits, means we need at least 55^20 to have as many bits of entropy.
// this leads us to 4 groups of 5 to create 55^20
let mut trng = thread_rng();
let mut trng = rng();
format!(
"{}-{}-{}-{}",
(&mut trng)
@ -80,8 +80,9 @@ impl Distribution<char> for DistinctAlpha {
const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHJKLMNPQRSTUVWXYZ\
abcdefghjkpqrstuvwxyz\
0123456789";
let range = Uniform::new(0, RANGE);
// TODO: this needs to handle the error, maybe?
#[allow(clippy::expect_used)]
let range = Uniform::new(0, RANGE).expect("Failed to get a uniform range");
let n = range.sample(rng);
GEN_ASCII_STR_CHARSET[n as usize] as char

View file

@ -683,10 +683,10 @@ mod tests {
"value": "claire@example.com"
}
]"#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetEmailAddress>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetEmailAddress>(&vs, &[])
}
#[test]
@ -711,9 +711,9 @@ mod tests {
}
]"#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetAddress>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetAddress>(&vs, &[])
}
}

View file

@ -381,6 +381,6 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
}

View file

@ -400,6 +400,6 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
}

View file

@ -185,9 +185,9 @@ mod tests {
#[test]
fn test_scim_boolean() {
let vs: ValueSet = ValueSetBool::new(true);
crate::valueset::scim_json_reflexive(vs.clone(), "true");
crate::valueset::scim_json_reflexive(&vs, "true");
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetBool>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetBool>(&vs, &[])
}
}

View file

@ -352,6 +352,6 @@ raBy6edj7W0EIH+yQxkDEwIhAI0nVKaI6duHLAvtKW6CfEQFG6jKg7dyk37YYiRD
assert_eq!(cert.s256, expect_s256);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetCertificate>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetCertificate>(&vs, &[])
}
}

View file

@ -193,6 +193,6 @@ mod tests {
let vs: ValueSet = ValueSetCid::new(Cid::new_zero());
let data = r#""00000000000000000000000000000000-00000000-0000-0000-0000-000000000000""#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
}

View file

@ -1183,15 +1183,15 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
#[test]
fn test_scim_credential_type() {
let vs: ValueSet = ValueSetCredentialType::new(CredentialType::Mfa);
crate::valueset::scim_json_reflexive(vs.clone(), r#""mfa""#);
crate::valueset::scim_json_reflexive(&vs, r#""mfa""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetCredentialType>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetCredentialType>(&vs, &[])
}
}

View file

@ -210,9 +210,9 @@ mod tests {
let odt = OffsetDateTime::UNIX_EPOCH + Duration::from_secs(69_420);
let vs: ValueSet = ValueSetDateTime::new(odt);
crate::valueset::scim_json_reflexive(vs.clone(), r#""1970-01-01T19:17:00Z""#);
crate::valueset::scim_json_reflexive(&vs, r#""1970-01-01T19:17:00Z""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetDateTime>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetDateTime>(&vs, &[])
}
}

View file

@ -183,9 +183,6 @@ mod tests {
fn test_scim_hexstring() {
let vs: ValueSet =
ValueSetHexString::new("D68475C760A7A0F6A924C28F095573A967F600D6".to_string());
crate::valueset::scim_json_reflexive(
vs.clone(),
r#""D68475C760A7A0F6A924C28F095573A967F600D6""#,
);
crate::valueset::scim_json_reflexive(&vs, r#""D68475C760A7A0F6A924C28F095573A967F600D6""#);
}
}

View file

@ -1,3 +1,5 @@
use std::io::Cursor;
use image::codecs::jpeg::JpegDecoder;
use image::ImageDecoder;
use sketching::*;
@ -79,9 +81,9 @@ pub fn has_trailer(contents: &Vec<u8>) -> Result<bool, ImageValidationError> {
pub fn validate_decoding(
filename: &str,
contents: &[u8],
limits: image::io::Limits,
limits: image::Limits,
) -> Result<(), ImageValidationError> {
let mut decoder = match JpegDecoder::new(contents) {
let mut decoder = match JpegDecoder::new(Cursor::new(contents)) {
Ok(val) => val,
Err(err) => {
return Err(ImageValidationError::InvalidImage(format!(

View file

@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::valueset::ScimResolveStatus;
use std::fmt::Display;
use std::io::Cursor;
use crate::be::dbvalue::DbValueImage;
use crate::prelude::*;
@ -37,8 +38,8 @@ pub trait ImageValueThings {
/// A sha256 of the filename/type/contents
fn hash_imagevalue(&self) -> String;
fn get_limits(&self) -> image::io::Limits {
let mut limits = image::io::Limits::default();
fn get_limits(&self) -> image::Limits {
let mut limits = image::Limits::default();
limits.max_image_height = Some(MAX_IMAGE_HEIGHT);
limits.max_image_width = Some(MAX_IMAGE_WIDTH);
limits
@ -148,7 +149,7 @@ impl ImageValueThings for ImageValue {
/// validate the GIF file contents, and that it's actually a GIF
fn validate_is_gif(&self) -> Result<(), ImageValidationError> {
let Ok(mut decoder) = GifDecoder::new(&self.contents[..]) else {
let Ok(mut decoder) = GifDecoder::new(Cursor::new(&self.contents[..])) else {
return Err(ImageValidationError::InvalidImage(
"Failed to parse GIF".to_string(),
));
@ -189,7 +190,7 @@ impl ImageValueThings for ImageValue {
));
}
let Ok(mut decoder) = WebPDecoder::new(&self.contents[..]) else {
let Ok(mut decoder) = WebPDecoder::new(Cursor::new(&self.contents[..])) else {
return Err(ImageValidationError::InvalidImage(
"Failed to parse WebP file".to_string(),
));
@ -532,7 +533,7 @@ mod tests {
"142dc7984dd548dd5dacfe2ad30f8473e3217e39b3b6c8d17a0cf6e4e24b02e0"
]"#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
}
*/
}

View file

@ -226,9 +226,9 @@ mod tests {
#[test]
fn test_scim_iname() {
let vs: ValueSet = ValueSetIname::new("stevo");
crate::valueset::scim_json_reflexive(vs.clone(), r#""stevo""#);
crate::valueset::scim_json_reflexive(&vs, r#""stevo""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetIname>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetIname>(&vs, &[])
}
}

View file

@ -183,9 +183,9 @@ mod tests {
#[test]
fn test_scim_index() {
let vs: ValueSet = ValueSetIndex::new(IndexType::Equality);
crate::valueset::scim_json_reflexive(vs.clone(), r#"["EQUALITY"]"#);
crate::valueset::scim_json_reflexive(&vs, r#"["EQUALITY"]"#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetIndex>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetIndex>(&vs, &[])
}
}

View file

@ -227,9 +227,9 @@ mod tests {
#[test]
fn test_scim_iutf8() {
let vs: ValueSet = ValueSetIutf8::new("lowercase string");
crate::valueset::scim_json_reflexive(vs.clone(), r#""lowercase string""#);
crate::valueset::scim_json_reflexive(&vs, r#""lowercase string""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetIutf8>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetIutf8>(&vs, &[])
}
}

View file

@ -205,9 +205,9 @@ mod tests {
"{\"pres\":\"class\"}"
]
"#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
// Test that we can parse json values into a valueset.
// crate::valueset::scim_json_put_reflexive::<ValueSetJsonFilter>(vs, &[])
// crate::valueset::scim_json_put_reflexive::<ValueSetJsonFilter>(&vs, &[])
}
}

View file

@ -649,6 +649,6 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
}

View file

@ -995,7 +995,7 @@ pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result<ValueSet, OperationErro
}
#[cfg(test)]
pub(crate) fn scim_json_reflexive(vs: ValueSet, data: &str) {
pub(crate) fn scim_json_reflexive(vs: &ValueSet, data: &str) {
let scim_value = vs.to_scim_value().unwrap().assume_resolved();
let strout = serde_json::to_string_pretty(&scim_value).unwrap();
@ -1012,25 +1012,27 @@ pub(crate) fn scim_json_reflexive(vs: ValueSet, data: &str) {
#[cfg(test)]
pub(crate) fn scim_json_reflexive_unresolved(
write_txn: &mut QueryServerWriteTransaction,
vs: ValueSet,
vs: &ValueSet,
data: &str,
) {
let scim_int_value = vs.to_scim_value().unwrap().assume_unresolved();
let scim_value = write_txn.resolve_scim_interim(scim_int_value).unwrap();
let strout = serde_json::to_string_pretty(&scim_value).unwrap();
let strout = serde_json::to_string_pretty(&scim_value).expect("Failed to serialize");
eprintln!("{}", strout);
let json_value: serde_json::Value = serde_json::to_value(&scim_value).unwrap();
let json_value: serde_json::Value =
serde_json::to_value(&scim_value).expect("Failed to convert to JSON");
let expect: serde_json::Value = serde_json::from_str(data).unwrap();
let expect: serde_json::Value =
serde_json::from_str(data).expect("Failed to parse expected JSON");
assert_eq!(json_value, expect);
}
#[cfg(test)]
pub(crate) fn scim_json_put_reflexive<T: ValueSetScimPut>(
expect_vs: ValueSet,
expect_vs: &ValueSet,
additional_tests: &[(JsonValue, ValueSet)],
) {
let scim_value = expect_vs.to_scim_value().unwrap().assume_resolved();
@ -1041,7 +1043,7 @@ pub(crate) fn scim_json_put_reflexive<T: ValueSetScimPut>(
let generic = serde_json::to_value(scim_value).unwrap();
// Check that we can turn back into a vs from the generic version.
let vs = T::from_scim_json_put(generic).unwrap().assume_resolved();
assert_eq!(&vs, &expect_vs);
assert_eq!(&vs, expect_vs);
// For each additional check, assert they work as expected.
for (jv, expect_vs) in additional_tests {
@ -1053,7 +1055,7 @@ pub(crate) fn scim_json_put_reflexive<T: ValueSetScimPut>(
#[cfg(test)]
pub(crate) fn scim_json_put_reflexive_unresolved<T: ValueSetScimPut>(
write_txn: &mut QueryServerWriteTransaction,
expect_vs: ValueSet,
expect_vs: &ValueSet,
additional_tests: &[(JsonValue, ValueSet)],
) {
let scim_int_value = expect_vs.to_scim_value().unwrap().assume_unresolved();
@ -1063,7 +1065,7 @@ pub(crate) fn scim_json_put_reflexive_unresolved<T: ValueSetScimPut>(
// Check that we can turn back into a vs from the generic version.
let vs_inter = T::from_scim_json_put(generic).unwrap().assume_unresolved();
let vs = write_txn.resolve_valueset_intermediate(vs_inter).unwrap();
assert_eq!(&vs, &expect_vs);
assert_eq!(&vs, expect_vs);
// For each additional check, assert they work as expected.
for (jv, expect_vs) in additional_tests {

View file

@ -189,12 +189,9 @@ mod tests {
fn test_scim_nsuniqueid() {
let vs: ValueSet =
ValueSetNsUniqueId::new("3a163ca0-47624620-a18806b7-50c84c86".to_string());
crate::valueset::scim_json_reflexive(
vs.clone(),
r#""3a163ca0-47624620-a18806b7-50c84c86""#,
);
crate::valueset::scim_json_reflexive(&vs, r#""3a163ca0-47624620-a18806b7-50c84c86""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetNsUniqueId>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetNsUniqueId>(&vs, &[])
}
}

View file

@ -898,10 +898,10 @@ mod tests {
fn test_scim_oauth2_scope() {
let vs: ValueSet = ValueSetOauthScope::new("fully_sick_scope_m8".to_string());
let data = r#"["fully_sick_scope_m8"]"#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetOauthScope>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetOauthScope>(&vs, &[])
}
#[qs_test]
@ -930,12 +930,12 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive_unresolved(&mut write_txn, vs.clone(), data);
crate::valueset::scim_json_reflexive_unresolved(&mut write_txn, &vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive_unresolved::<ValueSetOauthScopeMap>(
&mut write_txn,
vs,
&vs,
&[],
);
@ -970,12 +970,12 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive_unresolved(&mut write_txn, vs.clone(), data);
crate::valueset::scim_json_reflexive_unresolved(&mut write_txn, &vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive_unresolved::<ValueSetOauthClaimMap>(
&mut write_txn,
vs,
&vs,
&[],
);

View file

@ -205,6 +205,6 @@ mod tests {
#[test]
fn test_scim_restricted() {
let vs: ValueSet = ValueSetRestricted::new("Test".to_string());
crate::valueset::scim_json_reflexive(vs, r#""Test""#);
crate::valueset::scim_json_reflexive(&vs, r#""Test""#);
}
}

View file

@ -1920,7 +1920,7 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
#[test]
@ -1948,6 +1948,6 @@ mod tests {
]
"#;
crate::valueset::scim_json_reflexive(vs, data);
crate::valueset::scim_json_reflexive(&vs, data);
}
}

View file

@ -188,6 +188,6 @@ mod tests {
#[test]
fn test_scim_spn() {
let vs: ValueSet = ValueSetSpn::new(("claire".to_string(), "example.com".to_string()));
crate::valueset::scim_json_reflexive(vs, r#""claire@example.com""#);
crate::valueset::scim_json_reflexive(&vs, r#""claire@example.com""#);
}
}

View file

@ -247,9 +247,9 @@ mod tests {
}
]
"#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetSshKey>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetSshKey>(&vs, &[])
}
}

View file

@ -188,9 +188,9 @@ mod tests {
#[test]
fn test_scim_syntax() {
let vs: ValueSet = ValueSetSyntax::new(SyntaxType::Uuid);
crate::valueset::scim_json_reflexive(vs.clone(), r#""UUID""#);
crate::valueset::scim_json_reflexive(&vs, r#""UUID""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetSyntax>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetSyntax>(&vs, &[])
}
}

View file

@ -163,9 +163,9 @@ mod tests {
#[test]
fn test_scim_uihint() {
let vs: ValueSet = ValueSetUiHint::new(UiHint::PosixAccount);
crate::valueset::scim_json_reflexive(vs.clone(), r#"["posixaccount"]"#);
crate::valueset::scim_json_reflexive(&vs, r#"["posixaccount"]"#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetUiHint>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetUiHint>(&vs, &[])
}
}

View file

@ -196,9 +196,9 @@ mod tests {
#[test]
fn test_scim_uint32() {
let vs: ValueSet = ValueSetUint32::new(69);
crate::valueset::scim_json_reflexive(vs.clone(), "69");
crate::valueset::scim_json_reflexive(&vs, "69");
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetUint32>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetUint32>(&vs, &[])
}
}

View file

@ -183,9 +183,9 @@ mod tests {
fn test_scim_url() {
let u = Url::parse("https://idm.example.com").unwrap();
let vs: ValueSet = ValueSetUrl::new(u);
crate::valueset::scim_json_reflexive(vs.clone(), r#""https://idm.example.com/""#);
crate::valueset::scim_json_reflexive(&vs, r#""https://idm.example.com/""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetUrl>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetUrl>(&vs, &[])
}
}

View file

@ -246,9 +246,9 @@ mod tests {
fn test_scim_utf8() {
let vs: ValueSet = ValueSetUtf8::new("Test".to_string());
// Test that the output json matches some known str
crate::valueset::scim_json_reflexive(vs.clone(), r#""Test""#);
crate::valueset::scim_json_reflexive(&vs, r#""Test""#);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetUtf8>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetUtf8>(&vs, &[])
}
}

View file

@ -422,10 +422,10 @@ mod tests {
let data = r#""4d21d04a-dc0e-42eb-b850-34dd180b107f""#;
crate::valueset::scim_json_reflexive(vs.clone(), data);
crate::valueset::scim_json_reflexive(&vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive::<ValueSetUuid>(vs, &[])
crate::valueset::scim_json_put_reflexive::<ValueSetUuid>(&vs, &[])
}
#[qs_test]
@ -449,12 +449,12 @@ mod tests {
let data = r#"[{"uuid": "4d21d04a-dc0e-42eb-b850-34dd180b107f", "value": "testperson1@example.com"}]"#;
crate::valueset::scim_json_reflexive_unresolved(&mut write_txn, vs.clone(), data);
crate::valueset::scim_json_reflexive_unresolved(&mut write_txn, &vs, data);
// Test that we can parse json values into a valueset.
crate::valueset::scim_json_put_reflexive_unresolved::<ValueSetRefer>(
&mut write_txn,
vs,
&vs,
&[],
);

View file

@ -44,7 +44,7 @@ pub fn cli_kanidm(_input: TokenStream) -> TokenStream {
.run()
.unwrap();
let mut kanidm = kanidm.command();
kanidm.env("KANIDM_URL", &rsclient.get_url().to_string());
kanidm.env("KANIDM_URL", rsclient.get_url().to_string());
kanidm.env("KANIDM_TOKEN_CACHE_PATH", &token_cache_path);
kanidm
}

View file

@ -10,7 +10,7 @@ async fn test_v1_group_id_patch(rsclient: &KanidmClient) {
.await;
assert!(res.is_ok());
create_user(&rsclient, "foo", "foogroup").await;
create_user(rsclient, "foo", "foogroup").await;
let post_body = serde_json::json!({"attrs": { ATTR_DESCRIPTION : ["Fancy group change"]}});
@ -31,7 +31,7 @@ async fn test_v1_group_id_attr_post(rsclient: &KanidmClient) {
.await;
assert!(res.is_ok());
create_user(&rsclient, "foo", "foogroup").await;
create_user(rsclient, "foo", "foogroup").await;
let post_body = serde_json::json!(["foo"]);

View file

@ -17,8 +17,8 @@ static USER_B_NAME: &str = "valid_user_b";
#[kanidmd_testkit::test]
async fn test_not_authenticated(rsclient: &KanidmClient) {
// basically here we try a bit of all the possible combinations while unauthenticated to check it's not working
setup_server(&rsclient).await;
create_user(&rsclient, USER_A_NAME).await;
setup_server(rsclient).await;
create_user(rsclient, USER_A_NAME).await;
let _ = rsclient.logout().await;
let res = rsclient
.idm_person_identify_user(USER_A_NAME, IdentifyUserRequest::Start)
@ -47,11 +47,11 @@ async fn test_not_authenticated(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
async fn test_non_existing_user_id(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
create_user(&rsclient, USER_A_NAME).await;
create_user(&rsclient, USER_B_NAME).await;
setup_server(rsclient).await;
create_user(rsclient, USER_A_NAME).await;
create_user(rsclient, USER_B_NAME).await;
let non_existing_user = "non_existing_user";
login_with_user(&rsclient, USER_A_NAME).await;
login_with_user(rsclient, USER_A_NAME).await;
let res: Result<IdentifyUserResponse, kanidm_client::ClientError> = rsclient
.idm_person_identify_user(non_existing_user, IdentifyUserRequest::Start)
.await;
@ -87,9 +87,9 @@ async fn test_non_existing_user_id(rsclient: &KanidmClient) {
// Each tests is named like `test_{api input}_response_{expected api output}_or_{expected api output}`
#[kanidmd_testkit::test]
async fn test_start_response_identity_verification_available(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
create_user(&rsclient, USER_A_NAME).await;
login_with_user(&rsclient, USER_A_NAME).await;
setup_server(rsclient).await;
create_user(rsclient, USER_A_NAME).await;
login_with_user(rsclient, USER_A_NAME).await;
let response = rsclient
.idm_person_identify_user(USER_A_NAME, IdentifyUserRequest::Start)
@ -106,10 +106,10 @@ async fn test_start_response_identity_verification_available(rsclient: &KanidmCl
// `Start`, that is WaitForCode or ProvideCode
#[kanidmd_testkit::test]
async fn test_start_response_wait_for_code_or_provide_code(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
login_with_user(&rsclient, USER_A_NAME).await;
setup_server(rsclient).await;
let user_a_uuid = create_user(rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(rsclient, USER_B_NAME).await;
login_with_user(rsclient, USER_A_NAME).await;
let response = rsclient
.idm_person_identify_user(USER_B_NAME, IdentifyUserRequest::Start)
.await;
@ -130,10 +130,10 @@ async fn test_start_response_wait_for_code_or_provide_code(rsclient: &KanidmClie
#[kanidmd_testkit::test]
async fn test_provide_code_response_code_failure_or_provide_code(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
login_with_user(&rsclient, USER_A_NAME).await;
setup_server(rsclient).await;
let user_a_uuid = create_user(rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(rsclient, USER_B_NAME).await;
login_with_user(rsclient, USER_A_NAME).await;
let response = rsclient
.idm_person_identify_user(
USER_B_NAME,
@ -158,12 +158,12 @@ async fn test_provide_code_response_code_failure_or_provide_code(rsclient: &Kani
// here we actually test the full idm flow by duplicating the server
#[kanidmd_testkit::test]
async fn test_full_identification_flow(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
setup_server(rsclient).await;
let user_a_uuid = create_user(rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(rsclient, USER_B_NAME).await;
//user A session
let valid_user_a_client = rsclient;
login_with_user(&valid_user_a_client, USER_A_NAME).await;
login_with_user(valid_user_a_client, USER_A_NAME).await;
//user B session
let valid_user_b_client = valid_user_a_client.new_session().unwrap();
login_with_user(&valid_user_b_client, USER_B_NAME).await;

View file

@ -76,10 +76,10 @@ async fn test_webdriver_user_login(rsclient: &KanidmClient) {
use fantoccini::Locator;
use kanidmd_testkit::*;
use std::time::Duration;
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
create_user_with_all_attrs(
&rsclient,
rsclient,
NOT_ADMIN_TEST_USERNAME,
Some(NOT_ADMIN_TEST_PASSWORD),
)
@ -89,7 +89,7 @@ async fn test_webdriver_user_login(rsclient: &KanidmClient) {
handle_error!(
c,
c.goto(&rsclient.get_url().to_string()).await,
c.goto(rsclient.get_url().to_string()).await,
"Couldn't get URL"
);
@ -207,7 +207,7 @@ async fn test_webdriver_user_login(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
async fn test_domain_reset_token_key(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
let token = rsclient.get_token().await.expect("No bearer token present");
@ -220,7 +220,7 @@ async fn test_domain_reset_token_key(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
async fn test_idm_domain_set_ldap_basedn(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
assert!(rsclient
.idm_domain_set_ldap_basedn("dc=krabsarekool,dc=example,dc=com")
.await
@ -233,7 +233,7 @@ async fn test_idm_domain_set_ldap_basedn(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
assert!(rsclient
.idm_domain_set_ldap_max_queryable_attrs(20)
.await
@ -247,7 +247,7 @@ async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
/// Checks that a built-in group idm_all_persons has the "builtin" class as expected.
async fn test_all_persons_has_builtin_class(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
let res = rsclient
.idm_group_get("idm_all_persons")
.await
@ -306,7 +306,7 @@ async fn test_all_persons_has_builtin_class(rsclient: &KanidmClient) {
/// Testing the CLI doing things.
async fn test_integration_with_assert_cmd(rsclient: KanidmClient) {
// setup the admin things
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
rsclient
.idm_person_account_primary_credential_set_password(
@ -334,13 +334,13 @@ async fn test_integration_with_assert_cmd(rsclient: KanidmClient) {
assert!(anon_whoami.status.success());
println!("Output: {:?}", anon_whoami);
test_cmd_admin(&token_cache_path, &rsclient, "login -D admin");
test_cmd_admin(&token_cache_path, rsclient, "login -D admin");
// login as idm_admin
test_cmd_idm_admin(&token_cache_path, &rsclient, "login -D idm_admin");
test_cmd_idm_admin(&token_cache_path, rsclient, "login -D idm_admin");
test_cmd_admin_split(
&token_cache_path,
&rsclient,
rsclient,
&[
"service-account",
"create",
@ -355,13 +355,13 @@ async fn test_integration_with_assert_cmd(rsclient: KanidmClient) {
test_cmd_admin(
&token_cache_path,
&rsclient,
rsclient,
&format!("service-account get -D admin {}", NOT_ADMIN_TEST_USERNAME),
);
// updating the display name
test_cmd_admin(
&token_cache_path,
&rsclient,
rsclient,
&format!(
"service-account update -D admin {} --displayname cheeseballs",
NOT_ADMIN_TEST_USERNAME
@ -370,7 +370,7 @@ async fn test_integration_with_assert_cmd(rsclient: KanidmClient) {
// updating the email
test_cmd_admin(
&token_cache_path,
&rsclient,
rsclient,
&format!(
"service-account update -D admin {} --mail foo@bar.com",
NOT_ADMIN_TEST_USERNAME
@ -380,7 +380,7 @@ async fn test_integration_with_assert_cmd(rsclient: KanidmClient) {
// checking the email was changed
let sad = test_cmd_admin(
&token_cache_path,
&rsclient,
rsclient,
&format!(
"service-account get -D admin -o json {}",
NOT_ADMIN_TEST_USERNAME

View file

@ -10,7 +10,7 @@ async fn test_v1_person_id_patch(rsclient: &KanidmClient) {
.await;
assert!(res.is_ok());
create_user(&rsclient, "foo", "foogroup").await;
create_user(rsclient, "foo", "foogroup").await;
let post_body = serde_json::json!({"attrs": { ATTR_MAIL : ["crab@example.com"]}});
@ -31,7 +31,7 @@ async fn test_v1_person_id_ssh_pubkeys_post(rsclient: &KanidmClient) {
.await;
assert!(res.is_ok());
create_user(&rsclient, "foo", "foogroup").await;
create_user(rsclient, "foo", "foogroup").await;
let post_body = serde_json::json!([
"ssh-key-tag-goes-here",

View file

@ -1366,7 +1366,7 @@ async fn setup_demo_account_password(
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_passkey(rsclient: &KanidmClient) {
let mut wa = setup_demo_account_passkey(&rsclient).await;
let mut wa = setup_demo_account_passkey(rsclient).await;
let res = rsclient
.auth_passkey_begin("demo_account")
@ -1690,7 +1690,7 @@ async fn test_server_user_auth_token_lifecycle(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
async fn test_server_user_auth_reauthentication(rsclient: &KanidmClient) {
let mut wa = setup_demo_account_passkey(&rsclient).await;
let mut wa = setup_demo_account_passkey(rsclient).await;
let res = rsclient
.auth_passkey_begin("demo_account")
@ -1869,12 +1869,12 @@ async fn start_password_session(
#[kanidmd_testkit::test]
async fn test_server_user_auth_unprivileged(rsclient: &KanidmClient) {
let (account_name, account_pass) = setup_demo_account_password(&rsclient)
let (account_name, account_pass) = setup_demo_account_password(rsclient)
.await
.expect("Failed to setup demo_account");
let uat = start_password_session(
&rsclient,
rsclient,
account_name.as_str(),
account_pass.as_str(),
false,
@ -1892,18 +1892,13 @@ async fn test_server_user_auth_unprivileged(rsclient: &KanidmClient) {
#[kanidmd_testkit::test]
async fn test_server_user_auth_privileged_shortcut(rsclient: &KanidmClient) {
let (account_name, account_pass) = setup_demo_account_password(&rsclient)
let (account_name, account_pass) = setup_demo_account_password(rsclient)
.await
.expect("Failed to setup demo_account");
let uat = start_password_session(
&rsclient,
account_name.as_str(),
account_pass.as_str(),
true,
)
.await
.expect("Failed to start session");
let uat = start_password_session(rsclient, account_name.as_str(), account_pass.as_str(), true)
.await
.expect("Failed to start session");
match uat.purpose {
UatPurpose::ReadOnly => panic!("Unexpected uat purpose"),

View file

@ -6,10 +6,10 @@ use kanidmd_testkit::*;
async fn account_id_unix_token(rsclient: &KanidmClient) {
login_put_admin_idm_admins(rsclient).await;
create_user(&rsclient, "group_manager", "idm_group_manage_priv").await;
create_user(rsclient, "group_manager", "idm_group_manage_priv").await;
// create test user without creating new groups
create_user(&rsclient, NOT_ADMIN_TEST_USERNAME, NAME_IDM_ADMINS).await;
login_account(&rsclient, "group_manager").await;
create_user(rsclient, NOT_ADMIN_TEST_USERNAME, NAME_IDM_ADMINS).await;
login_account(rsclient, "group_manager").await;
let response = rsclient
.idm_account_unix_token_get(NOT_ADMIN_TEST_USERNAME)
@ -32,7 +32,7 @@ async fn account_id_unix_token(rsclient: &KanidmClient) {
assert!(format!("{:?}", val).contains("400"));
}
login_put_admin_idm_admins(&rsclient).await;
login_put_admin_idm_admins(rsclient).await;
rsclient
.idm_person_account_unix_extend(NOT_ADMIN_TEST_USERNAME, None, None)

View file

@ -5,6 +5,7 @@ use crate::{handle_client_error, PwBadlistOpt};
use std::fs::File;
use std::io::Read;
use tokio::task;
use zxcvbn::Score;
const CHUNK_SIZE: usize = 1000;
@ -67,10 +68,6 @@ impl PwBadlistOpt {
info!("Have {} unique passwords to process", pwset.len());
// Break the list into chunks per thread availability
// let par_count = thread::available_parallelism()
// .expect("Failed to determine available parallelism")
// .get();
let task_handles: Vec<_> = pwset
.chunks(CHUNK_SIZE)
.map(|chunk| chunk.to_vec())
@ -82,18 +79,7 @@ impl PwBadlistOpt {
if v.len() < 10 {
return false;
}
match zxcvbn::zxcvbn(v.as_str(), &[]) {
Ok(r) => r.score() >= 4,
Err(e) => {
error!(
"zxcvbn unable to process '{}' - {:?}",
v.as_str(),
e
);
error!("adding to badlist anyway ...");
true
}
}
zxcvbn::zxcvbn(v.as_str(), &[]).score() >= Score::Four
})
.map(|s| s.to_string())
.collect::<Vec<_>>();

View file

@ -8,4 +8,6 @@ pub enum Error {
Interrupt,
Crossbeam,
InvalidState,
#[allow(dead_code)]
RandomNumber(String),
}

View file

@ -4,8 +4,9 @@ use crate::model::ActorRole;
use crate::profile::Profile;
use crate::state::{Credential, Flag, Group, GroupName, Person, PreflightState, State};
use hashbrown::HashMap;
use rand::distributions::{Alphanumeric, DistString, Uniform};
use rand::seq::{index, SliceRandom};
use rand::distr::{Alphanumeric, SampleString, Uniform};
use rand::seq::{index, IndexedRandom};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
@ -171,7 +172,8 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result<St
let baseline = persons.len() / 3;
let inverse = persons.len() - baseline;
// Randomly add extra from the inverse
let extra = Uniform::new(0, inverse);
let extra =
Uniform::new(0, inverse).map_err(|err| Error::RandomNumber(err.to_string()))?;
baseline + seeded_rng.sample(extra)
}
};

View file

@ -27,7 +27,7 @@ impl ActorBasic {
pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
let max_backoff_time_in_ms = 2 * warmup_time_ms / 3;
let randomised_backoff_time =
Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
ActorBasic {
state: State::Unauthenticated,
randomised_backoff_time,

View file

@ -76,7 +76,7 @@ impl ActorLatencyMeasurer {
let max_backoff_time_in_ms = 2 * warmup_time_ms / 3;
let randomised_backoff_time =
Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
Ok(ActorLatencyMeasurer {
state: State::Unauthenticated,
randomised_backoff_time,

View file

@ -25,7 +25,7 @@ impl ActorReader {
pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
let max_backoff_time_in_ms = warmup_time_ms - 1000;
let randomised_backoff_time =
Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
ActorReader {
state: State::Unauthenticated,
randomised_backoff_time,

View file

@ -26,7 +26,7 @@ impl ActorWriter {
pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
let max_backoff_time_in_ms = 2 * warmup_time_ms / 3;
let randomised_backoff_time =
Duration::from_millis(cha_rng.gen_range(0..max_backoff_time_in_ms));
Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
ActorWriter {
state: State::Unauthenticated,
randomised_backoff_time,

View file

@ -1,6 +1,6 @@
use crate::error::Error;
use crate::state::{GroupName, Model};
use rand::{thread_rng, Rng};
use rand::{rng, Rng};
use serde::de::{value, IntoDeserializer};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
@ -200,8 +200,8 @@ impl ProfileBuilder {
} = self;
let seed: u64 = seed.unwrap_or_else(|| {
let mut rng = thread_rng();
rng.gen()
let mut rng = rng();
rng.random()
});
//TODO: Allow to specify group properties from the CLI

View file

@ -187,7 +187,7 @@ pub async fn execute(state: State, control_rx: broadcast::Receiver<Signal>) -> R
})
})
.collect::<Result<Vec<_>, _>>()?;
let main_client_index = seeded_rng.gen_range(0..cloned_clients.len());
let main_client_index = seeded_rng.random_range(0..cloned_clients.len());
let main_client = cloned_clients.remove(main_client_index);
//note that cloned_clients now contains all other clients except the first one

View file

@ -694,7 +694,7 @@ mod tests {
for file in PathBuf::from(&examples_dir)
.canonicalize()
.expect(&format!("Can't find examples dir at {}", examples_dir))
.unwrap_or_else(|_| panic!("Can't find examples dir at {}", examples_dir))
.read_dir()
.expect("Can't read examples dir!")
{

View file

@ -71,32 +71,32 @@ impl RequestOptions {
fn nss_fallback_unavail() {
let req_opt = RequestOptions::fallback_unavail();
let Response::Unavail = core::get_all_user_entries(req_opt) else {
unreachable!();
panic!("unrecoverable");
};
let req_opt = RequestOptions::fallback_unavail();
let Response::Unavail = core::get_user_entry_by_uid(0, req_opt) else {
unreachable!();
panic!("unrecoverable");
};
let req_opt = RequestOptions::fallback_unavail();
let Response::Unavail = core::get_user_entry_by_name("root".to_string(), req_opt) else {
unreachable!();
panic!("unrecoverable");
};
let req_opt = RequestOptions::fallback_unavail();
let Response::Unavail = core::get_all_group_entries(req_opt) else {
unreachable!();
panic!("unrecoverable");
};
let req_opt = RequestOptions::fallback_unavail();
let Response::Unavail = core::get_group_entry_by_gid(0, req_opt) else {
unreachable!();
panic!("unrecoverable");
};
let req_opt = RequestOptions::fallback_unavail();
let Response::Unavail = core::get_group_entry_by_name("root".to_string(), req_opt) else {
unreachable!();
panic!("unrecoverable");
};
}
@ -105,7 +105,7 @@ fn nss_fallback_all_user_entries() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(users) = core::get_all_user_entries(req_opt) else {
unreachable!();
panic!("Failed to get all user entries");
};
assert_eq!(users.len(), 3);
@ -129,7 +129,7 @@ fn nss_fallback_all_user_entries() {
fn nss_fallback_user_entry_by_uid() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(user) = core::get_user_entry_by_uid(0, req_opt) else {
unreachable!();
panic!("Failed to get user entry by uid");
};
assert_eq!(user.name, "root");
@ -139,7 +139,7 @@ fn nss_fallback_user_entry_by_uid() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(user) = core::get_user_entry_by_uid(1000, req_opt) else {
unreachable!();
panic!("Failed to get user entry by uid");
};
assert_eq!(user.name, "tobias");
@ -149,7 +149,7 @@ fn nss_fallback_user_entry_by_uid() {
let req_opt = RequestOptions::fallback_fixture();
let Response::NotFound = core::get_user_entry_by_uid(10, req_opt) else {
unreachable!();
panic!("Wrong result");
};
}
@ -157,7 +157,7 @@ fn nss_fallback_user_entry_by_uid() {
fn nss_fallback_user_entry_by_name() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(user) = core::get_user_entry_by_name("root".to_string(), req_opt) else {
unreachable!();
panic!("Failed to get user entry by name");
};
assert_eq!(user.name, "root");
@ -167,7 +167,7 @@ fn nss_fallback_user_entry_by_name() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(user) = core::get_user_entry_by_name("ellie".to_string(), req_opt) else {
unreachable!();
panic!("Failed to get user entry by name");
};
assert_eq!(user.name, "ellie");
@ -177,7 +177,7 @@ fn nss_fallback_user_entry_by_name() {
let req_opt = RequestOptions::fallback_fixture();
let Response::NotFound = core::get_user_entry_by_name("william".to_string(), req_opt) else {
unreachable!();
panic!("Wrong result");
};
}
@ -186,7 +186,7 @@ fn nss_fallback_all_group_entries() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(groups) = core::get_all_group_entries(req_opt) else {
unreachable!();
panic!("Failed to get all group entries");
};
assert_eq!(groups.len(), 3);
@ -207,7 +207,7 @@ fn nss_fallback_all_group_entries() {
fn nss_fallback_group_entry_by_uid() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(group) = core::get_group_entry_by_gid(0, req_opt) else {
unreachable!();
panic!("Failed to get group entry by gid");
};
assert_eq!(group.name, "root");
@ -216,7 +216,7 @@ fn nss_fallback_group_entry_by_uid() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(group) = core::get_group_entry_by_gid(1000, req_opt) else {
unreachable!();
panic!("Failed to get group entry by gid");
};
assert_eq!(group.name, "tobias");
@ -225,7 +225,7 @@ fn nss_fallback_group_entry_by_uid() {
let req_opt = RequestOptions::fallback_fixture();
let Response::NotFound = core::get_group_entry_by_gid(10, req_opt) else {
unreachable!();
panic!("Wrong result");
};
}
@ -234,7 +234,7 @@ fn nss_fallback_group_entry_by_name() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(group) = core::get_group_entry_by_name("root".to_string(), req_opt)
else {
unreachable!();
panic!("Failed to get group entry by name");
};
assert_eq!(group.name, "root");
@ -244,7 +244,7 @@ fn nss_fallback_group_entry_by_name() {
let req_opt = RequestOptions::fallback_fixture();
let Response::Success(group) = core::get_group_entry_by_name("ellie".to_string(), req_opt)
else {
unreachable!();
panic!("Failed to get group entry by name");
};
assert_eq!(group.name, "ellie");
@ -253,6 +253,6 @@ fn nss_fallback_group_entry_by_name() {
let req_opt = RequestOptions::fallback_fixture();
let Response::NotFound = core::get_group_entry_by_name("william".to_string(), req_opt) else {
unreachable!();
panic!("Wrong result");
};
}

View file

@ -121,23 +121,17 @@ impl PamHandler for TestHandler {
/// Display a message to the user.
fn message(&self, _prompt: &str) -> PamResult<()> {
let mut q = self.response_queue.lock().unwrap();
match q.pop_front() {
e => {
eprintln!("{:?}", e);
panic!("Invalid event transition");
}
}
let e = q.pop_front();
eprintln!("{:?}", e);
panic!("Invalid event transition message");
}
/// Display a device grant request to the user.
fn message_device_grant(&self, _data: &DeviceAuthorizationResponse) -> PamResult<()> {
let mut q = self.response_queue.lock().unwrap();
match q.pop_front() {
e => {
eprintln!("{:?}", e);
panic!("Invalid event transition");
}
}
let e = q.pop_front();
eprintln!("{:?}", e);
panic!("Invalid event transition message_device_grant");
}
/// Request a password from the user.
@ -154,22 +148,16 @@ impl PamHandler for TestHandler {
fn prompt_for_pin(&self, _msg: Option<&str>) -> PamResult<Option<String>> {
let mut q = self.response_queue.lock().unwrap();
match q.pop_front() {
e => {
eprintln!("{:?}", e);
panic!("Invalid event transition");
}
}
let e = q.pop_front();
eprintln!("{:?}", e);
panic!("Invalid event transition prompt_for_pin");
}
fn prompt_for_mfacode(&self) -> PamResult<Option<String>> {
let mut q = self.response_queue.lock().unwrap();
match q.pop_front() {
e => {
eprintln!("{:?}", e);
panic!("Invalid event transition");
}
}
let mut q = self.response_queue.lock().expect("Failed to lock mutex");
let e = q.pop_front();
eprintln!("{:?}", e);
panic!("Invalid event transition prompt_for_mfacode");
}
}

View file

@ -1189,7 +1189,7 @@ async fn test_cache_extend_group_members() {
assert!(groups.iter().any(|group| {
group.name == "extensible_group"
&& group.members.as_slice()
== &[
== [
"local_account".to_string(),
"testaccount1@idm.example.com".to_string(),
]