Subaddressing and catch-all addresses support.

This commit is contained in:
Mauro D
2023-06-08 14:54:09 +00:00
parent 891d39940d
commit 1ce0cee7e6
16 changed files with 280 additions and 65 deletions

View File

@@ -79,6 +79,15 @@ watchconfig = true
diskQuota = [500000]
userPassword = ["$2y$05$bvIG6Nmid91Mu9RcmmWZfO5HJIMCT8riNW0hEp8f6/FuA2/mHZFpe"]
[[users]]
name = "robert"
sn = "@catchall.org"
mail = "robert@catchall.org"
uidnumber = 7
[[users.customattributes]]
principalName = ["Robect Foobar"]
userPassword = ["nopass"]
[[users]]
name = "serviceuser"
mail = "serviceuser@example.org"

View File

@@ -147,10 +147,22 @@ async fn ldap_directory() {
handle.ids_by_email("jane@example.org").await.unwrap(),
vec![3],
);
compare_sorted(
handle.ids_by_email("jane+alias@example.org").await.unwrap(),
vec![3],
);
compare_sorted(
handle.ids_by_email("info@example.org").await.unwrap(),
vec![2, 3, 4],
);
compare_sorted(
handle.ids_by_email("info+alias@example.org").await.unwrap(),
vec![2, 3, 4],
);
compare_sorted(
handle.ids_by_email("unknown@example.org").await.unwrap(),
Vec::<u32>::new(),
);
// Domain validation
assert!(handle.is_local_domain("example.org").await.unwrap());
@@ -159,6 +171,9 @@ async fn ldap_directory() {
// RCPT TO
assert!(handle.rcpt("jane@example.org").await.unwrap());
assert!(handle.rcpt("info@example.org").await.unwrap());
assert!(handle.rcpt("jane+alias@example.org").await.unwrap());
assert!(handle.rcpt("info+alias@example.org").await.unwrap());
assert!(handle.rcpt("random_user@catchall.org").await.unwrap());
assert!(!handle.rcpt("invalid@example.org").await.unwrap());
// VRFY
@@ -170,6 +185,10 @@ async fn ldap_directory() {
handle.vrfy("john").await.unwrap(),
vec!["john@example.org".to_string()],
);
compare_sorted(
handle.vrfy("jane+alias@example").await.unwrap(),
vec!["jane@example.org".to_string()],
);
compare_sorted(handle.vrfy("info").await.unwrap(), Vec::<String>::new());
compare_sorted(handle.vrfy("invalid").await.unwrap(), Vec::<String>::new());

View File

@@ -15,6 +15,10 @@ const CONFIG: &str = r#"
type = "sql"
address = "sqlite::memory:"
[directory."sql".options]
catch-all = true
subaddressing = true
[directory."sql".pool]
max-connections = 1
@@ -50,6 +54,10 @@ base-dn = "dc=example,dc=org"
dn = "cn=serviceuser,ou=svcaccts,dc=example,dc=org"
secret = "mysecret"
[directory."ldap".options]
catch-all = true
subaddressing = true
[directory."ldap".filter]
login = "(&(objectClass=posixAccount)(accountStatus=active)(cn=?))"
name = "(&(|(objectClass=posixAccount)(objectClass=posixGroup))(cn=?))"
@@ -111,6 +119,10 @@ ttl = {positive = '10s', negative = '5s'}
[directory."local"]
type = "memory"
[directory."local".options]
catch-all = true
subaddressing = true
[[directory."local".users]]
name = "john"
description = "John Doe"

View File

@@ -53,6 +53,11 @@ async fn sql_directory() {
link_test_address(handle.as_ref(), "jane", "info@example.org", "list").await;
link_test_address(handle.as_ref(), "bill", "info@example.org", "list").await;
// Add catch-all user
create_test_user(handle.as_ref(), "robert", "abcde", "Robert Foobar").await;
link_test_address(handle.as_ref(), "robert", "robert@catchall.org", "primary").await;
link_test_address(handle.as_ref(), "robert", "@catchall.org", "alias").await;
// Test authentication
assert_eq!(
handle
@@ -177,6 +182,22 @@ async fn sql_directory() {
handle.ids_by_email("info@example.org").await.unwrap(),
vec![2, 3, 4]
);
assert_eq!(
handle.ids_by_email("jane+alias@example.org").await.unwrap(),
vec![3]
);
assert_eq!(
handle.ids_by_email("info+alias@example.org").await.unwrap(),
vec![2, 3, 4]
);
assert_eq!(
handle.ids_by_email("unknown@example.org").await.unwrap(),
Vec::<u32>::new()
);
assert_eq!(
handle.ids_by_email("anything@catchall.org").await.unwrap(),
vec![7]
);
// Domain validation
assert!(handle.is_local_domain("example.org").await.unwrap());
@@ -185,6 +206,9 @@ async fn sql_directory() {
// RCPT TO
assert!(handle.rcpt("jane@example.org").await.unwrap());
assert!(handle.rcpt("info@example.org").await.unwrap());
assert!(handle.rcpt("jane+alias@example.org").await.unwrap());
assert!(handle.rcpt("info+alias@example.org").await.unwrap());
assert!(handle.rcpt("random_user@catchall.org").await.unwrap());
assert!(!handle.rcpt("invalid@example.org").await.unwrap());
// VRFY
@@ -196,6 +220,10 @@ async fn sql_directory() {
handle.vrfy("john").await.unwrap(),
vec!["john@example.org".to_string()]
);
assert_eq!(
handle.vrfy("jane+alias@example").await.unwrap(),
vec!["jane@example.org".to_string()]
);
assert_eq!(handle.vrfy("info").await.unwrap(), Vec::<String>::new());
assert_eq!(handle.vrfy("invalid").await.unwrap(), Vec::<String>::new());

View File

@@ -228,7 +228,7 @@ pub async fn jmap_tests() {
let delete = true;
let mut params = init_jmap_tests(delete).await;
/*email_query::test(params.server.clone(), &mut params.client, delete).await;
email_query::test(params.server.clone(), &mut params.client, delete).await;
email_get::test(params.server.clone(), &mut params.client).await;
email_set::test(params.server.clone(), &mut params.client).await;
email_parse::test(params.server.clone(), &mut params.client).await;
@@ -249,7 +249,7 @@ pub async fn jmap_tests() {
vacation_response::test(params.server.clone(), &mut params.client).await;
email_submission::test(params.server.clone(), &mut params.client).await;
websocket::test(params.server.clone(), &mut params.client).await;
quota::test(params.server.clone(), &mut params.client).await;*/
quota::test(params.server.clone(), &mut params.client).await;
stress_test::test(params.server.clone(), params.client).await;
if delete {