# # 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 . ###### # 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 ' % \ 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 = "9977d846539d4945900bd04bae25bf746ac75fb561d3769014002db04e1790b8" 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 key in users: tasks.user_add( self.master, users[key]["uid"], extra_args=[ "--password-expiration", users[key]["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