mirror of
https://gitlab.com/simple-nixos-mailserver/nixos-mailserver.git
synced 2024-12-27 15:36:12 +01:00
8b03ae5701
Sets up a declaratively configured OpenLDAP instance with users alice and bob. They each own one email address, First we test that postfix can communicate with LDAP and do the expected lookups using the defined maps. Then we use doveadm to make sure it can look up the two accounts. Next we check the binding between account and mail address, by logging in as alice and trying to send from bob@example.com, which alice is not allowed to do. We expect postfix to reject the sender address here. Finally we check mail delivery between alice and bob. Alice tries to send a mail from alice@example.com to bob@example.com and bob then checks whether it arrived in their mailbox.
172 lines
4.7 KiB
Nix
172 lines
4.7 KiB
Nix
{ pkgs ? import <nixpkgs> {}
|
|
, ...
|
|
}:
|
|
|
|
let
|
|
bindPassword = "unsafegibberish";
|
|
alicePassword = "testalice";
|
|
bobPassword = "testbob";
|
|
in
|
|
pkgs.nixosTest {
|
|
name = "ldap";
|
|
nodes = {
|
|
machine = { config, pkgs, ... }: {
|
|
imports = [
|
|
./../default.nix
|
|
./lib/config.nix
|
|
];
|
|
|
|
virtualisation.memorySize = 1024;
|
|
|
|
environment.systemPackages = [
|
|
(pkgs.writeScriptBin "mail-check" ''
|
|
${pkgs.python3}/bin/python ${../scripts/mail-check.py} $@
|
|
'')];
|
|
|
|
services.openldap = {
|
|
enable = true;
|
|
settings = {
|
|
children = {
|
|
"cn=schema".includes = [
|
|
"${pkgs.openldap}/etc/schema/core.ldif"
|
|
"${pkgs.openldap}/etc/schema/cosine.ldif"
|
|
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
|
|
"${pkgs.openldap}/etc/schema/nis.ldif"
|
|
];
|
|
"olcDatabase={1}mdb" = {
|
|
attrs = {
|
|
objectClass = [
|
|
"olcDatabaseConfig"
|
|
"olcMdbConfig"
|
|
];
|
|
olcDatabase = "{1}mdb";
|
|
olcDbDirectory = "/var/lib/openldap";
|
|
olcSuffix = "dc=example";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
declarativeContents."dc=example" = ''
|
|
dn: dc=example
|
|
objectClass: domain
|
|
dc: example
|
|
|
|
dn: cn=mail,dc=example
|
|
objectClass: organizationalRole
|
|
objectClass: simpleSecurityObject
|
|
objectClass: top
|
|
cn: mail
|
|
userPassword: ${bindPassword}
|
|
|
|
dn: ou=users,dc=example
|
|
objectClass: organizationalUnit
|
|
ou: users
|
|
|
|
dn: cn=alice,ou=users,dc=example
|
|
objectClass: inetOrgPerson
|
|
cn: alice
|
|
sn: Foo
|
|
mail: alice@example.com
|
|
userPassword: ${alicePassword}
|
|
|
|
dn: cn=bob,ou=users,dc=example
|
|
objectClass: inetOrgPerson
|
|
cn: bob
|
|
sn: Bar
|
|
mail: bob@example.com
|
|
userPassword: ${bobPassword}
|
|
'';
|
|
};
|
|
|
|
mailserver = {
|
|
enable = true;
|
|
fqdn = "mail.example.com";
|
|
domains = [ "example.com" ];
|
|
localDnsResolver = false;
|
|
|
|
ldap = {
|
|
enable = true;
|
|
uris = [
|
|
"ldap://"
|
|
];
|
|
bind = {
|
|
dn = "cn=mail,dc=example";
|
|
password = bindPassword;
|
|
};
|
|
searchBase = "ou=users,dc=example";
|
|
searchScope = "sub";
|
|
};
|
|
|
|
vmailGroupName = "vmail";
|
|
vmailUID = 5000;
|
|
|
|
enableImap = false;
|
|
};
|
|
};
|
|
};
|
|
testScript = ''
|
|
import sys
|
|
|
|
from glob import glob
|
|
|
|
machine.start()
|
|
machine.wait_for_unit("multi-user.target")
|
|
|
|
def test_lookup(map, key, expected):
|
|
path = glob(f"/nix/store/*-{map}")[0]
|
|
value = machine.succeed(f"postmap -q alice@example.com ldap:{path}").rstrip()
|
|
try:
|
|
assert value == expected
|
|
except AssertionError:
|
|
print(f"Expected {map} lookup for key '{key}' to return '{expected}, but got '{value}'", file=sys.stderr)
|
|
raise
|
|
|
|
|
|
with subtest("Test postmap lookups"):
|
|
test_lookup("ldap-virtual-mailbox-map.cf", "alice@example.com", "alice")
|
|
test_lookup("ldap-sender-login-map.cf", "alice", "alice")
|
|
|
|
test_lookup("ldap-virtual-mailbox-map.cf", "bob@example.com", "alice")
|
|
test_lookup("ldap-sender-login-map.cf", "bob", "alice")
|
|
|
|
with subtest("Test doveadm lookups"):
|
|
out = machine.succeed("doveadm user -u alice")
|
|
machine.log(out)
|
|
|
|
out = machine.succeed("doveadm user -u bob")
|
|
machine.log(out)
|
|
|
|
with subtest("Test account/mail address binding"):
|
|
machine.fail(" ".join([
|
|
"mail-check send-and-read",
|
|
"--smtp-port 587",
|
|
"--smtp-starttls",
|
|
"--smtp-host localhost",
|
|
"--smtp-username alice",
|
|
"--imap-host localhost",
|
|
"--imap-username bob",
|
|
"--from-addr bob@example.com",
|
|
"--to-addr aliceb@example.com",
|
|
"--src-password-file <(echo '${alicePassword}')",
|
|
"--dst-password-file <(echo '${bobPassword}')",
|
|
"--ignore-dkim-spf"
|
|
]))
|
|
machine.succeed("journalctl -u postfix | grep -q 'Sender address rejected: not owned by user alice'")
|
|
|
|
with subtest("Test mail delivery"):
|
|
machine.succeed(" ".join([
|
|
"mail-check send-and-read",
|
|
"--smtp-port 587",
|
|
"--smtp-starttls",
|
|
"--smtp-host localhost",
|
|
"--smtp-username alice",
|
|
"--imap-host localhost",
|
|
"--imap-username bob",
|
|
"--from-addr alice@example.com",
|
|
"--to-addr bob@example.com",
|
|
"--src-password-file <(echo '${alicePassword}')",
|
|
"--dst-password-file <(echo '${bobPassword}')",
|
|
"--ignore-dkim-spf"
|
|
]))
|
|
'';
|
|
}
|