From 3ec1fb202d710d00985c4e7a7c5d0fe6efab9ffe Mon Sep 17 00:00:00 2001 From: Dennis Stumm Date: Sun, 30 Oct 2016 14:11:36 +0100 Subject: [PATCH] Add ldap auth for postfix and dovecot (#352) * Add ldap support for postfix and dovecot * Add SASLAUTHD * Update README.md * Add necessary packages to dockerfile * Add config files for ldap * Add tests for ldap auth --- Dockerfile | 6 + Makefile | 29 +++- README.md | 89 +++++++++++- config/dovecot-ldap.conf.ext | 10 ++ config/postfix-ldap-aliases.cf | 8 ++ config/postfix-ldap-groups.cf | 8 ++ config/postfix-ldap-users.cf | 8 ++ target/start-mailserver.sh | 132 ++++++++++++++++-- test/auth/imap-ldap-auth.txt | 2 + test/auth/sasl-ldap-smtp-auth.txt | 5 + test/config/dovecot-ldap.conf.ext | 10 ++ test/config/postfix-ldap-aliases.cf | 8 ++ test/config/postfix-ldap-groups.cf | 8 ++ test/config/postfix-ldap-users.cf | 8 ++ test/docker-openldap/Dockerfile | 5 + .../bootstrap/ldif/01_mail-tree.ldif | 5 + .../bootstrap/ldif/02_user-email.ldif | 25 ++++ .../bootstrap/schema/mmc/postfix-book.schema | 70 ++++++++++ test/email-templates/test-email.txt | 3 + test/tests.bats | 47 +++++++ 20 files changed, 468 insertions(+), 18 deletions(-) create mode 100644 config/dovecot-ldap.conf.ext create mode 100644 config/postfix-ldap-aliases.cf create mode 100644 config/postfix-ldap-groups.cf create mode 100644 config/postfix-ldap-users.cf create mode 100644 test/auth/imap-ldap-auth.txt create mode 100644 test/auth/sasl-ldap-smtp-auth.txt create mode 100644 test/config/dovecot-ldap.conf.ext create mode 100644 test/config/postfix-ldap-aliases.cf create mode 100644 test/config/postfix-ldap-groups.cf create mode 100644 test/config/postfix-ldap-users.cf create mode 100644 test/docker-openldap/Dockerfile create mode 100644 test/docker-openldap/bootstrap/ldif/01_mail-tree.ldif create mode 100644 test/docker-openldap/bootstrap/ldif/02_user-email.ldif create mode 100644 test/docker-openldap/bootstrap/schema/mmc/postfix-book.schema create mode 100644 test/email-templates/test-email.txt diff --git a/Dockerfile b/Dockerfile index 267c86d4..43563ccd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update -q --fix-missing && \ curl \ dovecot-core \ dovecot-imapd \ + dovecot-ldap \ dovecot-lmtpd \ dovecot-managesieved \ dovecot-pop3d \ @@ -32,9 +33,11 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update -q --fix-missing && \ opendmarc \ p7zip \ postfix \ + postfix-ldap \ pyzor \ razor \ rsyslog \ + sasl2-bin \ spamassassin \ unzip \ && \ @@ -53,6 +56,9 @@ RUN chmod 644 /etc/clamav/freshclam.conf && freshclam # Configures Dovecot RUN sed -i -e 's/include_try \/usr\/share\/dovecot\/protocols\.d/include_try \/etc\/dovecot\/protocols\.d/g' /etc/dovecot/dovecot.conf RUN sed -i -e 's/#mail_plugins = \$mail_plugins/mail_plugins = \$mail_plugins sieve/g' /etc/dovecot/conf.d/15-lda.conf +RUN sed -i -e 's/^.*lda_mailbox_autocreate.*/lda_mailbox_autocreate = yes/g' /etc/dovecot/conf.d/15-lda.conf +RUN sed -i -e 's/^.*lda_mailbox_autosubscribe.*/lda_mailbox_autosubscribe = yes/g' /etc/dovecot/conf.d/15-lda.conf +RUN sed -i -e 's/^.*postmaster_address.*/postmaster_address = '${POSTMASTER_ADDRESS:="postmaster@domain.com"}'/g' /etc/dovecot/conf.d/15-lda.conf COPY target/dovecot/auth-passwdfile.inc /etc/dovecot/conf.d/ COPY target/dovecot/??-*.conf /etc/dovecot/conf.d/ diff --git a/Makefile b/Makefile index 18545b96..1156a37c 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,11 @@ all-fast: build generate-accounts run fixtures tests clean no-build: generate-accounts run fixtures tests clean build-no-cache: + cd test/docker-openldap/ && docker build -f Dockerfile -t ldap --no-cache . docker build --no-cache -t $(NAME) . build: + cd test/docker-openldap/ && docker build -f Dockerfile -t ldap . docker build -t $(NAME) . generate-accounts: @@ -69,6 +71,7 @@ run: -v "`pwd`/test":/tmp/docker-mailserver-test \ -e DISABLE_CLAMAV=1 \ -h mail.my-domain.com -t $(NAME) + sleep 20 docker run -d --name mail_manual_ssl \ -v "`pwd`/test/config":/tmp/docker-mailserver \ -v "`pwd`/test":/tmp/docker-mailserver-test \ @@ -76,6 +79,27 @@ run: -e SSL_CERT_PATH=/tmp/docker-mailserver/letsencrypt/mail.my-domain.com/fullchain.pem \ -e SSL_KEY_PATH=/tmp/docker-mailserver/letsencrypt/mail.my-domain.com/privkey.pem \ -h mail.my-domain.com -t $(NAME) + sleep 20 + docker run -d --name ldap_for_mail \ + -e LDAP_DOMAIN="localhost.localdomain" \ + -h mail.my-domain.com -t ldap + sleep 20 + docker run -d --name mail_with_ldap \ + -v "`pwd`/test/config":/tmp/docker-mailserver \ + -v "`pwd`/test":/tmp/docker-mailserver-test \ + -e ENABLE_LDAP=1 \ + -e LDAP_SERVER_HOST=ldap \ + -e LDAP_SEARCH_BASE=ou=people,dc=localhost,dc=localdomain \ + -e LDAP_BIND_DN=cn=admin,dc=localhost,dc=localdomain \ + -e ENABLE_SASLAUTHD=1 \ + -e SASLAUTHD_MECHANISMS=ldap \ + -e SASLAUTHD_LDAP_SERVER=ldap \ + -e SASLAUTHD_LDAP_BIND_DN=cn=admin,dc=localhost,dc=localdomain \ + -e SASLAUTHD_LDAP_PASSWORD=admin \ + -e SASLAUTHD_LDAP_SEARCH_BASE=ou=people,dc=localhost,dc=localdomain \ + -e POSTMASTER_ADDRESS=postmaster@localhost.localdomain \ + --link ldap_for_mail:ldap \ + -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start sleep 20 @@ -115,7 +139,10 @@ clean: fail-auth-mailer \ mail_disabled_amavis \ mail_disabled_clamav \ - mail_manual_ssl + mail_manual_ssl \ + ldap_for_mail \ + mail_with_ldap + @if [ -f config/postfix-accounts.cf.bak ]; then\ rm -f config/postfix-accounts.cf ;\ mv config/postfix-accounts.cf.bak config/postfix-accounts.cf ;\ diff --git a/README.md b/README.md index 71ae5f8e..f3d78ae4 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,9 @@ Easy to deploy and upgrade. Includes: -- postfix with smtp auth -- dovecot for sasl, imap (and optional pop3) with ssl support +- postfix with smtp or ldap auth +- dovecot for sasl, imap (and optional pop3) with ssl support, with ldap auth +- saslauthd with ldap auth - amavis - spamassasin supporting custom rules - clamav with automatic updates @@ -118,6 +119,40 @@ Otherwise, `iptables` won't be able to ban IPs. - **empty** => `fetchmail` disabled - 1 => `fetchmail` enabled +##### ENABLE_LDAP + + - **empty** => LDAP authentification is disabled + - 1 => LDAP authentification is enabled + - NOTE: + - A second container for the ldap service is necessary (e.g. [docker-openldap](https://github.com/osixia/docker-openldap)) + - For preparing the ldap server to use in combination with this continer [this](http://acidx.net/wordpress/2014/06/installing-a-mailserver-with-postfix-dovecot-sasl-ldap-roundcube/) article may be helpful + +##### LDAP_SERVER_HOST + + - **empty** => mail.domain.com + - => Specify the dns-name/ip-address where the ldap-server + - NOTE: If you going to use the mailserver in combination with docker-compose you can set the service name here + +##### LDAP_SEARCH_BASE + + - **empty** => ou=people,dc=domain,dc=com + - => e.g. LDAP_SEARCH_BASE=dc=mydomain,dc=local + +##### LDAP_BIND_DN + + - **empty** => cn=admin,dc=domain,dc=com + - => take a look at examples of SASL_LDAP_BIND_DN + +##### LDAP_BIND_PW + + - **empty** => admin + - => Specify the password to bind against ldap + +##### POSTMASTER_ADDRESS + + - **empty** => postmaster@domain.com + - => Specify the postmaster address + ##### SA_TAG - **2.0** => add spam info headers if at, or above that level @@ -130,6 +165,56 @@ Otherwise, `iptables` won't be able to ban IPs. - **6.31** => triggers spam evasive actions +##### ENABLE_SASLAUTHD + + - **empty** => `saslauthd` is disabled + - 1 => `saslauthd` is enabled + +##### SASLAUTHD_MECHANISMS + + - empty => pam + - ldap => authenticate against ldap server + - shadow => authenticate against local user db + - mysql => authenticate against mysql db + - rimap => authenticate against imap server + - NOTE: can be a list of mechanisms like pam ldap shadow + +##### SASLAUTHD_MECH_OPTIONS + + - empty => None + - e.g. with SASLAUTHD_MECHANISMS rimap you need to specify the ip-address/servername of the imap server ==> xxx.xxx.xxx.xxx + +##### SASLAUTHD_LDAP_SERVER + + - empty => localhost + +##### SASLAUTHD_LDAP_SSL + + - empty or 0 => ldap:// will be used + - 1 => ldaps:// will be used + +##### SASLAUTHD_LDAP_BIND_DN + + - empty => anonymous bind + - specify an object with priviliges to search the directory tree + - e.g. active directory: SASLAUTHD_LDAP_BIND_DN=cn=Administrator,cn=Users,dc=mydomain,dc=net + - e.g. openldap: SASLAUTHD_LDAP_BIND_DN=cn=admin,dc=mydomain,dc=net + +##### SASLAUTHD_LDAP_PASSWORD + + - empty => anonymous bind + +##### SASLAUTHD_LDAP_SEARCH_BASE + + - empty => Reverting to SASLAUTHD_MECHANISMS pam + - specify the search base + +##### SASLAUTHD_LDAP_FILTER + + - empty => default filter (&(uniqueIdentifier=%u)(mailEnabled=TRUE)) + - e.g. for active directory: (&(sAMAccountName=%U)(objectClass=person)) + - e.g. for openldap: (&(uid=%U)(objectClass=person)) + ##### SASL_PASSWD - **empty** => No sasl_passwd will be created diff --git a/config/dovecot-ldap.conf.ext b/config/dovecot-ldap.conf.ext new file mode 100644 index 00000000..aa4e10cc --- /dev/null +++ b/config/dovecot-ldap.conf.ext @@ -0,0 +1,10 @@ +base = ou=people,dc=domain,dc=com +default_pass_scheme = SSHA +dn = cn=admin,dc=domain,dc=com +dnpass = admin +hosts = mail.domain.com +ldap_version = 3 +pass_attrs = uniqueIdentifier=user,userPassword=password +pass_filter = (&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n)) +user_attrs = mailHomeDirectory=home,mailUidNumber=uid,mailGidNumber=gid,mailStorageDirectory=mail +user_filter = (&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n)) diff --git a/config/postfix-ldap-aliases.cf b/config/postfix-ldap-aliases.cf new file mode 100644 index 00000000..a3f77eaf --- /dev/null +++ b/config/postfix-ldap-aliases.cf @@ -0,0 +1,8 @@ +bind = yes +bind_dn = cn=admin,dc=domain,dc=com +bind_pw = admin +query_filter = (&(mailAlias=%s)(mailEnabled=TRUE)) +result_attribute = mail +search_base = ou=people,dc=domain,dc=com +server_host = mail.domain.com +version = 3 diff --git a/config/postfix-ldap-groups.cf b/config/postfix-ldap-groups.cf new file mode 100644 index 00000000..5ac2e06a --- /dev/null +++ b/config/postfix-ldap-groups.cf @@ -0,0 +1,8 @@ +bind = yes +bind_dn = cn=admin,dc=domain,dc=com +bind_pw = admin +query_filter = (&(mailGroupMember=%s)(mailEnabled=TRUE)) +result_attribute = mail +search_base = ou=people,dc=domain,dc=com +server_host = mail.domain.com +version = 3 diff --git a/config/postfix-ldap-users.cf b/config/postfix-ldap-users.cf new file mode 100644 index 00000000..f837a04c --- /dev/null +++ b/config/postfix-ldap-users.cf @@ -0,0 +1,8 @@ +bind = yes +bind_dn = cn=admin,dc=domain,dc=com +bind_pw = admin +query_filter = (&(mail=%s)(mailEnabled=TRUE)) +result_attribute = mail +search_base = ou=people,dc=domain,dc=com +server_host = mail.domain.com +version = 3 diff --git a/target/start-mailserver.sh b/target/start-mailserver.sh index cb3a9b43..4a9e9c38 100644 --- a/target/start-mailserver.sh +++ b/target/start-mailserver.sh @@ -20,20 +20,9 @@ fi echo "export VIRUSMAILS_DELETE_DELAY=${VIRUSMAILS_DELETE_DELAY:="7"}" >> /root/.bashrc # -# Users +# Configuring Dovecot # -if [ -f /tmp/docker-mailserver/postfix-accounts.cf ]; then - echo "Checking file line endings" - sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf - echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" - echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox - - # Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline - sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf - # Configuring Dovecot - echo -n > /etc/dovecot/userdb - chown dovecot:dovecot /etc/dovecot/userdb - chmod 640 /etc/dovecot/userdb +if [ "$SMTP_ONLY" != 1 ]; then cp -a /usr/share/dovecot/protocols.d /etc/dovecot/ # Disable pop3 (it will be eventually enabled later in the script, if requested) mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab @@ -42,6 +31,26 @@ if [ -f /tmp/docker-mailserver/postfix-accounts.cf ]; then sed -i -e 's/#port = 993/port = 993/g' /etc/dovecot/conf.d/10-master.conf sed -i -e 's/#port = 995/port = 995/g' /etc/dovecot/conf.d/10-master.conf sed -i -e 's/#ssl = yes/ssl = required/g' /etc/dovecot/conf.d/10-ssl.conf +fi + +# +# Users +# +if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then + echo "Checking file line endings" + sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf + echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" + echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox + + # Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline + sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf + + echo -n > /etc/dovecot/userdb + chown dovecot:dovecot /etc/dovecot/userdb + chmod 640 /etc/dovecot/userdb + + sed -i -e '/\!include auth-ldap\.conf\.ext/s/^/#/' /etc/dovecot/conf.d/10-auth.conf + sed -i -e '/\!include auth-passwdfile\.inc/s/^#//' /etc/dovecot/conf.d/10-auth.conf # Creating users # 'pass' is encrypted @@ -75,6 +84,93 @@ else echo "==> Warning: 'config/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created." fi +# +# LDAP +# +if [ "$ENABLE_LDAP" = 1 ]; then + for i in 'users' 'groups' 'aliases'; do + fpath="/tmp/docker-mailserver/postfix-ldap-${i}.cf" + if [ -f $fpath ]; then + cp ${fpath} /etc/postfix/ldap-${i}.cf + sed -i -e 's|^server_host.*|server_host = '${LDAP_SERVER_HOST:="mail.domain.com"}'|g' \ + -e 's|^search_base.*|search_base = '${LDAP_SEARCH_BASE:="ou=people,dc=domain,dc=com"}'|g' \ + -e 's|^bind_dn.*|bind_dn = '${LDAP_BIND_DN:="cn=admin,dc=domain,dc=com"}'|g' \ + -e 's|^bind_pw.*|bind_pw = '${LDAP_BIND_PW:="admin"}'|g' \ + /etc/postfix/ldap-${i}.cf + else + echo "${fpath} not found" + echo "==> Warning: 'config/postfix-ldap-$i.cf' is not provided." + fi + done + + echo "Loading dovecot LDAP authentification configuration" + cp /tmp/docker-mailserver/dovecot-ldap.conf.ext /etc/dovecot/dovecot-ldap.conf.ext + + sed -i -e 's|^hosts.*|hosts = '${LDAP_SERVER_HOST:="mail.domain.com"}'|g' \ + -e 's|^base.*|base = '${LDAP_SEARCH_BASE:="ou=people,dc=domain,dc=com"}'|g' \ + -e 's|^dn\s*=.*|dn = '${LDAP_BIND_DN:="cn=admin,dc=domain,dc=com"}'|g' \ + -e 's|^dnpass\s*=.*|dnpass = '${LDAP_BIND_PW:="admin"}'|g' \ + /etc/dovecot/dovecot-ldap.conf.ext + + echo "Enabling dovecot LDAP authentification" + sed -i -e '/\!include auth-ldap\.conf\.ext/s/^#//' /etc/dovecot/conf.d/10-auth.conf + sed -i -e '/\!include auth-passwdfile\.inc/s/^/#/' /etc/dovecot/conf.d/10-auth.conf + + echo "Configuring LDAP" + [ -f /etc/postfix/ldap-users.cf ] && \ + postconf -e "virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf" || \ + echo '==> Warning: /etc/postfix/ldap-user.cf not found' + + [ -f /etc/postfix/ldap-aliases.cf -a -f /etc/postfix/ldap-groups.cf ] && \ + postconf -e "virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf, ldap:/etc/postfix/ldap-groups.cf" || \ + echo '==> Warning: /etc/postfix/ldap-aliases.cf or /etc/postfix/ldap-groups.cf not found' + + [ ! -f /etc/postfix/sasl/smtpd.conf ] && cat > /etc/postfix/sasl/smtpd.conf << EOF +pwcheck_method: saslauthd +mech_list: plain login +EOF +fi + +# +# SASLAUTHD +# +if [ "$ENABLE_SASLAUTHD" = 1 ]; then + echo "Configuring Cyrus SASL" + # checking env vars and setting defaults + [ -z $SASLAUTHD_MECHANISMS ] && SASLAUTHD_MECHANISMS=pam + [ -z $SASLAUTHD_LDAP_SEARCH_BASE ] && SASLAUTHD_MECHANISMS=pam + [ -z $SASLAUTHD_LDAP_SERVER ] && SASLAUTHD_LDAP_SERVER=localhost + [ -z $SASLAUTHD_LDAP_FILTER ] && SASLAUTHD_LDAP_FILTER='(&(uniqueIdentifier=%u)(mailEnabled=TRUE))' + ([ $SASLAUTHD_LDAP_SSL == 0 ] || [ -z $SASLAUTHD_LDAP_SSL ]) && SASLAUTHD_LDAP_PROTO='ldap://' || SASLAUTHD_LDAP_PROTO='ldaps://' + + if [ ! -f /etc/saslauthd.conf ]; then + echo "Creating /etc/saslauthd.conf" + cat > /etc/saslauthd.conf << EOF +ldap_servers: ${SASLAUTHD_LDAP_PROTO}${SASLAUTHD_LDAP_SERVER} + +ldap_auth_method: bind +ldap_bind_dn: ${SASLAUTHD_LDAP_BIND_DN} +ldap_bind_pw: ${SASLAUTHD_LDAP_PASSWORD} + +ldap_search_base: ${SASLAUTHD_LDAP_SEARCH_BASE} +ldap_filter: ${SASLAUTHD_LDAP_FILTER} + +ldap_referrals: yes +log_level: 10 +EOF + fi + + sed -i -e "s|^START=.*|START=yes|g" \ + -e "s|^MECHANISMS=.*|MECHANISMS="\"$SASLAUTHD_MECHANISMS\""|g" \ + -e "s|^MECH_OPTIONS=.*|MECH_OPTIONS="\"$SASLAUTHD_MECH_OPTIONS\""|g" \ + /etc/default/saslauthd + sed -i -e "/smtpd_sasl_path =.*/d" \ + -e "/smtpd_sasl_type =.*/d" \ + -e "/dovecot_destination_recipient_limit =.*/d" \ + /etc/postfix/main.cf + gpasswd -a postfix sasl +fi + # # Aliases # @@ -427,8 +523,14 @@ if [ "$ENABLE_FAIL2BAN" = 1 ]; then /etc/init.d/fail2ban start fi -echo "Listing users" -/usr/sbin/dovecot user '*' +if [ "$ENABLE_SASLAUTHD" = 1 ]; then + /etc/init.d/saslauthd start +fi + +if [ "$SMTP_ONLY" != 1 ]; then + echo "Listing users" + /usr/sbin/dovecot user '*' +fi echo "Starting..." tail -f /var/log/mail/mail.log diff --git a/test/auth/imap-ldap-auth.txt b/test/auth/imap-ldap-auth.txt new file mode 100644 index 00000000..89be2773 --- /dev/null +++ b/test/auth/imap-ldap-auth.txt @@ -0,0 +1,2 @@ +a1 LOGIN some.user@localhost.localdomain secret +a2 LOGOUT diff --git a/test/auth/sasl-ldap-smtp-auth.txt b/test/auth/sasl-ldap-smtp-auth.txt new file mode 100644 index 00000000..df4d7db4 --- /dev/null +++ b/test/auth/sasl-ldap-smtp-auth.txt @@ -0,0 +1,5 @@ +EHLO mail +AUTH LOGIN +c29tZS51c2VyQGxvY2FsaG9zdC5sb2NhbGRvbWFpbg== +c2VjcmV0 +QUIT diff --git a/test/config/dovecot-ldap.conf.ext b/test/config/dovecot-ldap.conf.ext new file mode 100644 index 00000000..a82641fa --- /dev/null +++ b/test/config/dovecot-ldap.conf.ext @@ -0,0 +1,10 @@ +base = ou=people,dc=my-domain,dc=com +default_pass_scheme = SSHA +dn = cn=admin,dc=my-domain,dc=com +dnpass = admin +hosts = mail.my-domain.com +ldap_version = 3 +pass_attrs = uniqueIdentifier=user,userPassword=password +pass_filter = (&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n)) +user_attrs = mailHomeDirectory=home,mailUidNumber=uid,mailGidNumber=gid,mailStorageDirectory=mail +user_filter = (&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n)) diff --git a/test/config/postfix-ldap-aliases.cf b/test/config/postfix-ldap-aliases.cf new file mode 100644 index 00000000..cb9c21af --- /dev/null +++ b/test/config/postfix-ldap-aliases.cf @@ -0,0 +1,8 @@ +bind = yes +bind_dn = cn=admin,dc=my-domain,dc=com +bind_pw = admin +query_filter = (&(mailAlias=%s)(mailEnabled=TRUE)) +result_attribute = mail +search_base = ou=people,dc=my-domain,dc=com +server_host = mail.my-domain.com +version = 3 diff --git a/test/config/postfix-ldap-groups.cf b/test/config/postfix-ldap-groups.cf new file mode 100644 index 00000000..13e69367 --- /dev/null +++ b/test/config/postfix-ldap-groups.cf @@ -0,0 +1,8 @@ +bind = yes +bind_dn = cn=admin,dc=my-domain,dc=com +bind_pw = admin +query_filter = (&(mailGroupMember=%s)(mailEnabled=TRUE)) +result_attribute = mail +search_base = ou=people,dc=my-domain,dc=com +server_host = mail.my-domain.com +version = 3 diff --git a/test/config/postfix-ldap-users.cf b/test/config/postfix-ldap-users.cf new file mode 100644 index 00000000..18cf8acf --- /dev/null +++ b/test/config/postfix-ldap-users.cf @@ -0,0 +1,8 @@ +bind = yes +bind_dn = cn=admin,dc=my-domain,dc=com +bind_pw = admin +query_filter = (&(mail=%s)(mailEnabled=TRUE)) +result_attribute = mail +search_base = ou=people,dc=my-domain,dc=com +server_host = mail.my-domain.com +version = 3 diff --git a/test/docker-openldap/Dockerfile b/test/docker-openldap/Dockerfile new file mode 100644 index 00000000..8e32766c --- /dev/null +++ b/test/docker-openldap/Dockerfile @@ -0,0 +1,5 @@ +FROM osixia/openldap:1.1.6 +MAINTAINER Dennis Stumm + +ADD bootstrap /container/service/slapd/assets/config/bootstrap +RUN rm /container/service/slapd/assets/config/bootstrap/schema/mmc/mail.schema diff --git a/test/docker-openldap/bootstrap/ldif/01_mail-tree.ldif b/test/docker-openldap/bootstrap/ldif/01_mail-tree.ldif new file mode 100644 index 00000000..940fef24 --- /dev/null +++ b/test/docker-openldap/bootstrap/ldif/01_mail-tree.ldif @@ -0,0 +1,5 @@ +dn: ou=people,dc=localhost,dc=localdomain +changetype: add +objectClass: organizationalUnit +objectClass: top +ou: people diff --git a/test/docker-openldap/bootstrap/ldif/02_user-email.ldif b/test/docker-openldap/bootstrap/ldif/02_user-email.ldif new file mode 100644 index 00000000..3528f49b --- /dev/null +++ b/test/docker-openldap/bootstrap/ldif/02_user-email.ldif @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------- +# Create mail accounts +# -------------------------------------------------------------------- +# Some User +dn: uniqueIdentifier=some.user,ou=people,dc=localhost,dc=localdomain +changetype: add +objectClass: organizationalPerson +objectClass: person +objectClass: top +objectClass: PostfixBookMailAccount +objectClass: extensibleObject +cn: Some User +givenName: User +mail: some.user@localhost.localdomain +mailAlias: postmaster@localhost.localdomain +mailGroupMember: employees@localhost.localdomain +mailEnabled: TRUE +mailGidNumber: 5000 +mailHomeDirectory: /var/mail/localhost.localdomain/some.user/ +mailQuota: 10240 +mailStorageDirectory: maildir:/var/mail/localhost.localdomain/some.user/ +mailUidNumber: 5000 +sn: Some +uniqueIdentifier: some.user +userPassword: {SSHA}eLtqGpid+hkSVhxvsdTPztv4uapRofGx diff --git a/test/docker-openldap/bootstrap/schema/mmc/postfix-book.schema b/test/docker-openldap/bootstrap/schema/mmc/postfix-book.schema new file mode 100644 index 00000000..8047a242 --- /dev/null +++ b/test/docker-openldap/bootstrap/schema/mmc/postfix-book.schema @@ -0,0 +1,70 @@ +# $Id$ +# +# State of Mind +# Private Enterprise Number: 29426 +# +# OID prefix: 1.3.6.1.4.1.29426 +# +# Attributes: 1.3.6.1.4.1.29426.1.10.x +# + + +attributetype ( 1.3.6.1.4.1.29426.1.10.1 NAME 'mailHomeDirectory' + DESC 'The absolute path to the mail user home directory' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.2 NAME 'mailAlias' + DESC 'RFC822 Mailbox - mail alias' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.3 NAME 'mailUidNumber' + DESC 'UID required to access the mailbox' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.4 NAME 'mailGidNumber' + DESC 'GID required to access the mailbox' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.5 NAME 'mailEnabled' + DESC 'TRUE to enable, FALSE to disable account' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.6 NAME 'mailGroupMember' + DESC 'Name of a mail distribution list' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.7 NAME 'mailQuota' + DESC 'Mail quota limit in kilobytes' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.29426.1.10.8 NAME 'mailStorageDirectory' + DESC 'The absolute path to the mail users mailbox' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + + +# +# Objects: 1.3.6.1.4.1.29426.1.2.2.x +# + +objectclass ( 1.3.6.1.4.1.29426.1.2.2.1 NAME 'PostfixBookMailAccount' + SUP top AUXILIARY + DESC 'Mail account used in Postfix Book' + MUST ( mail ) + MAY ( mailHomeDirectory $ mailAlias $ mailGroupMember + $ mailUidNumber $ mailGidNumber $ mailEnabled + $ mailQuota $mailStorageDirectory ) ) + +objectclass ( 1.3.6.1.4.1.29426.1.2.2.2 NAME 'PostfixBookMailForward' + SUP top AUXILIARY + DESC 'Mail forward used in Postfix Book' + MUST ( mail $ mailAlias )) + diff --git a/test/email-templates/test-email.txt b/test/email-templates/test-email.txt new file mode 100644 index 00000000..69608d44 --- /dev/null +++ b/test/email-templates/test-email.txt @@ -0,0 +1,3 @@ +Subject: Test Message + +This is a test mail. diff --git a/test/tests.bats b/test/tests.bats index 58fa2aa2..ab3b190a 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -66,6 +66,11 @@ [ "$status" -eq 1 ] } +@test "checking process: saslauthd (saslauthd server enabled)" { + run docker exec mail_with_ldap /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'" + [ "$status" -eq 0 ] +} + # # imap # @@ -755,3 +760,45 @@ run ./setup.sh -c mail debug login ls [ "$status" -eq 0 ] } + +# +# LDAP +# + +# postfix +@test "checking postfix: ldap lookup works correctly" { + run docker exec mail_with_ldap /bin/sh -c "postmap -q some.user@localhost.localdomain ldap:/etc/postfix/ldap-users.cf" + [ "$status" -eq 0 ] + [ "$output" = "some.user@localhost.localdomain" ] + run docker exec mail_with_ldap /bin/sh -c "postmap -q postmaster@localhost.localdomain ldap:/etc/postfix/ldap-aliases.cf" + [ "$status" -eq 0 ] + [ "$output" = "some.user@localhost.localdomain" ] + run docker exec mail_with_ldap /bin/sh -c "postmap -q employees@localhost.localdomain ldap:/etc/postfix/ldap-groups.cf" + [ "$status" -eq 0 ] + [ "$output" = "some.user@localhost.localdomain" ] +} + +# dovecot +@test "checking dovecot: ldap imap connection and authentication works" { + run docker exec mail_with_ldap /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-ldap-auth.txt" + [ "$status" -eq 0 ] +} + +@test "checking dovecot: mail delivery works" { + run docker exec mail_with_ldap /bin/sh -c "sendmail -f user@external.tld some.user@localhost.localdomain < /tmp/docker-mailserver-test/email-templates/test-email.txt" + sleep 10 + run docker exec mail_with_ldap /bin/sh -c "ls -A /var/mail/localhost.localdomain/some.user/new | wc -l" + [ "$status" -eq 0 ] + [ "$output" -eq 1 ] +} + +# saslauthd +@test "checking saslauthd: sasl ldap authentication works" { + run docker exec mail_with_ldap bash -c "testsaslauthd -u some.user -p secret" + [ "$status" -eq 0 ] +} + +@test "checking saslauthd: ldap smtp authentication" { + run docker exec mail_with_ldap /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/sasl-ldap-smtp-auth.txt | grep 'Authentication successful'" + [ "$status" -eq 0 ] +}