From 38b83c2b9329b8b16096d63e83f186c91d578ce8 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 10 Jul 2024 16:14:46 -0400 Subject: [PATCH] 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 --- ipaserver/install/ca.py | 20 ++++++++-- ipatests/test_integration/test_hsm.py | 57 +++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py index e57dc47587fa0e0a6dbbe7511784af065560d782..9ff91b9cc42673138eee6fa8e0eb46b323be8b1d 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 64305460a5150dfc28a4ab378ac72cd38987184c..974820fc7363b77fd5fdecc7cf0efca412f3af42 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 -- 2.45.2