diff --git a/flake.nix b/flake.nix index 0deb9c8..54d747e 100644 --- a/flake.nix +++ b/flake.nix @@ -35,6 +35,7 @@ "external" "clamav" "multiple" + "ldap" ]; genTest = testName: release: { "name"= "${testName}-${builtins.replaceStrings ["."] ["_"] release.name}"; diff --git a/tests/ldap.nix b/tests/ldap.nix new file mode 100644 index 0000000..6077543 --- /dev/null +++ b/tests/ldap.nix @@ -0,0 +1,172 @@ +{ pkgs ? import {} +, ... +}: + +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" + ])) + ''; +}