Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
233 lines
6.6 KiB
Rust
233 lines
6.6 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use crate::{
|
|
directory::ldap::ldap_test_directory,
|
|
utils::{server::TestServerBuilder, smtp::SmtpConnection},
|
|
};
|
|
use ahash::AHashMap;
|
|
use common::auth::{AuthRequest, RECOVERY_ADMIN_ID};
|
|
use email::cache::MessageCacheFetch;
|
|
use registry::schema::structs::{Account, AccountSettings, Directory};
|
|
use std::net::IpAddr;
|
|
use types::id::Id;
|
|
|
|
pub async fn test() {
|
|
println!("Running directory integration tests...");
|
|
crate::utils::containers::ensure_openldap().await;
|
|
let test = TestServerBuilder::new("directory_integration_test")
|
|
.await
|
|
.with_default_listeners()
|
|
.await
|
|
.with_object(Directory::Ldap(ldap_test_directory()))
|
|
.await
|
|
.build()
|
|
.await;
|
|
let admin = test.account("admin");
|
|
admin.mta_no_auth().await;
|
|
admin.mta_disable_spam_filter().await;
|
|
admin.reload_settings().await;
|
|
|
|
// Test account creation by login
|
|
let account = crate::utils::account::Account::new(
|
|
"[email protected]",
|
|
"this is John's LDAP password",
|
|
&[],
|
|
"",
|
|
Id::from(u32::MAX),
|
|
);
|
|
assert_eq!(
|
|
account
|
|
.registry_get::<AccountSettings>(Id::singleton())
|
|
.await
|
|
.description
|
|
.as_deref(),
|
|
Some("John Doe")
|
|
);
|
|
|
|
// Test account creation by rcpt
|
|
let mut lmtp = SmtpConnection::connect().await;
|
|
for rcpt in [
|
|
"[email protected]",
|
|
"[email protected]",
|
|
"[email protected]",
|
|
"[email protected]",
|
|
"[email protected]",
|
|
] {
|
|
lmtp.ingest(
|
|
"[email protected]",
|
|
&[rcpt],
|
|
&TEST_EMAIL.replace("$RCPT", rcpt),
|
|
)
|
|
.await;
|
|
}
|
|
|
|
// Fetch all accounts
|
|
let mut accounts = admin
|
|
.registry_get_all::<Account>()
|
|
.await
|
|
.into_iter()
|
|
.map(|(id, account)| {
|
|
(
|
|
match &account {
|
|
Account::User(user_account) => user_account.name.clone(),
|
|
Account::Group(group_account) => group_account.name.clone(),
|
|
},
|
|
(account, id),
|
|
)
|
|
})
|
|
.collect::<AHashMap<_, _>>();
|
|
assert_eq!(accounts.len(), 5, "Got: {accounts:#?}");
|
|
|
|
// Validate accounts
|
|
for (name, description, secret, groups, aliases) in [
|
|
(
|
|
"john.doe",
|
|
"John Doe",
|
|
"$app$8958830913002348890$",
|
|
&["sales"][..],
|
|
&["john"][..],
|
|
),
|
|
(
|
|
"jane.smith",
|
|
"Jane Smith",
|
|
"$app$4096614298472586996$",
|
|
&["sales", "corporate"][..],
|
|
&[][..],
|
|
),
|
|
(
|
|
"bill.foobar",
|
|
"Bill Foobar",
|
|
"",
|
|
&["corporate"][..],
|
|
&["bill"][..],
|
|
),
|
|
] {
|
|
let (account, id) = accounts
|
|
.remove(name)
|
|
.map(|(account, id)| (account.into_user().unwrap(), id))
|
|
.unwrap();
|
|
assert_eq!(account.description.as_deref(), Some(description));
|
|
if !secret.is_empty() {
|
|
assert_eq!(
|
|
test.server
|
|
.registry()
|
|
.object::<Account>(id)
|
|
.await
|
|
.unwrap()
|
|
.unwrap()
|
|
.into_user()
|
|
.unwrap()
|
|
.credentials
|
|
.values()
|
|
.next()
|
|
.and_then(|v| v.as_main_credential())
|
|
.map(|v| v.secret.as_str()),
|
|
Some(secret)
|
|
);
|
|
}
|
|
for group in groups {
|
|
let id = accounts.get(*group).unwrap().1;
|
|
assert!(
|
|
account
|
|
.member_group_ids
|
|
.iter()
|
|
.any(|group_id| group_id == &id),
|
|
"Account {name} is not a member of group {group}"
|
|
);
|
|
}
|
|
for alias in aliases {
|
|
assert!(
|
|
account
|
|
.aliases
|
|
.iter()
|
|
.any(|account_alias| account_alias.name == *alias),
|
|
"Account {name} does not have alias {alias}"
|
|
);
|
|
}
|
|
assert_eq!(
|
|
test.server
|
|
.get_cached_messages(id.document_id())
|
|
.await
|
|
.unwrap()
|
|
.emails
|
|
.index
|
|
.len(),
|
|
1
|
|
);
|
|
}
|
|
|
|
// Validate groups
|
|
for (name, description, aliases) in [
|
|
("sales", "sales", &[][..]),
|
|
("corporate", "corporate", &["everyone"][..]),
|
|
] {
|
|
let (account, id) = accounts
|
|
.remove(name)
|
|
.map(|(account, id)| (account.into_group().unwrap(), id))
|
|
.unwrap();
|
|
assert_eq!(account.description.as_deref(), Some(description));
|
|
for alias in aliases {
|
|
assert!(
|
|
account
|
|
.aliases
|
|
.iter()
|
|
.any(|account_alias| account_alias.name == *alias),
|
|
"Group {name} does not have alias {alias}"
|
|
);
|
|
}
|
|
assert_eq!(
|
|
test.server
|
|
.get_cached_messages(id.document_id())
|
|
.await
|
|
.unwrap()
|
|
.emails
|
|
.index
|
|
.len(),
|
|
1
|
|
);
|
|
}
|
|
|
|
// Test recovery admin impersonation of an account that has not logged in before
|
|
assert!(
|
|
test.server
|
|
.account_id_from_email("[email protected]", false)
|
|
.await
|
|
.unwrap()
|
|
.is_none(),
|
|
"Account [email protected] exists before impersonation"
|
|
);
|
|
let access_token = test
|
|
.server
|
|
.authenticate(&AuthRequest::from_plain(
|
|
"[email protected]%admin",
|
|
admin.secret(),
|
|
0,
|
|
IpAddr::from([127, 0, 0, 1]),
|
|
))
|
|
.await
|
|
.unwrap_or_else(|err| panic!("Failed to impersonate [email protected]: {err:?}"));
|
|
assert_ne!(access_token.account_id(), RECOVERY_ADMIN_ID);
|
|
assert_eq!(
|
|
test.server
|
|
.registry()
|
|
.object::<Account>(access_token.account_id().into())
|
|
.await
|
|
.unwrap()
|
|
.and_then(|account| account.into_user())
|
|
.map(|account| account.name),
|
|
Some("multi.mail".to_string())
|
|
);
|
|
}
|
|
|
|
const TEST_EMAIL: &str = r#"From: [email protected]
|
|
To: $RCPT
|
|
Subject: TPS Report for $RCPT
|
|
|
|
I'm going to need those TPS reports ASAP. So, if you could do that, that'd be great.
|
|
|
|
"#;
|