URL: https://github.com/freeipa/freeipa/pull/757 Author: tomaskrizek Title: #757: ca, kra install: validate DM password Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/757/head:pr757 git checkout pr757
From 2cce2304491ce575b6803ca4dd7d8f6630c57a35 Mon Sep 17 00:00:00 2001 From: Tomas Krizek <tkri...@redhat.com> Date: Wed, 3 May 2017 10:05:25 +0200 Subject: [PATCH 1/5] ca install: merge duplicated code for DM password Extract copy-pasted code to a single function. Related https://pagure.io/freeipa/issue/6892 Signed-off-by: Tomas Krizek <tkri...@redhat.com> --- install/tools/ipa-ca-install | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index 60261aa..da6e5c3 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -116,9 +116,19 @@ def parse_options(): return safe_options, options, filename -def get_dirman_password(): - return installutils.read_password( - "Directory Manager (existing master)", confirm=False, validate=False) +def _get_dirman_password(password=None, unattended=False): + if not password: + if unattended: + sys.exit('Directory Manager password required') + try: + password = installutils.read_password( + "Directory Manager (existing master)", confirm=False, + validate=False) + except KeyboardInterrupt: + sys.exit(0) + if password is None: + sys.exit("Directory Manager password required") + return password def install_replica(safe_options, options, filename): @@ -142,16 +152,8 @@ def install_replica(safe_options, options, filename): check_creds(options, api.env.realm) # get the directory manager password - dirman_password = options.password - if not dirman_password: - if options.unattended: - sys.exit('Directory Manager password required') - try: - dirman_password = get_dirman_password() - except KeyboardInterrupt: - sys.exit(0) - if dirman_password is None: - sys.exit("Directory Manager password required") + dirman_password = _get_dirman_password( + options.password, options.unattended) if (not options.promote and not options.admin_password and not options.skip_conncheck and options.unattended): @@ -199,16 +201,8 @@ def install_replica(safe_options, options, filename): def install_master(safe_options, options): - dm_password = options.password - if not dm_password: - if options.unattended: - sys.exit('Directory Manager password required') - try: - dm_password = get_dirman_password() - except KeyboardInterrupt: - sys.exit(0) - if dm_password is None: - sys.exit("Directory Manager password required") + dm_password = _get_dirman_password( + options.password, options.unattended) options.realm_name = api.env.realm options.domain_name = api.env.domain From e3e8f051220970f10a34c8297b1a381d1721b663 Mon Sep 17 00:00:00 2001 From: Tomas Krizek <tkri...@redhat.com> Date: Wed, 3 May 2017 10:01:09 +0200 Subject: [PATCH 2/5] installutils: add DM password validator Add a validator that checks whether provided Directory Manager is valid by attempting to connect to LDAP. Related https://pagure.io/freeipa/issue/6892 Signed-off-by: Tomas Krizek <tkri...@redhat.com> --- ipaserver/install/installutils.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 9230e70..b6f0148 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -50,6 +50,7 @@ from ipapython import ipautil, admintool, version from ipapython.admintool import ScriptError from ipapython.ipa_log_manager import root_logger +from ipapython.ipaldap import DIRMAN_DN, LDAPClient from ipalib.util import validate_hostname from ipalib import api, errors, x509 from ipapython.dn import DN @@ -329,6 +330,21 @@ def _read_password_default_validator(password): if len(password) < 8: raise ValueError("Password must be at least 8 characters long") + +def validate_dm_password_ldap(password): + """ + Validate DM password by attempting to connect to LDAP. api.env has to + contain valid ldap_uri. + """ + client = LDAPClient(api.env.ldap_uri, cacert=paths.IPA_CA_CRT) + try: + client.simple_bind(DIRMAN_DN, password) + except errors.ACIError: + raise ValueError("Invalid Directory Manager password") + else: + client.unbind() + + def read_password(user, confirm=True, validate=True, retry=True, validator=_read_password_default_validator): correct = False pwd = None From 230e835dc64bd0ddf3d900efa8c34001da8f3221 Mon Sep 17 00:00:00 2001 From: Tomas Krizek <tkri...@redhat.com> Date: Wed, 10 May 2017 09:36:52 +0200 Subject: [PATCH 3/5] kra install: use ScriptErrors instead RuntimeErrors Replace RuntimeErrors with ScriptErrors to be consistent with the rest of the code. Related https://pagure.io/freeipa/issue/6892 Signed-off-by: Tomas Krizek <tkri...@redhat.com> --- ipaserver/install/ipa_kra_install.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py index 8b1cb63..0da4f2e 100644 --- a/ipaserver/install/ipa_kra_install.py +++ b/ipaserver/install/ipa_kra_install.py @@ -138,8 +138,8 @@ def run(self): super(KRAInstaller, self).run() if not cainstance.is_ca_installed_locally(): - raise RuntimeError("Dogtag CA is not installed. " - "Please install the CA first") + raise admintool.ScriptError("Dogtag CA is not installed. " + "Please install the CA first") # check if KRA is not already installed _kra = krainstance.KRAInstance(api) @@ -155,11 +155,11 @@ def run(self): if domain_level > DOMAIN_LEVEL_0: self.options.promote = True elif not self.args: - raise RuntimeError("A replica file is required.") + raise admintool.ScriptError("A replica file is required.") if self.args and (not self.installing_replica or self.options.promote): - raise RuntimeError("Too many parameters provided. " - "No replica file is required.") + raise admintool.ScriptError("Too many parameters provided. " + "No replica file is required.") self.options.dm_password = self.options.password self.options.setup_ca = False From 8d13f2a638d254b3dd3b8045d43d7efeb4432e3b Mon Sep 17 00:00:00 2001 From: Tomas Krizek <tkri...@redhat.com> Date: Wed, 3 May 2017 10:16:13 +0200 Subject: [PATCH 4/5] ca, kra install: validate DM password Before proceeding with installation, validate DM password. If the provided DM password is invalid, abort the installation. Fixes https://pagure.io/freeipa/issue/6892 Signed-off-by: Tomas Krizek <tkri...@redhat.com> --- install/tools/ipa-ca-install | 19 ++++++++++--------- ipaserver/install/ipa_kra_install.py | 8 ++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install index da6e5c3..78c2d57 100755 --- a/install/tools/ipa-ca-install +++ b/install/tools/ipa-ca-install @@ -34,6 +34,7 @@ from ipaserver.install import cainstance, service from ipapython import version from ipalib import api from ipalib.constants import DOMAIN_LEVEL_0 +from ipapython.admintool import ScriptError from ipapython.config import IPAOptionParser from ipapython.ipa_log_manager import root_logger, standard_logging_setup from ipaplatform.paths import paths @@ -119,15 +120,15 @@ def parse_options(): def _get_dirman_password(password=None, unattended=False): if not password: if unattended: - sys.exit('Directory Manager password required') - try: - password = installutils.read_password( - "Directory Manager (existing master)", confirm=False, - validate=False) - except KeyboardInterrupt: - sys.exit(0) - if password is None: - sys.exit("Directory Manager password required") + raise ScriptError('Directory Manager password required') + password = installutils.read_password( + "Directory Manager (existing master)", confirm=False, + validate=False) + try: + installutils.validate_dm_password_ldap(password) + except ValueError: + raise ScriptError("Directory Manager password is invalid") + return password diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py index 0da4f2e..5b40267 100644 --- a/ipaserver/install/ipa_kra_install.py +++ b/ipaserver/install/ipa_kra_install.py @@ -137,6 +137,14 @@ def ask_for_options(self): def run(self): super(KRAInstaller, self).run() + # Verify DM password. This has to be called after ask_for_options(), + # so it can't be placed in validate_options(). + try: + installutils.validate_dm_password_ldap(self.options.password) + except ValueError: + raise admintool.ScriptError( + "Directory Manager password is invalid") + if not cainstance.is_ca_installed_locally(): raise admintool.ScriptError("Dogtag CA is not installed. " "Please install the CA first") From 46774281093a9b61cfaf7a7fdeed60031948ce4b Mon Sep 17 00:00:00 2001 From: Tomas Krizek <tkri...@redhat.com> Date: Wed, 10 May 2017 10:28:36 +0200 Subject: [PATCH 5/5] tests: make sure CA and KRA can handle incorrect dm password CA and KRA installation should be possible even if it has previously failed due to an incorrect Directory Manager passoword. Related https://pagure.io/freeipa/issue/6892 Signed-off-by: Tomas Krizek <tkri...@redhat.com> --- ipatests/pytest_plugins/integration/tasks.py | 16 +++++++++++---- ipatests/test_integration/test_installation.py | 28 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ipatests/pytest_plugins/integration/tasks.py b/ipatests/pytest_plugins/integration/tasks.py index 172f5b8..ccd6017 100644 --- a/ipatests/pytest_plugins/integration/tasks.py +++ b/ipatests/pytest_plugins/integration/tasks.py @@ -1156,20 +1156,28 @@ def ipa_restore(master, backup_path): backup_path]) -def install_kra(host, domain_level=None, first_instance=False, raiseonerr=True): +def install_kra(host, domain_level=None, first_instance=False, raiseonerr=True, + incorrect_dm_password=False): if domain_level is None: domain_level = domainlevel(host) - command = ["ipa-kra-install", "-U", "-p", host.config.dirman_password] + dm_password = host.config.dirman_password + if incorrect_dm_password: + dm_password += "x" + command = ["ipa-kra-install", "-U", "-p", dm_password] if domain_level == DOMAIN_LEVEL_0 and not first_instance: replica_file = get_replica_filename(host) command.append(replica_file) return host.run_command(command, raiseonerr=raiseonerr) -def install_ca(host, domain_level=None, first_instance=False, raiseonerr=True): +def install_ca(host, domain_level=None, first_instance=False, raiseonerr=True, + incorrect_dm_password=False): if domain_level is None: domain_level = domainlevel(host) - command = ["ipa-ca-install", "-U", "-p", host.config.dirman_password, + dm_password = host.config.dirman_password + if incorrect_dm_password: + dm_password += "x" + command = ["ipa-ca-install", "-U", "-p", dm_password, "-P", 'admin', "-w", host.config.admin_password] if domain_level == DOMAIN_LEVEL_0 and not first_instance: replica_file = get_replica_filename(host) diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py index b13c999..fa90a12 100644 --- a/ipatests/test_integration/test_installation.py +++ b/ipatests/test_integration/test_installation.py @@ -81,6 +81,8 @@ def test_replica2_ipa_ca_install(self): tasks.install_ca(self.replicas[2]) def test_replica2_ipa_kra_install(self): + tasks.install_kra(self.replica[2], incorrect_dm_password=True, + raiseonerr=False) tasks.install_kra(self.replicas[2]) @@ -312,3 +314,29 @@ def test_install_master(self): def test_install_kra(self): tasks.install_kra(self.master, first_instance=True) + + +## +# Single replica installation tests +## + +class TestInstallReplicaCA_KRA_Incorrect_Password(IntegrationTest): + + num_replicas = 1 + topology = 'star' + + @classmethod + def install(cls, mh): + tasks.install_master(cls.master, setup_dns=False) + + def test_replica0_ipa_ca_install(self): + tasks.install_ca(self.replicas[0], incorrect_dm_password=True, + raiseonerr=False) + tasks.install_ca(self.replicas[0]) + + def test_replica0_ipa_kra_install(self): + tasks.install_kra(self.replicas[0], incorrect_dm_password=True, + raiseonerr=False) + tasks.install_kra(self.replicas[0]) + +
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code