aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2019-11-10 03:18:26 +0100
committerGuilhem Moulin <guilhem@fripost.org>2019-11-13 06:23:57 +0100
commit78522acced782587b3768f3fb57f2f25cb905754 (patch)
tree376fd984327ebc453fbdae0c9f821cb0b87e6467
parent67440844c422ee30b31df9a46a7f99ac0e833add (diff)
Test suite: add new tests for authentication.
This can't be done with `doveadm exec imap`, so the IMAPd needs to bind to TCP port 10143 on the loopback interface. Also, no longer pass ‘imap_capability’ Dovecot setting explicitely to `doveadm exec imap`; changed tests/sync-live-crippled to use type=imap instead of type=tunnel.
-rw-r--r--tests/auth-login/interimap.remote5
-rw-r--r--tests/auth-login/remote.conf2
-rw-r--r--tests/auth-login/t12
l---------tests/auth-logindisabled/interimap.remote1
-rw-r--r--tests/auth-logindisabled/remote.conf4
-rw-r--r--tests/auth-logindisabled/t16
-rw-r--r--tests/auth-noplaintext/interimap.remote3
l---------tests/auth-noplaintext/remote.conf1
-rw-r--r--tests/auth-noplaintext/t15
l---------tests/auth-sasl-plain-no-ir/interimap.remote1
-rw-r--r--tests/auth-sasl-plain-no-ir/remote.conf2
-rw-r--r--tests/auth-sasl-plain-no-ir/t26
-rw-r--r--tests/auth-sasl-plain/interimap.remote4
-rw-r--r--tests/auth-sasl-plain/remote.conf1
-rw-r--r--tests/auth-sasl-plain/t12
-rw-r--r--tests/list7
-rwxr-xr-xtests/run109
-rw-r--r--tests/snippets/dovecot/imapd.conf12
-rw-r--r--tests/snippets/dovecot/interimap-required-capabilities.conf3
l---------tests/sync-live-crippled/interimap.remote1
-rw-r--r--tests/sync-live-crippled/remote.conf4
21 files changed, 213 insertions, 28 deletions
diff --git a/tests/auth-login/interimap.remote b/tests/auth-login/interimap.remote
new file mode 100644
index 0000000..b7d67bf
--- /dev/null
+++ b/tests/auth-login/interimap.remote
@@ -0,0 +1,5 @@
+type = imap
+host = localhost
+port = 10143
+STARTTLS = NO
+auth = login
diff --git a/tests/auth-login/remote.conf b/tests/auth-login/remote.conf
new file mode 100644
index 0000000..4ab127a
--- /dev/null
+++ b/tests/auth-login/remote.conf
@@ -0,0 +1,2 @@
+!include conf.d/imapd.conf
+auth_mechanisms = plain login
diff --git a/tests/auth-login/t b/tests/auth-login/t
new file mode 100644
index 0000000..7fd83d5
--- /dev/null
+++ b/tests/auth-login/t
@@ -0,0 +1,12 @@
+for ((i = 0; i < 32; i++)); do
+ u="$(shuf -n1 -e "local" "remote")"
+ sample_message | deliver -u "$u"
+done
+
+# check that credentials aren't leaked to the debug output
+interimap --debug || error
+grep -Fx "remote: C: xxx LOGIN [REDACTED]" <"$STDERR" || error
+
+check_mailbox_status "INBOX"
+
+# vim: set filetype=sh :
diff --git a/tests/auth-logindisabled/interimap.remote b/tests/auth-logindisabled/interimap.remote
new file mode 120000
index 0000000..a4ea3f3
--- /dev/null
+++ b/tests/auth-logindisabled/interimap.remote
@@ -0,0 +1 @@
+../auth-sasl-plain/interimap.remote \ No newline at end of file
diff --git a/tests/auth-logindisabled/remote.conf b/tests/auth-logindisabled/remote.conf
new file mode 100644
index 0000000..1f02afe
--- /dev/null
+++ b/tests/auth-logindisabled/remote.conf
@@ -0,0 +1,4 @@
+!include conf.d/imapd.conf
+
+# trick dovecot into treating local connections as insecure
+imap_capability = +LOGINDISABLED
diff --git a/tests/auth-logindisabled/t b/tests/auth-logindisabled/t
new file mode 100644
index 0000000..0bcd0d6
--- /dev/null
+++ b/tests/auth-logindisabled/t
@@ -0,0 +1,16 @@
+! interimap --debug || error
+
+# double check the presence of 'LOGINDISABLED' in the preauth capability list
+grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability"
+
+sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability"
+tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities"
+grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error
+grep -Fx "LOGINDISABLED" <"$TMPDIR/capabilities" || error
+! grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error # otherwise we'd try to upgrade the connectionn
+
+# make sure we didn't send any credentials
+grep -Fx "remote: ERROR: Logins are disabled." <"$STDERR" || error
+! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error
+
+# vim: set filetype=sh :
diff --git a/tests/auth-noplaintext/interimap.remote b/tests/auth-noplaintext/interimap.remote
new file mode 100644
index 0000000..60567e2
--- /dev/null
+++ b/tests/auth-noplaintext/interimap.remote
@@ -0,0 +1,3 @@
+type = imap
+host = localhost
+port = 10143
diff --git a/tests/auth-noplaintext/remote.conf b/tests/auth-noplaintext/remote.conf
new file mode 120000
index 0000000..dbbb908
--- /dev/null
+++ b/tests/auth-noplaintext/remote.conf
@@ -0,0 +1 @@
+../auth-sasl-plain/remote.conf \ No newline at end of file
diff --git a/tests/auth-noplaintext/t b/tests/auth-noplaintext/t
new file mode 100644
index 0000000..11d7d4d
--- /dev/null
+++ b/tests/auth-noplaintext/t
@@ -0,0 +1,15 @@
+! interimap --debug || error
+
+# double check the presence of 'STARTTLS' in the preauth capability list
+grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability"
+
+sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability"
+tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities"
+ grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error
+! grep -Fx "STARTTLS" <"$TMPDIR/capabilities" || error
+
+# make sure we didn't send any credentials
+grep -Fx "remote: ERROR: Server did not advertise STARTTLS capability." <"$STDERR" || error
+! grep -E "^remote: C: .* (AUTHENTICATE|LOGIN) " <"$STDERR" || error
+
+# vim: set filetype=sh :
diff --git a/tests/auth-sasl-plain-no-ir/interimap.remote b/tests/auth-sasl-plain-no-ir/interimap.remote
new file mode 120000
index 0000000..a4ea3f3
--- /dev/null
+++ b/tests/auth-sasl-plain-no-ir/interimap.remote
@@ -0,0 +1 @@
+../auth-sasl-plain/interimap.remote \ No newline at end of file
diff --git a/tests/auth-sasl-plain-no-ir/remote.conf b/tests/auth-sasl-plain-no-ir/remote.conf
new file mode 100644
index 0000000..dae9545
--- /dev/null
+++ b/tests/auth-sasl-plain-no-ir/remote.conf
@@ -0,0 +1,2 @@
+!include conf.d/imapd.conf
+!include conf.d/interimap-required-capabilities.conf
diff --git a/tests/auth-sasl-plain-no-ir/t b/tests/auth-sasl-plain-no-ir/t
new file mode 100644
index 0000000..17aa9e6
--- /dev/null
+++ b/tests/auth-sasl-plain-no-ir/t
@@ -0,0 +1,26 @@
+n=1 # at least one message to send remotely
+sample_message | deliver -u "local"
+for ((i = 0; i < 32; i++)); do
+ u="$(shuf -n1 -e "local" "remote")"
+ [ "$u" = "remote" ] || n=$(( n+1 ))
+ sample_message | deliver -u "$u"
+done
+
+# check that credentials aren't leaked to the debug output
+interimap --debug || error
+grep -Fx "remote: C: xxx AUTHENTICATE PLAIN [REDACTED]" <"$STDERR" || error
+
+# make sure we didn't use SASL-IR
+grep -oE -m1 '^remote: S: \* OK \[CAPABILITY IMAP4rev1( [^]]*)? AUTH=[^]]*\]' <"$STDERR" >"$TMPDIR/capability"
+
+sed -ri 's/^remote: S: \* OK \[CAPABILITY (.*)\]$/\1/' "$TMPDIR/capability"
+tr " " "\\n" <"$TMPDIR/capability" >"$TMPDIR/capabilities"
+ grep -Fx "IMAP4rev1" <"$TMPDIR/capabilities" || error
+! grep -Fx "SASL-IR" <"$TMPDIR/capabilities" || error
+
+# make sure all literals were synchronizing (and that we didn't use MULTIAPPEND)
+xcgrep "$n" -E "^remote(\(INBOX\))?: C: [0-9]+ APPEND INBOX .* \{[0-9]+\}$" <"$STDERR"
+
+check_mailbox_status "INBOX"
+
+# vim: set filetype=sh :
diff --git a/tests/auth-sasl-plain/interimap.remote b/tests/auth-sasl-plain/interimap.remote
new file mode 100644
index 0000000..9c0a623
--- /dev/null
+++ b/tests/auth-sasl-plain/interimap.remote
@@ -0,0 +1,4 @@
+type = imap
+host = localhost
+port = 10143
+STARTTLS = NO
diff --git a/tests/auth-sasl-plain/remote.conf b/tests/auth-sasl-plain/remote.conf
new file mode 100644
index 0000000..3ccbd42
--- /dev/null
+++ b/tests/auth-sasl-plain/remote.conf
@@ -0,0 +1 @@
+!include conf.d/imapd.conf
diff --git a/tests/auth-sasl-plain/t b/tests/auth-sasl-plain/t
new file mode 100644
index 0000000..68f71a9
--- /dev/null
+++ b/tests/auth-sasl-plain/t
@@ -0,0 +1,12 @@
+for ((i = 0; i < 32; i++)); do
+ u="$(shuf -n1 -e "local" "remote")"
+ sample_message | deliver -u "$u"
+done
+
+# check that credentials aren't leaked to the debug output
+interimap --debug || error
+grep -Fx "remote: C: xxx AUTHENTICATE PLAIN [REDACTED]" <"$STDERR" || error
+
+check_mailbox_status "INBOX"
+
+# vim: set filetype=sh :
diff --git a/tests/list b/tests/list
index 21aa3f4..86034ef 100644
--- a/tests/list
+++ b/tests/list
@@ -31,6 +31,13 @@ largeint Large UIDVALIDITY/UIDNEXT/HIGHESTMODSEQ values
resume Resume when aborted
repair --repair
+. Authentication
+ auth-sasl-plain AUTHENTICATE (SASL PLAIN)
+ auth-sasl-plain-no-ir AUTHENTICATE (SASL PLAIN, no SASL-IR)
+ auth-login LOGIN
+ auth-logindisabled LOGINDISABLED
+ auth-noplaintext abort when STARTTLS is not offered
+
. Live synchronization (60s)
sync-live local/remote simulation
sync-live-crippled local/remote simulation (crippled remote)
diff --git a/tests/run b/tests/run
index cb52518..bff9c18 100755
--- a/tests/run
+++ b/tests/run
@@ -27,7 +27,8 @@ if [ $# -eq 0 ] || [ $# -gt 2 ]; then
exit 1
fi
-TESTDIR="$(dirname -- "$0")/$1"
+BASEDIR="$(dirname -- "$0")"
+TESTDIR="$BASEDIR/$1"
TESTNAME="${2-$1}"
if [ ! -d "$TESTDIR" ]; then
printf "ERROR: Not a directory: %s\\n" "$TESTDIR" >&2
@@ -35,7 +36,18 @@ if [ ! -d "$TESTDIR" ]; then
fi
ROOTDIR="$(mktemp --tmpdir="${TMPDIR:-/dev/shm}" --directory "$1.XXXXXXXXXX")"
-trap 'rm -rf -- "$ROOTDIR"' EXIT INT TERM
+declare -a DOVECOT_SERVER=()
+trap cleanup EXIT INT TERM
+cleanup() {
+ local pid c
+ for c in "${DOVECOT_SERVER[@]}"; do
+ if [ ! -f "$c" ] || ! env -i PATH="/usr/bin:/bin" doveadm -c "$c" stop; then
+ pid="$(< "${c%/*}/run/master.pid")"
+ kill -TERM "$pid" || printf "kill(1) exited with status %d\\n" "$?" >&2
+ fi
+ done
+ rm -rf -- "$ROOTDIR"
+}
_STDOUT="$ROOTDIR/stdout"
_STDERR="$ROOTDIR/stderr"
@@ -60,7 +72,7 @@ environ_set() {
# Prepare the test harness
prepare() {
declare -a ENVIRON=()
- local src cfg target u home n capability
+ local src cfg target u home n proto
if [ -f "$TESTDIR/remotes" ]; then
for cfg in $(seq 1 "$(< "$TESTDIR/remotes")"); do
REMOTES+=( "remote$cfg" )
@@ -72,27 +84,64 @@ prepare() {
for u in "local" "${REMOTES[@]}"; do
home="$ROOTDIR/$u/home"
export "HOME_$u"="$home"
- mkdir -pm0700 -- "$home/.config/dovecot"
- cat >"$home/.config/dovecot/config" <<-EOF
+ environ_set "$u"
+
+ mkdir -pm0700 -- "$home/.dovecot"
+ cat >"$home/.dovecot/config" <<-EOF
log_path = $HOME_local/mail.log
mail_home = $home
mail_location = dbox:~/inbox:LAYOUT=index
mailbox_list_index = yes
ssl = no
+ listen = 127.0.0.1, ::1
namespace inbox {
inbox = yes
}
EOF
if [ -f "$TESTDIR/$u.conf" ]; then
- cat >>"$home/.config/dovecot/config" <"$TESTDIR/$u.conf"
+ cat >>"$home/.dovecot/config" <"$TESTDIR/$u.conf"
+ fi
+ cp -aT -- "$BASEDIR/snippets/dovecot" "$home/.dovecot/conf.d"
+
+ proto="$(env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -h protocols)"
+ if [ -n "$proto" ]; then
+ cat >>"$home/.dovecot/config" <<-EOF
+ # https://wiki.dovecot.org/HowTo/Rootless
+ base_dir = $home/.dovecot/run
+ default_internal_user = $(id -un)
+ default_internal_group = $(id -gn)
+ default_login_user = $(id -un)
+
+ service anvil {
+ chroot =
+ }
+ service imap-login {
+ chroot =
+ }
+ service stats {
+ chroot =
+ }
+
+ passdb {
+ args = scheme=PLAIN username_format=%u $home/.dovecot/users
+ driver = passwd-file
+ }
+ userdb {
+ args = username_format=%u $home/.dovecot/users
+ driver = passwd-file
+ }
+ EOF
+
+ env -i PATH="/usr/bin:/bin" /usr/sbin/dovecot -c "$home/.dovecot/config"
+ DOVECOT_SERVER+=( "$home/.dovecot/config" )
+ printf "%s:%s:::::\\n" "$u" "$(xxd -l16 -p </dev/urandom)" >"$home/.dovecot/users"
fi
- environ_set "$u"
mkdir -pm0755 -- "$home/.local/bin"
cat >"$home/.local/bin/doveadm" <<-EOF
#!/bin/sh
exec env -i ${ENVIRON[@]@Q} \\
- doveadm -c ${home@Q}/.config/dovecot/config "\$@"
+ doveadm -c ${home@Q}/.dovecot/config "\$@"
EOF
chmod +x -- "$home/.local/bin/doveadm"
done
@@ -123,15 +172,19 @@ prepare() {
cat <"$TESTDIR/interimap$n.local" >>"$HOME_local/.config/interimap/config$n"
fi
- # `doveadm exec imap` ignores 'imap_capability' from doveconf/config
- capability="$(doveconf -c "$home/.config/dovecot/config" -h imap_capability)"
- cat >>"$HOME_local/.config/interimap/config$n" <<-EOF
-
- [remote]
- type = tunnel
- command = exec ${home@Q}/.local/bin/doveadm exec imap ${capability:+-oimap_capability=${capability@Q}}
- null-stderr = NO
- EOF
+ printf "\\n[remote]\\n" >>"$HOME_local/.config/interimap/config$n"
+ if [ -s "$home/.dovecot/users" ]; then
+ cat <<-EOF
+ username = $u
+ password = $(awk -F: -vu="$u" '$1 == u {print $2}' <"$home/.dovecot/users")
+ EOF
+ else
+ cat <<-EOF
+ type = tunnel
+ command = exec ${home@Q}/.local/bin/doveadm exec imap
+ null-stderr = NO
+ EOF
+ fi >>"$HOME_local/.config/interimap/config$n"
if [ -f "$TESTDIR/interimap$n.remote" ]; then
cat <"$TESTDIR/interimap$n.remote" >>"$HOME_local/.config/interimap/config$n"
fi
@@ -208,7 +261,7 @@ dump_test_result() {
environ_set "$u"
eval home="\$HOME_$u"
printf "%s dovecot configuration:\\n%s\\n" "$u" "$below"
- env -i "${ENVIRON[@]}" doveconf -c "$home/.config/dovecot/config" -n
+ env -i "${ENVIRON[@]}" doveconf -c "$home/.dovecot/config" -n
printf "%s\\n\\n" "$above"
done
@@ -218,6 +271,10 @@ dump_test_result() {
printf "%s\\n\\n" "$above"
done
+ printf "mail.log:\\n%s\\n" "$below"
+ cat -- "$HOME_local/mail.log" 2>/dev/null || true
+ printf "%s\\n\\n" "$above"
+
printf "standard output:\\n%s\\n" "$below"
cat <"$_STDOUT"
printf "%s\\n\\n" "$above"
@@ -230,10 +287,10 @@ dump_test_result() {
# Check mailbox consistency between the local/remote server and interimap's database
check_mailbox_status() {
local mailbox="$1" lns="inbox" lsep lprefix rns="inbox" rsep rprefix
- lsep="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/separator")"
- lprefix="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/prefix")"
- rsep="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/separator")"
- rprefix="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/prefix")"
+ lsep="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/separator")"
+ lprefix="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/prefix")"
+ rsep="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/separator")"
+ rprefix="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/prefix")"
local blob="x'$(printf "%s" "$mailbox" | tr "$lsep" "\\0" | xxd -c256 -ps)'"
local rmailbox="$(printf "%s" "$mailbox" | tr "$lsep" "$rsep")"
@@ -305,10 +362,10 @@ check_mailboxes_status() {
# Check mailbox list constency between the local and remote servers
check_mailbox_list() {
local m i lns="inbox" lsep lprefix rns="inbox" rsep rprefix sub=
- lsep="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/separator")"
- lprefix="$(doveconf -c "$HOME_local/.config/dovecot/config" -h "namespace/$lns/prefix")"
- rsep="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/separator")"
- rprefix="$(doveconf -c "$HOME_remote/.config/dovecot/config" -h "namespace/$lns/prefix")"
+ lsep="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/separator")"
+ lprefix="$(doveconf -c "$HOME_local/.dovecot/config" -h "namespace/$lns/prefix")"
+ rsep="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/separator")"
+ rprefix="$(doveconf -c "$HOME_remote/.dovecot/config" -h "namespace/$lns/prefix")"
if [ $# -gt 0 ] && [ "$1" = "-s" ]; then
sub="-s"
shift
diff --git a/tests/snippets/dovecot/imapd.conf b/tests/snippets/dovecot/imapd.conf
new file mode 100644
index 0000000..c9926ce
--- /dev/null
+++ b/tests/snippets/dovecot/imapd.conf
@@ -0,0 +1,12 @@
+protocols = $protocols imap
+
+mail_plugins = $mail_plugins zlib
+protocol imap {
+ mail_plugins = $mail_plugins imap_zlib
+}
+
+service imap-login {
+ inet_listener imap {
+ port = 10143
+ }
+}
diff --git a/tests/snippets/dovecot/interimap-required-capabilities.conf b/tests/snippets/dovecot/interimap-required-capabilities.conf
new file mode 100644
index 0000000..10dd8e1
--- /dev/null
+++ b/tests/snippets/dovecot/interimap-required-capabilities.conf
@@ -0,0 +1,3 @@
+# strict minimum of IMAP capabilities required for interimap to work
+# (in particular, no LITERAL+, MULTIAPPEND, COMPRESS=DEFLATE, SASL-IR)
+imap_capability = IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS
diff --git a/tests/sync-live-crippled/interimap.remote b/tests/sync-live-crippled/interimap.remote
new file mode 120000
index 0000000..a4ea3f3
--- /dev/null
+++ b/tests/sync-live-crippled/interimap.remote
@@ -0,0 +1 @@
+../auth-sasl-plain/interimap.remote \ No newline at end of file
diff --git a/tests/sync-live-crippled/remote.conf b/tests/sync-live-crippled/remote.conf
index 76c08e0..ee22c5f 100644
--- a/tests/sync-live-crippled/remote.conf
+++ b/tests/sync-live-crippled/remote.conf
@@ -2,5 +2,5 @@ namespace inbox {
separator = ^
}
-# strict minimum of IMAP capabilities required for interimap to work
-imap_capability = IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS
+!include conf.d/imapd.conf
+!include conf.d/interimap-required-capabilities.conf