mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
The test test_epn.py::TestEPN::test_EPN_config_file ensures that
/etc/ipa/epn.conf is installed and compares its checksum with an
expected value.
Commit fcad9c9 has changed the content of the file and the cksum
must be updated to reflect the new content.
Fixes: https://pagure.io/freeipa/issue/9419
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
845 lines
30 KiB
Python
845 lines
30 KiB
Python
#
|
|
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
######
|
|
# This test suite will _expectedly_ fail if run at the end of the UTC day
|
|
# because users would be created during day N and then EPN output checked
|
|
# during day N+1. This is expected and should be ignored as it does not
|
|
# reflect a product bug. -- fcami
|
|
######
|
|
|
|
from __future__ import print_function, absolute_import
|
|
|
|
import base64
|
|
import datetime
|
|
import email
|
|
import json
|
|
import logging
|
|
import os
|
|
import pytest
|
|
import textwrap
|
|
|
|
from subprocess import CalledProcessError
|
|
|
|
from ipaplatform.paths import paths
|
|
from ipatests.test_integration.base import IntegrationTest
|
|
from ipatests.pytest_ipa.integration.firewall import Firewall
|
|
from ipatests.pytest_ipa.integration import tasks
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
EPN_PKG = ["*ipa-client-epn"]
|
|
|
|
SMTP_CLIENT_CERT = os.path.join(paths.OPENSSL_CERTS_DIR, "smtp_client.pem")
|
|
SMTP_CLIENT_KEY = os.path.join(paths.OPENSSL_PRIVATE_DIR, "smtp_client.key")
|
|
SMTP_CLIENT_KEY_PASS = "Secret123"
|
|
|
|
SMTPD_KEY = os.path.join(paths.OPENSSL_PRIVATE_DIR, "postfix.key")
|
|
SMTPD_CERT = os.path.join(paths.OPENSSL_CERTS_DIR, "postfix.pem")
|
|
|
|
DEFAULT_EPN_CONF = textwrap.dedent(
|
|
"""\
|
|
[global]
|
|
"""
|
|
)
|
|
|
|
USER_EPN_CONF = DEFAULT_EPN_CONF + textwrap.dedent(
|
|
"""\
|
|
smtp_user={user}
|
|
smtp_password={password}
|
|
"""
|
|
)
|
|
|
|
STARTTLS_EPN_CONF = USER_EPN_CONF + textwrap.dedent(
|
|
"""\
|
|
smtp_server={server}
|
|
smtp_security=starttls
|
|
"""
|
|
)
|
|
|
|
SSL_EPN_CONF = USER_EPN_CONF + textwrap.dedent(
|
|
"""\
|
|
smtp_server={server}
|
|
smtp_port=465
|
|
smtp_security=ssl
|
|
"""
|
|
)
|
|
|
|
CLIENT_CERT_EPN_CONF = textwrap.dedent(
|
|
"""\
|
|
smtp_client_cert={client_cert}
|
|
smtp_client_key={client_key}
|
|
smtp_client_key_pass={client_key_pass}
|
|
"""
|
|
)
|
|
|
|
def datetime_to_generalized_time(dt):
|
|
"""Convert datetime to LDAP_GENERALIZED_TIME_FORMAT
|
|
Note: Move into ipalib.
|
|
"""
|
|
dt = dt.timetuple()
|
|
generalized_time_str = str(dt.tm_year) + "".join(
|
|
"0" * (2 - len(str(item))) + str(item)
|
|
for item in (dt.tm_mon, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec,)
|
|
)
|
|
return generalized_time_str + "Z"
|
|
|
|
|
|
def postconf(host, option):
|
|
host.run_command(r"postconf -e '%s'" % option)
|
|
|
|
|
|
def configure_postfix(host, realm):
|
|
"""Configure postfix for:
|
|
* SASL auth
|
|
* to be the destination of the IPA domain.
|
|
"""
|
|
# Setup the keytab we need for SASL auth
|
|
host.run_command(r"ipa service-add smtp/%s --force" % host.hostname)
|
|
host.run_command(r"ipa-getkeytab -p smtp/%s -k /etc/postfix/smtp.keytab" %
|
|
host.hostname)
|
|
host.run_command(r"chown root:mail /etc/postfix/smtp.keytab")
|
|
host.run_command(r"chmod 640 /etc/postfix/smtp.keytab")
|
|
|
|
# Configure the SASL smtp service to use GSSAPI
|
|
host.run_command(
|
|
r"sed -i 's/plain login/GSSAPI plain login/' /etc/sasl2/smtpd.conf")
|
|
host.run_command(
|
|
r"sed -i 's/MECH=pam/MECH=kerberos5/' /etc/sysconfig/saslauthd")
|
|
postconf(host,
|
|
'import_environment = MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ '
|
|
'XAUTHORITY DISPLAY LANG=C KRB5_KTNAME=/etc/postfix/smtp.keytab')
|
|
postconf(host,
|
|
'smtpd_client_restrictions = permit_sasl_authenticated, reject')
|
|
postconf(host,
|
|
'smtpd_recipient_restrictions = permit_sasl_authenticated, reject')
|
|
postconf(host,
|
|
'smtpd_sender_restrictions = permit_sasl_authenticated, reject')
|
|
postconf(host, 'smtpd_sasl_auth_enable = yes')
|
|
postconf(host, 'smtpd_sasl_security_options = noanonymous')
|
|
postconf(host,
|
|
'smtpd_sasl_tls_security_options = $smtpd_sasl_security_options')
|
|
postconf(host, 'broken_sasl_auth_clients = yes')
|
|
postconf(host, 'smtpd_sasl_authenticated_header = yes')
|
|
postconf(host, 'smtpd_sasl_local_domain = %s' % realm)
|
|
# TLS will not be used
|
|
postconf(host, 'smtpd_tls_security_level = none')
|
|
|
|
# disable procmail if exists, make use of default local(8) delivery agent
|
|
postconf(host, "mailbox_command=")
|
|
|
|
# listen on all active interfaces
|
|
postconf(host, "inet_interfaces = all")
|
|
|
|
host.run_command(["systemctl", "restart", "saslauthd"])
|
|
|
|
result = host.run_command(["postconf", "mydestination"])
|
|
mydestination = result.stdout_text.strip() + ", " + host.domain.name
|
|
postconf(host, mydestination)
|
|
|
|
host.run_command(["systemctl", "restart", "postfix"])
|
|
|
|
|
|
def configure_starttls(host):
|
|
"""Obtain a TLS cert for the host and configure postfix for starttls
|
|
|
|
Depends on configure_postfix() being executed first.
|
|
"""
|
|
|
|
host.run_command(["rm", "-f", SMTPD_KEY, SMTPD_CERT])
|
|
host.run_command(["ipa-getcert", "request",
|
|
"-f", SMTPD_CERT,
|
|
"-k", SMTPD_KEY,
|
|
"-K", "smtp/%s" % host.hostname,
|
|
"-D", host.hostname,
|
|
"-O", "postfix",
|
|
"-o", "postfix",
|
|
"-M", "0640",
|
|
"-m", "0640",
|
|
"-w",
|
|
])
|
|
postconf(host, 'smtpd_tls_loglevel = 1')
|
|
postconf(host, 'smtpd_tls_auth_only = yes')
|
|
postconf(host, "smtpd_tls_key_file = {}".format(SMTPD_KEY))
|
|
postconf(host, "smtpd_tls_cert_file = {}".format(SMTPD_CERT))
|
|
postconf(host, 'smtpd_tls_received_header = yes')
|
|
postconf(host, 'smtpd_tls_session_cache_timeout = 3600s')
|
|
# announce STARTTLS support to remote SMTP clients, not require
|
|
postconf(host, 'smtpd_tls_security_level = may')
|
|
|
|
host.run_command(["systemctl", "restart", "postfix"])
|
|
|
|
|
|
def configure_ssl_client_cert(host):
|
|
"""Obtain a TLS cert for the SMTP client and configure postfix for client
|
|
certificate verification.
|
|
|
|
Depends on configure_starttls().
|
|
"""
|
|
host.run_command(["rm", "-f", SMTP_CLIENT_KEY, SMTP_CLIENT_CERT])
|
|
|
|
host.run_command(["ipa-getcert", "request",
|
|
"-f", SMTP_CLIENT_CERT,
|
|
"-k", SMTP_CLIENT_KEY,
|
|
"-K", "smtp_client/%s" % host.hostname,
|
|
"-D", host.hostname,
|
|
"-P", "Secret123",
|
|
"-w",
|
|
])
|
|
|
|
# mandatory TLS encryption
|
|
postconf(host, "smtpd_tls_security_level = encrypt")
|
|
# require a trusted remote SMTP client certificate
|
|
postconf(host, "smtpd_tls_req_ccert = yes")
|
|
# CA certificates of root CAs trusted to sign remote SMTP client cert
|
|
postconf(host, f"smtpd_tls_CAfile = {paths.IPA_CA_CRT}")
|
|
|
|
host.run_command(["systemctl", "restart", "postfix"])
|
|
|
|
|
|
def configure_ssl(host):
|
|
"""Enable the ssl listener on port 465.
|
|
"""
|
|
conf = host.get_file_contents('/etc/postfix/master.cf',
|
|
encoding='utf-8')
|
|
conf += 'smtps inet n - n - - smtpd\n'
|
|
conf += ' -o syslog_name=postfix/smtps\n'
|
|
conf += ' -o smtpd_tls_wrappermode=yes\n'
|
|
conf += ' -o smtpd_sasl_auth_enable=yes\n'
|
|
host.put_file_contents('/etc/postfix/master.cf', conf)
|
|
|
|
host.run_command(["systemctl", "restart", "postfix"])
|
|
|
|
|
|
def decode_header(header):
|
|
"""Decode the header if needed and return the value"""
|
|
# Only support one value for now
|
|
(value, encoding) = email.header.decode_header(header)[0]
|
|
if encoding:
|
|
return value.decode(encoding)
|
|
else:
|
|
return value
|
|
|
|
|
|
def validate_mail(host, id, content):
|
|
"""Retrieve a remote e-mail and determine if it matches the current user"""
|
|
mail = host.get_file_contents('/var/mail/user%d' % id)
|
|
msg = email.message_from_bytes(mail)
|
|
assert decode_header(msg['To']) == 'user%d@%s' % (id, host.domain.name)
|
|
assert decode_header(msg['From']) == 'IPA-EPN <noreply@%s>' % \
|
|
host.domain.name
|
|
assert decode_header(msg['subject']) == 'Your password will expire soon.'
|
|
|
|
for part in msg.walk():
|
|
if part.get_content_maintype() == 'multipart':
|
|
continue
|
|
body = part.get_payload()
|
|
decoded = base64.b64decode(body).decode('utf-8')
|
|
assert content in decoded
|
|
|
|
|
|
class TestEPN(IntegrationTest):
|
|
"""Test Suite for EPN: https://pagure.io/freeipa/issue/3687
|
|
"""
|
|
|
|
num_clients = 1
|
|
notify_ttls = (28, 14, 7, 3, 1)
|
|
|
|
def _check_epn_output(
|
|
self,
|
|
host,
|
|
dry_run=False,
|
|
mailtest=False,
|
|
from_nbdays=None,
|
|
to_nbdays=None,
|
|
raiseonerr=True,
|
|
validatejson=True
|
|
):
|
|
result = tasks.ipa_epn(
|
|
host,
|
|
from_nbdays=from_nbdays,
|
|
to_nbdays=to_nbdays,
|
|
mailtest=mailtest,
|
|
dry_run=dry_run,
|
|
raiseonerr=raiseonerr
|
|
)
|
|
if validatejson:
|
|
json.dumps(json.loads(result.stdout_text), ensure_ascii=False)
|
|
return (result.stdout_text, result.stderr_text, result.returncode)
|
|
|
|
@classmethod
|
|
def install(cls, mh):
|
|
# External DNS is only available before install so cache a copy
|
|
# of the *ipa-epn-client package so we can experimentally remove
|
|
# it later.
|
|
#
|
|
# Notes:
|
|
# - A package can't be downloaded that is already installed so we
|
|
# have to remove it first.
|
|
# - dnf cleans up previously downloaded locations so make a copy it
|
|
# doesn't know about.
|
|
# - Adds a class variable, pkg, containing the package name of
|
|
# the downloaded *ipa-client-epn rpm.
|
|
hosts = [cls.master, cls.clients[0]]
|
|
tasks.uninstall_packages(cls.clients[0],EPN_PKG)
|
|
pkgdir = tasks.download_packages(cls.clients[0], EPN_PKG)
|
|
pkg = cls.clients[0].run_command(r'ls -1 {}'.format(pkgdir))
|
|
cls.pkg = pkg.stdout_text.strip()
|
|
cls.clients[0].run_command(['cp',
|
|
os.path.join(pkgdir, cls.pkg),
|
|
'/tmp'])
|
|
cls.clients[0].run_command(r'rm -rf {}'.format(pkgdir))
|
|
|
|
for host in hosts:
|
|
tasks.install_packages(host, EPN_PKG + ["postfix"])
|
|
try:
|
|
tasks.install_packages(host, ["cyrus-sasl"])
|
|
except Exception:
|
|
# the package is likely already installed
|
|
pass
|
|
|
|
tasks.install_master(cls.master, setup_dns=True)
|
|
tasks.install_client(cls.master, cls.clients[0])
|
|
for host in hosts:
|
|
configure_postfix(host, cls.master.domain.realm)
|
|
Firewall(host).enable_services(["smtp", "smtps"])
|
|
|
|
|
|
@classmethod
|
|
def uninstall(cls, mh):
|
|
super(TestEPN, cls).uninstall(mh)
|
|
tasks.uninstall_packages(cls.master,EPN_PKG)
|
|
tasks.uninstall_packages(cls.master, ["postfix"])
|
|
tasks.uninstall_packages(cls.clients[0], EPN_PKG)
|
|
tasks.uninstall_packages(cls.clients[0], ["postfix"])
|
|
cls.master.run_command(r'rm -f /etc/postfix/smtp.keytab')
|
|
|
|
for cert in [SMTPD_CERT, SMTP_CLIENT_CERT]:
|
|
cls.master.run_command(["getcert", "stop-tracking", "-f", cert])
|
|
|
|
cls.master.run_command(
|
|
[
|
|
"rm",
|
|
"-f",
|
|
SMTPD_CERT,
|
|
SMTPD_KEY,
|
|
SMTP_CLIENT_CERT,
|
|
SMTP_CLIENT_KEY,
|
|
]
|
|
)
|
|
|
|
@pytest.mark.skip_if_platform(
|
|
"debian", reason="Cannot check installed packages using RPM"
|
|
)
|
|
def test_EPN_config_file(self):
|
|
"""Check that the EPN configuration file is installed.
|
|
https://pagure.io/freeipa/issue/8374
|
|
"""
|
|
epn_conf = "/etc/ipa/epn.conf"
|
|
epn_template = "/etc/ipa/epn/expire_msg.template"
|
|
if tasks.get_platform(self.master) != "fedora":
|
|
cmd1 = self.master.run_command(["rpm", "-qc", "ipa-client-epn"])
|
|
else:
|
|
cmd1 = self.master.run_command(["rpm", "-qc", "freeipa-client-epn"])
|
|
assert epn_conf in cmd1.stdout_text
|
|
assert epn_template in cmd1.stdout_text
|
|
cmd2 = self.master.run_command(["sha256sum", epn_conf])
|
|
ck = "06a73f15562686516c984dd9fe61689c5268ff1c5a13e69f8b347afef41b3277"
|
|
assert cmd2.stdout_text.find(ck) == 0
|
|
|
|
def test_EPN_connection_refused(self):
|
|
"""Test EPN behavior when the configured SMTP is down
|
|
"""
|
|
|
|
self.master.run_command(["systemctl", "stop", "postfix"])
|
|
(unused, stderr_text, rc) = self._check_epn_output(
|
|
self.master, mailtest=True,
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
self.master.run_command(["systemctl", "start", "postfix"])
|
|
assert "IPA-EPN: Could not connect to the configured SMTP server" in \
|
|
stderr_text
|
|
assert rc > 0
|
|
|
|
def test_EPN_no_security_downgrade_starttls(self):
|
|
"""Configure postfix without starttls and test no auth happens
|
|
"""
|
|
epn_conf = STARTTLS_EPN_CONF.format(
|
|
server=self.master.hostname,
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
|
|
(unused, stderr_text, rc) = self._check_epn_output(
|
|
self.master, mailtest=True,
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
expected_msg = "IPA-EPN: Unable to create an encrypted session to"
|
|
assert expected_msg in stderr_text
|
|
assert rc > 0
|
|
|
|
def test_EPN_no_security_downgrade_tls(self):
|
|
"""Configure postfix without tls and test no auth happens
|
|
"""
|
|
epn_conf = SSL_EPN_CONF.format(
|
|
server=self.master.hostname,
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
|
|
(unused, stderr_text, rc) = self._check_epn_output(
|
|
self.master, mailtest=True,
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
expected_msg = (
|
|
"IPA-EPN: Could not connect to the configured SMTP "
|
|
"server"
|
|
)
|
|
assert expected_msg in stderr_text
|
|
assert rc > 0
|
|
|
|
def test_EPN_smoketest_1(self):
|
|
"""No users except admin. Check --dry-run output.
|
|
With the default configuration, the result should be an empty list.
|
|
Also check behavior on master and client alike.
|
|
"""
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', DEFAULT_EPN_CONF)
|
|
# check EPN on client (LDAP+GSSAPI)
|
|
(stdout_text, unused, _unused) = self._check_epn_output(
|
|
self.clients[0], dry_run=True
|
|
)
|
|
assert len(json.loads(stdout_text)) == 0
|
|
# check EPN on master (LDAPI)
|
|
(stdout_text, unused, _unused) = self._check_epn_output(
|
|
self.master, dry_run=True
|
|
)
|
|
assert len(json.loads(stdout_text)) == 0
|
|
|
|
@pytest.fixture
|
|
def cleanupusers(self):
|
|
"""Fixture to remove any users added as part of the tests.
|
|
|
|
It isn't necessary to remove all users created.
|
|
|
|
Ignore all errors.
|
|
"""
|
|
yield
|
|
for user in ["testuser0", "testuser1"]:
|
|
try:
|
|
self.master.run_command(['ipa', 'user-del', user])
|
|
except Exception:
|
|
pass
|
|
|
|
@pytest.fixture
|
|
def cleanupmail(self):
|
|
"""Cleanup any existing mail that has been sent."""
|
|
cmd = ["rm", "-f"]
|
|
for i in range(30):
|
|
cmd.append("/var/mail/user%d" % i)
|
|
self.master.run_command(cmd)
|
|
|
|
def test_EPN_smoketest_2(self, cleanupusers):
|
|
"""Add a user without password.
|
|
Add a user whose password expires within the default time range.
|
|
Check --dry-run output.
|
|
"""
|
|
tasks.user_add(self.master, "testuser0")
|
|
tasks.user_add(
|
|
self.master,
|
|
"testuser1",
|
|
password="Secret123",
|
|
extra_args=[
|
|
"--password-expiration",
|
|
datetime_to_generalized_time(
|
|
datetime.datetime.utcnow() + datetime.timedelta(days=7)
|
|
),
|
|
],
|
|
)
|
|
(stdout_text_client, unused, _unused) = self._check_epn_output(
|
|
self.clients[0], dry_run=True
|
|
)
|
|
(stdout_text_master, unused, _unused) = self._check_epn_output(
|
|
self.master, dry_run=True
|
|
)
|
|
assert stdout_text_master == stdout_text_client
|
|
assert "testuser0" not in stdout_text_client
|
|
assert "testuser1" in stdout_text_client
|
|
|
|
def test_EPN_smoketest_3(self):
|
|
"""Add a bunch of users with incrementally expiring passwords
|
|
(one per day). Check --dry-run output.
|
|
"""
|
|
|
|
users = {}
|
|
userbase_str = "user"
|
|
|
|
for i in range(30):
|
|
uid = userbase_str + str(i)
|
|
users[i] = dict(
|
|
uid=uid,
|
|
days=i,
|
|
krbpasswordexpiration=datetime_to_generalized_time(
|
|
datetime.datetime.utcnow() + datetime.timedelta(days=i)
|
|
),
|
|
)
|
|
|
|
for user_info in users.values():
|
|
tasks.user_add(
|
|
self.master,
|
|
user_info["uid"],
|
|
extra_args=[
|
|
"--password-expiration",
|
|
user_info["krbpasswordexpiration"],
|
|
],
|
|
password=None,
|
|
)
|
|
|
|
(stdout_text_client, unused, _unused) = self._check_epn_output(
|
|
self.clients[0], dry_run=True
|
|
)
|
|
(stdout_text_master, unused, _unused) = self._check_epn_output(
|
|
self.master, dry_run=True
|
|
)
|
|
assert stdout_text_master == stdout_text_client
|
|
user_lst = []
|
|
for user in json.loads(stdout_text_master):
|
|
user_lst.append(user["uid"])
|
|
expected_users = ["user1", "user3", "user7", "user14", "user28"]
|
|
assert sorted(user_lst) == sorted(expected_users)
|
|
|
|
def test_EPN_nbdays_0(self, cleanupmail):
|
|
"""Test the to/from nbdays options (implies --dry-run)
|
|
|
|
We have a set of users installed with varying expiration
|
|
dates. Confirm that to/from nbdays finds them.
|
|
|
|
Make sure --dry-run does not accidentally send emails.
|
|
"""
|
|
|
|
# Use the notify_ttls values with a 1-day sliding window
|
|
for i in self.notify_ttls:
|
|
user_list = []
|
|
(stdout_text_client, unused, _unused) = self._check_epn_output(
|
|
self.clients[0], from_nbdays=i, to_nbdays=i + 1, dry_run=True
|
|
)
|
|
for user in json.loads(stdout_text_client):
|
|
user_list.append(user["uid"])
|
|
assert len(user_list) == 1
|
|
userid = "user{id}".format(id=i)
|
|
assert user_list[0] == userid
|
|
|
|
# Check that the user list is expected for any given notify_ttls.
|
|
(stdout_text_client, unused, _unused) = self._check_epn_output(
|
|
self.clients[0], to_nbdays=i
|
|
)
|
|
user_list = [user["uid"] for user in json.loads(stdout_text_client)]
|
|
assert len(user_list) == 1
|
|
assert user_list[0] == "user{id}".format(id=i - 1)
|
|
|
|
# make sure no emails were sent
|
|
result = self.clients[0].run_command(['ls', '-lha', '/var/mail/'])
|
|
assert userid not in result.stdout_text
|
|
|
|
def test_EPN_nbdays_1(self, cleanupmail):
|
|
"""Test that for a given range, we find the users in that range"""
|
|
|
|
# Use hardcoded date ranges for now
|
|
for date_range in [(0, 5), (7, 15), (1, 20)]:
|
|
expected_user_list = ["user{i}".format(i=i)
|
|
for i in range(date_range[0], date_range[1])]
|
|
(stdout_text_client, unused, _unused) = self._check_epn_output(
|
|
self.clients[0],
|
|
from_nbdays=date_range[0],
|
|
to_nbdays=date_range[1]
|
|
)
|
|
user_list = [user["uid"] for user in json.loads(stdout_text_client)]
|
|
for user in expected_user_list:
|
|
assert user in user_list
|
|
for user in user_list:
|
|
assert user in expected_user_list
|
|
|
|
# Test the to/from nbdays options behavior with illegal input
|
|
|
|
def test_EPN_nbdays_input_0(self):
|
|
"""Make sure that --to-nbdays implies --dry-run ;
|
|
therefore check that the output is valid JSON and contains the
|
|
expected user.
|
|
"""
|
|
|
|
(stdout_text_client, unused, _unused) = self._check_epn_output(
|
|
self.clients[0], to_nbdays=5, dry_run=False
|
|
)
|
|
assert len(json.loads(stdout_text_client)) == 1
|
|
assert json.loads(stdout_text_client)[0]["uid"] == "user4"
|
|
|
|
def test_EPN_nbdays_input_1(self):
|
|
"""Make sure that --from-nbdays cannot be used without --to-nbdays"""
|
|
|
|
(unused, stderr_text_client, rc) = \
|
|
self._check_epn_output(
|
|
self.clients[0], from_nbdays=3,
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
assert "You cannot specify --from-nbdays without --to-nbdays" \
|
|
in stderr_text_client
|
|
assert rc > 0
|
|
|
|
def test_EPN_nbdays_input_2(self):
|
|
"""alpha input"""
|
|
|
|
(unused, stderr, rc) = self._check_epn_output(
|
|
self.clients[0], to_nbdays="abc",
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
assert "error: --to-nbdays must be a positive integer." in stderr
|
|
assert rc > 0
|
|
|
|
def test_EPN_nbdays_input_3(self):
|
|
"""from_nbdays > to_nbdays"""
|
|
|
|
(unused, stderr, rc) = self._check_epn_output(
|
|
self.clients[0], from_nbdays=9, to_nbdays=7,
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
assert "error: --from-nbdays must be smaller than --to-nbdays." in \
|
|
stderr
|
|
assert rc > 0
|
|
|
|
def test_EPN_nbdays_input_4(self):
|
|
"""decimal input"""
|
|
|
|
(unused, stderr, rc) = self._check_epn_output(
|
|
self.clients[0], to_nbdays=7.3,
|
|
raiseonerr=False, validatejson=False
|
|
)
|
|
logger.info(stderr)
|
|
assert rc > 0
|
|
assert "error: --to-nbdays must be a positive integer." in stderr
|
|
|
|
# From here the tests build on one another:
|
|
# 1) add auth
|
|
# 2) tweak the template
|
|
# 3) add starttls
|
|
|
|
def test_EPN_authenticated(self, cleanupmail):
|
|
"""Enable authentication and test that mail is delivered
|
|
"""
|
|
epn_conf = USER_EPN_CONF.format(
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
|
|
tasks.ipa_epn(self.master)
|
|
for i in self.notify_ttls:
|
|
validate_mail(self.master, i,
|
|
"Hi test user,\n\nYour password will expire")
|
|
|
|
def test_EPN_template(self, cleanupmail):
|
|
"""Modify the template to ensure changes are applied.
|
|
"""
|
|
exp_msg = textwrap.dedent('''
|
|
Hi {{ first }} {{last}},
|
|
Your login entry {{uid}} is going to expire on
|
|
{{ expiration }}. Please change it soon.
|
|
|
|
Your friendly neighborhood admins.
|
|
''')
|
|
self.master.put_file_contents('/etc/ipa/epn/expire_msg.template',
|
|
exp_msg)
|
|
|
|
tasks.ipa_epn(self.master)
|
|
for i in self.notify_ttls:
|
|
validate_mail(self.master, i,
|
|
"Hi test user,\nYour login entry user%d is going" % i)
|
|
|
|
def test_mailtest(self, cleanupmail):
|
|
"""Execute mailtest to validate mail is working
|
|
|
|
Set of of our pre-created users as the smtp_admin to receive
|
|
the mail, run ipa-epn --mailtest, then validate the result.
|
|
|
|
Using a non-expired user here, user2, to receive the result.
|
|
"""
|
|
epn_conf = (
|
|
USER_EPN_CONF
|
|
+ textwrap.dedent(
|
|
"""\
|
|
smtp_admin=user2@{domain}
|
|
"""
|
|
)
|
|
).format(
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
domain=self.master.domain.name,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
|
|
tasks.ipa_epn(self.master, mailtest=True)
|
|
validate_mail(self.master, 2,
|
|
"Hi SAMPLE USER,\nYour login entry SAUSER is going")
|
|
|
|
def test_mailtest_dry_run(self):
|
|
try:
|
|
tasks.ipa_epn(self.master, mailtest=True, dry_run=True)
|
|
except CalledProcessError as e:
|
|
assert 'You cannot specify' in e.stderr
|
|
else:
|
|
raise AssertionError('--mail-test and --dry-run aren\'t supposed '
|
|
'to succeed')
|
|
|
|
def test_EPN_starttls(self, cleanupmail):
|
|
"""Configure with starttls and test delivery
|
|
"""
|
|
epn_conf = STARTTLS_EPN_CONF.format(
|
|
server=self.master.hostname,
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
configure_starttls(self.master)
|
|
|
|
tasks.ipa_epn(self.master)
|
|
for i in self.notify_ttls:
|
|
validate_mail(self.master, i,
|
|
"Hi test user,\nYour login entry user%d is going" % i)
|
|
|
|
def test_EPN_ssl(self, cleanupmail):
|
|
"""Configure with ssl and test delivery
|
|
"""
|
|
epn_conf = SSL_EPN_CONF.format(
|
|
server=self.master.hostname,
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
configure_ssl(self.master)
|
|
|
|
tasks.ipa_epn(self.master)
|
|
for i in self.notify_ttls:
|
|
validate_mail(self.master, i,
|
|
"Hi test user,\nYour login entry user%d is going" % i)
|
|
|
|
def test_EPN_ssl_client_cert(self, cleanupmail):
|
|
"""Configure with ssl + client certificate and test delivery
|
|
"""
|
|
epn_conf = (SSL_EPN_CONF + CLIENT_CERT_EPN_CONF).format(
|
|
server=self.master.hostname,
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
client_cert=SMTP_CLIENT_CERT,
|
|
client_key=SMTP_CLIENT_KEY,
|
|
client_key_pass=SMTP_CLIENT_KEY_PASS,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
configure_ssl_client_cert(self.master)
|
|
|
|
tasks.ipa_epn(self.master)
|
|
for i in self.notify_ttls:
|
|
validate_mail(
|
|
self.master,
|
|
i,
|
|
"Hi test user,\nYour login entry user%d is going" % i
|
|
)
|
|
|
|
def test_EPN_starttls_client_cert(self, cleanupmail):
|
|
"""Configure with starttls + client certificate and test delivery
|
|
"""
|
|
epn_conf = (STARTTLS_EPN_CONF + CLIENT_CERT_EPN_CONF).format(
|
|
server=self.master.hostname,
|
|
user=self.master.config.admin_name,
|
|
password=self.master.config.admin_password,
|
|
client_cert=SMTP_CLIENT_CERT,
|
|
client_key=SMTP_CLIENT_KEY,
|
|
client_key_pass=SMTP_CLIENT_KEY_PASS,
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
|
|
tasks.ipa_epn(self.master)
|
|
for i in self.notify_ttls:
|
|
validate_mail(
|
|
self.master,
|
|
i,
|
|
"Hi test user,\nYour login entry user%d is going" % i
|
|
)
|
|
|
|
def test_EPN_delay_config(self, cleanupmail):
|
|
"""Test the smtp_delay configuration option
|
|
"""
|
|
epn_conf = DEFAULT_EPN_CONF + textwrap.dedent(
|
|
"""\
|
|
smtp_delay=A
|
|
"""
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
|
|
result = tasks.ipa_epn(self.master, raiseonerr=False)
|
|
assert "could not convert string to float: 'A'" in result.stderr_text
|
|
|
|
epn_conf = DEFAULT_EPN_CONF + textwrap.dedent(
|
|
"""\
|
|
smtp_delay=-1
|
|
"""
|
|
)
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', epn_conf)
|
|
result = tasks.ipa_epn(self.master, raiseonerr=False)
|
|
assert "smtp_delay cannot be less than zero" in result.stderr_text
|
|
|
|
def test_EPN_admin(self):
|
|
"""The admin user is special and has no givenName by default
|
|
It also doesn't by default have an e-mail address
|
|
Check --dry-run output.
|
|
"""
|
|
self.master.put_file_contents('/etc/ipa/epn.conf', DEFAULT_EPN_CONF)
|
|
self.master.run_command(
|
|
['ipa', 'user-mod', 'admin', '--password-expiration',
|
|
datetime_to_generalized_time(
|
|
datetime.datetime.utcnow() + datetime.timedelta(days=7)
|
|
)]
|
|
)
|
|
(unused, stderr_text, _unused) = self._check_epn_output(
|
|
self.master, dry_run=True
|
|
)
|
|
assert "uid=admin" in stderr_text
|
|
|
|
@pytest.mark.skip_if_platform(
|
|
"debian", reason="Don't know how to download-only pkgs in Debian"
|
|
)
|
|
def test_EPN_reinstall(self):
|
|
"""Test that EPN can be installed, uninstalled and reinstalled.
|
|
|
|
Since post-install we no longer have access to the repos
|
|
the package is downloaded and stored prior to server
|
|
installation.
|
|
"""
|
|
tasks.uninstall_packages(self.clients[0], EPN_PKG)
|
|
tasks.install_packages(self.clients[0],
|
|
[os.path.join('/tmp', self.pkg)])
|
|
self.clients[0].run_command(r'rm -f /tmp/{}'.format(self.pkg))
|
|
|
|
# re-installing will create a new epn.conf so any execution
|
|
# of ipa-epn will verify the reinstall was ok. Since the previous
|
|
# test would have failed this one should be ok with new config.
|
|
|
|
# Re-run the admin user expected failure
|
|
(unused, stderr_text, _unused) = self._check_epn_output(
|
|
self.master, dry_run=True
|
|
)
|
|
assert "uid=admin" in stderr_text
|