From 38b83c2b9329b8b16096d63e83f186c91d578ce8 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Jul 31 2024 20:19:02 +0000 Subject: Run HSM validation as pkiuser to verify token permissions Run all commands as pkiuser when validating that the HSM token is available, that the token library path is correct and that the password can read keys. This will avoid issues where the initial validation is ok but the pkiuser is not granted read access to some part of the token. This is very possible when using softhsm2. Fixes: https://pagure.io/freeipa/issue/9626 Signed-off-by: Rob Crittenden Reviewed-By: Florence Blanc-Renaud --- diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index e57dc47..9ff91b9 100644 --- a/ipaserver/install/ca.py +++ b/ipaserver/install/ca.py @@ -18,6 +18,7 @@ import six from ipalib.constants import IPA_CA_CN from ipalib.install import certstore from ipalib.install.service import enroll_only, master_install_only, replica_install_only +from ipaplatform.constants import constants from ipaserver.install import sysupgrade from ipapython.install import typing from ipapython.install.core import group, knob, extend_knob @@ -208,8 +209,15 @@ def hsm_validator(token_name, token_library, token_password): raise ValueError( "Token library path '%s' does not exist" % token_library ) + pkiuser = constants.PKI_USER + pkigroup = constants.PKI_GROUP + if 'libsofthsm' in token_library: + import grp + group = grp.getgrnam(constants.ODS_GROUP) + if str(constants.PKI_USER) in group.gr_mem: + pkigroup = constants.ODS_GROUP with certdb.NSSDatabase() as tempnssdb: - tempnssdb.create_db() + tempnssdb.create_db(user=str(pkiuser), group=str(pkigroup)) # Try adding the token library to the temporary database in # case it isn't already available. Ignore all errors. command = [ @@ -223,6 +231,7 @@ def hsm_validator(token_name, token_library, token_password): # It may fail if p11-kit has already registered the library, that's # ok. ipautil.run(command, stdin='\n', cwd=tempnssdb.secdir, + runas=pkiuser, suplementary_groups=[pkigroup], raiseonerr=False) command = [ @@ -232,7 +241,8 @@ def hsm_validator(token_name, token_library, token_password): '-force' ] lines = ipautil.run( - command, cwd=tempnssdb.secdir, capture_output=True).output + command, cwd=tempnssdb.secdir, capture_output=True, + runas=pkiuser, suplementary_groups=[pkigroup]).output found = False token_line = f'token: {token_name}' for line in lines.split('\n'): @@ -241,9 +251,11 @@ def hsm_validator(token_name, token_library, token_password): break if not found: raise ValueError( - "Token named '%s' was not found" % token_name + "Token named '%s' was not found. Check permissions" + % token_name ) pwdfile = ipautil.write_tmp_file(token_password) + os.fchown(pwdfile.fileno(), pkiuser.uid, pkigroup.gid) args = [ paths.CERTUTIL, "-d", '{}:{}'.format(tempnssdb.dbtype, tempnssdb.secdir), @@ -252,6 +264,8 @@ def hsm_validator(token_name, token_library, token_password): "-f", pwdfile.name, ] result = ipautil.run(args, cwd=tempnssdb.secdir, + runas=pkiuser, + suplementary_groups=[pkigroup], capture_error=True, raiseonerr=False) if result.returncode != 0 and len(result.error_output): if 'SEC_ERROR_BAD_PASSWORD' in result.error_output: diff --git a/ipatests/test_integration/test_hsm.py b/ipatests/test_integration/test_hsm.py index 6430546..974820f 100644 --- a/ipatests/test_integration/test_hsm.py +++ b/ipatests/test_integration/test_hsm.py @@ -833,6 +833,13 @@ class TestHSMNegative(IntegrationTest): cls.token_name, cls.token_password = get_hsm_token(cls.master) + @classmethod + def uninstall(cls, mh): + cls.master.run_command( + ['softhsm2-util', '--delete-token', '--token', cls.token_name], + raiseonerr=False + ) + def test_hsm_negative_wrong_token_details(self): check_version(self.master) # wrong token name @@ -868,6 +875,51 @@ class TestHSMNegative(IntegrationTest): ) assert result.returncode != 0 + def test_hsm_negative_bad_token_dir_permissions(self): + """Create an unreadable softhsm2 token and install should fail. + + This is most often seen on replicas where the pkiuser is not + a member of the ods group. + """ + check_version(self.master) + token_name = 'bad_perms' + token_passwd = 'Secret123' + self.master.run_command( + ['softhsm2-util', '--delete-token', '--token', token_name], + raiseonerr=False + ) + self.master.run_command( + ['usermod', 'pkiuser', '-a', '-G', 'ods'] + ) + self.master.run_command( + ['softhsm2-util', '--init-token', + '--free', '--pin', token_passwd, '--so-pin', token_passwd, + '--label', token_name] + ) + self.master.run_command( + ['usermod', 'pkiuser', '-r', '-G', 'ods'] + ) + result = tasks.install_master( + self.master, raiseonerr=False, + extra_args=( + '--token-name', token_name, + '--token-library-path', hsm_lib_path, + '--token-password', token_passwd + ) + ) + self.master.run_command( + ['usermod', 'pkiuser', '-a', '-G', 'ods'] + ) + self.master.run_command( + ['softhsm2-util', '--delete-token', '--token', token_name], + raiseonerr=False + ) + assert result.returncode != 0 + assert ( + f"Token named '{token_name}' was not found" + in result.stderr_text + ) + def test_hsm_negative_special_char_token_name(self): check_version(self.master) token_name = 'hsm:token' @@ -912,6 +964,11 @@ class TestHSMNegative(IntegrationTest): '--token-password-file', self.token_password_file ) ) + self.master.run_command( + ['softhsm2-util', '--delete-token', '--token', self.token_name], + raiseonerr=False + ) + # assert 'error message non existing token lib' in result.stderr_text assert result.returncode != 0