docker-mailserver/test/tests/parallel/set1/spam_virus/rspamd_dkim.bats

275 lines
10 KiB
Bash

load "${REPOSITORY_ROOT}/test/helper/common"
load "${REPOSITORY_ROOT}/test/helper/setup"
BATS_TEST_NAME_PREFIX='[Rspamd] (DKIM) '
CONTAINER_NAME='dms-test_rspamd-dkim'
DOMAIN_NAME='example.test'
SIGNING_CONF_FILE='/tmp/docker-mailserver/rspamd/override.d/dkim_signing.conf'
function setup_file() {
_init_with_defaults
# Comment for maintainers about `PERMIT_DOCKER=host`:
# https://github.com/docker-mailserver/docker-mailserver/pull/2815/files#r991087509
local CUSTOM_SETUP_ARGUMENTS=(
--env ENABLE_RSPAMD=1
--env ENABLE_OPENDKIM=0
--env ENABLE_OPENDMARC=0
--env ENABLE_POLICYD_SPF=0
--env LOG_LEVEL=trace
--env OVERRIDE_HOSTNAME="mail.${DOMAIN_NAME}"
)
_common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
_wait_for_service rspamd-redis
_wait_for_service rspamd
}
# We want each test to start with a clean state.
function teardown() {
__remove_signing_config_file
_run_in_container rm -rf /tmp/docker-mailserver/rspamd/dkim
assert_success
}
function teardown_file() { _default_teardown ; }
@test 'log level is applied correctly' {
_run_in_container setup config dkim -vv help
__log_is_free_of_warnings_and_errors
assert_output --partial 'Enabled trace-logging'
_run_in_container setup config dkim -v help
__log_is_free_of_warnings_and_errors
assert_output --partial 'Enabled debug-logging'
}
@test 'help message is properly shown' {
_run_in_container setup config dkim help
__log_is_free_of_warnings_and_errors
assert_output --partial 'Showing usage message now'
assert_output --partial 'rspamd-dkim - Configure DKIM (DomainKeys Identified Mail)'
}
@test 'default signing config is created if it does not exist and not overwritten' {
# Required pre-condition: no default configuration is present
__remove_signing_config_file
__create_key
assert_success
__log_is_free_of_warnings_and_errors
assert_output --partial "Supplying a default configuration (to '${SIGNING_CONF_FILE}')"
refute_output --partial "'${SIGNING_CONF_FILE}' exists, not supplying a default"
assert_output --partial "Finished DKIM key creation"
_file_exists_in_container "${SIGNING_CONF_FILE}"
_exec_in_container_bash "echo 'blabla' >${SIGNING_CONF_FILE}"
local INITIAL_SHA512_SUM=$(_exec_in_container sha512sum "${SIGNING_CONF_FILE}")
__create_key
assert_failure
assert_output --partial "Not overwriting existing files (use '--force' to overwrite existing files)"
# the same as before, but with the '--force' option
__create_key 'rsa' 'mail' "${DOMAIN_NAME}" '2048' '--force'
__log_is_free_of_warnings_and_errors
refute_output --partial "Supplying a default configuration ('${SIGNING_CONF_FILE}')"
assert_output --partial "Overwriting existing files as the '--force' option was supplied"
assert_output --partial "'${SIGNING_CONF_FILE}' exists, not supplying a default"
assert_output --partial "Finished DKIM key creation"
local SECOND_SHA512_SUM=$(_exec_in_container sha512sum "${SIGNING_CONF_FILE}")
assert_equal "${INITIAL_SHA512_SUM}" "${SECOND_SHA512_SUM}"
}
@test 'default directories and files are created' {
__create_key
assert_success
_count_files_in_directory_in_container /tmp/docker-mailserver/rspamd/dkim/ 3
_file_exists_in_container "${SIGNING_CONF_FILE}"
__check_path_in_signing_config "/tmp/docker-mailserver/rspamd/dkim/rsa-2048-mail-${DOMAIN_NAME}.private.txt"
__check_selector_in_signing_config 'mail'
}
@test "argument 'domain' is applied correctly" {
for DOMAIN in 'blabla.org' 'someother.com' 'random.de'; do
_run_in_container setup config dkim domain "${DOMAIN}"
assert_success
assert_line --partial "Domain set to '${DOMAIN}'"
local BASE_FILE_NAME="/tmp/docker-mailserver/rspamd/dkim/rsa-2048-mail-${DOMAIN}"
__check_key_files_are_present "${BASE_FILE_NAME}"
__check_path_in_signing_config "${BASE_FILE_NAME}.private.txt"
__remove_signing_config_file
done
}
@test "argument 'keytype' is applied correctly" {
_run_in_container setup config dkim keytype foobar
assert_failure
assert_line --partial "Unknown keytype 'foobar'"
for KEYTYPE in 'rsa' 'ed25519'; do
_run_in_container setup config dkim keytype "${KEYTYPE}"
assert_success
assert_line --partial "Keytype set to '${KEYTYPE}'"
local BASE_FILE_NAME="/tmp/docker-mailserver/rspamd/dkim/ed25519-mail-${DOMAIN_NAME}"
[[ ${KEYTYPE} == 'rsa' ]] && BASE_FILE_NAME="/tmp/docker-mailserver/rspamd/dkim/rsa-2048-mail-${DOMAIN_NAME}"
__check_key_files_are_present "${BASE_FILE_NAME}"
_run_in_container grep ".*k=${KEYTYPE};.*" "${BASE_FILE_NAME}.public.txt"
assert_success
_run_in_container grep ".*k=${KEYTYPE};.*" "${BASE_FILE_NAME}.public.dns.txt"
assert_success
__check_path_in_signing_config "${BASE_FILE_NAME}.private.txt"
__remove_signing_config_file
done
}
@test "argument 'selector' is applied correctly" {
for SELECTOR in 'foo' 'bar' 'baz'; do
__create_key 'rsa' "${SELECTOR}"
assert_success
assert_line --partial "Selector set to '${SELECTOR}'"
local BASE_FILE_NAME="/tmp/docker-mailserver/rspamd/dkim/rsa-2048-${SELECTOR}-${DOMAIN_NAME}"
__check_key_files_are_present "${BASE_FILE_NAME}"
_run_in_container grep "^${SELECTOR}\._domainkey.*" "${BASE_FILE_NAME}.public.txt"
assert_success
__check_rsa_keys 2048 "${SELECTOR}-${DOMAIN_NAME}"
__check_path_in_signing_config "${BASE_FILE_NAME}.private.txt"
__check_selector_in_signing_config "${SELECTOR}"
__remove_signing_config_file
done
}
@test "argument 'keysize' is applied correctly for RSA keys" {
for KEYSIZE in 1024 2048 4096; do
__create_key 'rsa' 'mail' "${DOMAIN_NAME}" "${KEYSIZE}"
assert_success
__log_is_free_of_warnings_and_errors
assert_line --partial "Keysize set to '${KEYSIZE}'"
__check_rsa_keys "${KEYSIZE}" "mail-${DOMAIN_NAME}"
__remove_signing_config_file
done
}
@test "when 'keytype=ed25519' is set, setting custom 'keysize' is rejected" {
__create_key 'ed25519' 'mail' "${DOMAIN_NAME}" 4096
assert_failure
assert_line --partial "Chosen keytype does not accept the 'keysize' argument"
}
@test "setting all arguments to a custom value works" {
local KEYTYPE='ed25519'
local SELECTOR='someselector'
local DOMAIN='dms.org'
__create_key "${KEYTYPE}" "${SELECTOR}" "${DOMAIN}"
assert_success
__log_is_free_of_warnings_and_errors
assert_line --partial "Keytype set to '${KEYTYPE}'"
assert_line --partial "Selector set to '${SELECTOR}'"
assert_line --partial "Domain set to '${DOMAIN}'"
local BASE_FILE_NAME="/tmp/docker-mailserver/rspamd/dkim/${KEYTYPE}-${SELECTOR}-${DOMAIN}"
__check_path_in_signing_config "${BASE_FILE_NAME}.private.txt"
__check_selector_in_signing_config 'someselector'
}
# Create DKIM keys.
#
# @param ${1} = keytype (default: rsa)
# @param ${2} = selector (default: mail)
# @param ${3} = domain (default: ${DOMAIN})
# @param ${4} = keysize (default: 2048)
function __create_key() {
local KEYTYPE=${1:-rsa}
local SELECTOR=${2:-mail}
local DOMAIN=${3:-${DOMAIN_NAME}}
local KEYSIZE=${4:-2048}
local FORCE=${5:-}
# Not quoting is intended here as we would othewise provide
# the argument "''" (empty string), which would cause errors
# shellcheck disable=SC2086
_run_in_container setup config dkim ${FORCE} \
keytype "${KEYTYPE}" \
keysize "${KEYSIZE}" \
selector "${SELECTOR}" \
domain "${DOMAIN}"
}
# Check whether an RSA key is created successfully and correctly
# for a specific key size.
#
# @param ${1} = key size
# @param ${2} = name of the selector and domain name (as one string)
function __check_rsa_keys() {
local KEYSIZE=${1:?Keysize must be supplied to __check_rsa_keys}
local SELECTOR_AND_DOMAIN=${2:?Selector and domain name must be supplied to __check_rsa_keys}
local BASE_FILE_NAME="/tmp/docker-mailserver/rspamd/dkim/rsa-${KEYSIZE}-${SELECTOR_AND_DOMAIN}"
__check_key_files_are_present "${BASE_FILE_NAME}"
__check_path_in_signing_config "${BASE_FILE_NAME}.private.txt"
# Check the private key matches the specification
_run_in_container_bash "openssl rsa -in '${BASE_FILE_NAME}.private.txt' -noout -text"
assert_success
assert_line --index 0 "Private-Key: (${KEYSIZE} bit, 2 primes)"
# Check the public key matches the specification
#
# We utilize the file for the DNS record contents which is already created
# by the Rspamd DKIM helper script. This makes parsing easier here.
local PUBKEY PUBKEY_INFO
PUBKEY=$(_exec_in_container_bash "grep -o 'p=.*' ${BASE_FILE_NAME}.public.dns.txt")
_run_in_container_bash "openssl enc -base64 -d <<< ${PUBKEY#p=} | openssl pkey -inform DER -pubin -noout -text"
assert_success
assert_line --index 0 "Public-Key: (${KEYSIZE} bit)"
}
# Verify that all DKIM key files are present.
#
# @param ${1} = base file name that all DKIM key files have
function __check_key_files_are_present() {
local BASE_FILE_NAME="${1:?Base file name must be supplied to __check_key_files_are_present}"
for FILE in ${BASE_FILE_NAME}.{public.txt,public.dns.txt,private.txt}; do
_file_exists_in_container "${FILE}"
done
}
# Check whether `path = .*` is set correctly in the signing configuration file.
#
# @param ${1} = file name that `path` should be set to
function __check_path_in_signing_config() {
local BASE_FILE_NAME=${1:?Base file name must be supplied to __check_path_in_signing_config}
_run_in_container grep "[[:space:]]*path = \"${BASE_FILE_NAME}\";" "${SIGNING_CONF_FILE}"
assert_success
}
# Check whether `selector = .*` is set correctly in the signing configuration file.
#
# @param ${1} = name that `selector` should be set to
function __check_selector_in_signing_config() {
local SELECTOR=${1:?Selector name must be supplied to __check_selector_in_signing_config}
_run_in_container grep "[[:space:]]*selector = \"${SELECTOR}\";" "${SIGNING_CONF_FILE}"
assert_success
}
# Check whether the script output is free of warnings and errors.
function __log_is_free_of_warnings_and_errors() {
assert_success
refute_output --partial '[ WARN ]'
refute_output --partial '[ ERROR ]'
}
# Remove the signing configuration file inside the container.
function __remove_signing_config_file() {
_exec_in_container rm -f "${SIGNING_CONF_FILE}"
}