From 46234f0cb91ad892b7420eb061e758e26c64e3c7 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Fri, 17 May 2019 14:27:46 +0300 Subject: [PATCH] test_ipagetkeytab: test retrieval of explicit encryption types In order to test a fix for https://pagure.io/freeipa/issue/7953, we need to create a keytab with a particular encryption type (arcfour-hmac) and attempt to request generation of ipaNTHash attribute from Kerberos keys in LDAP. Add a test case that performs this operation. Related: https://pagure.io/freeipa/issue/7953 Reviewed-By: Christian Heimes --- ipatests/test_cmdline/test_ipagetkeytab.py | 105 +++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/ipatests/test_cmdline/test_ipagetkeytab.py b/ipatests/test_cmdline/test_ipagetkeytab.py index 419de86e2..deb9e5f84 100644 --- a/ipatests/test_cmdline/test_ipagetkeytab.py +++ b/ipatests/test_cmdline/test_ipagetkeytab.py @@ -37,6 +37,7 @@ from ipapython import ipautil, ipaldap from ipaserver.plugins.ldap2 import ldap2 from ipatests.test_cmdline.cmdline import cmdline_test from ipatests.test_xmlrpc.tracker import host_plugin, service_plugin +from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_digits, add_oc from contextlib import contextmanager @@ -362,3 +363,107 @@ class TestBindMethods(KeytabRetrievalTest): '-H', 'ldaps://{}'.format(api.env.host), '-Y', 'EXTERNAL'], raiseonerr=False) + + +class SMBServiceTracker(service_plugin.ServiceTracker): + def __init__(self, name, host_fqdn, options=None): + super(SMBServiceTracker, self).__init__(name, host_fqdn, + options=options) + # Create SMB service principal that has POSIX attributes to allow + # generating SID and adding proper objectclasses + self.create_keys |= {u'uidnumber', u'gidnumber'} + self.options[u'addattr'] = [ + u'objectclass=ipaIDObject', u'uidNumber=-1', u'gidNumber=-1'] + + def track_create(self, **options): + super(SMBServiceTracker, self).track_create(**options) + self.attrs[u'uidnumber'] = [fuzzy_digits] + self.attrs[u'gidnumber'] = [fuzzy_digits] + self.attrs[u'objectclass'].append(u'ipaIDObject') + + +@pytest.fixture(scope='class') +def test_smb_svc(request, test_host): + service_tracker = SMBServiceTracker(u'cifs', test_host.name) + test_host.ensure_exists() + return service_tracker.make_fixture(request) + + +@pytest.mark.tier0 +@pytest.mark.xfail(reason="freeipa ticket 7953", strict=True) +@pytest.mark.skipif(u'ipantuserattrs' not in add_oc([], u'ipantuserattrs'), + reason="Must have trust support enabled for this test") +class test_smb_service(KeytabRetrievalTest): + """ + Test `ipa-getkeytab` for retrieving explicit enctypes + """ + command = "ipa-getkeytab" + keytabname = None + + @classmethod + def setup_class(cls): + super(test_smb_service, cls).setup_class() + + try: + cls.dm_password = retrieve_dm_password() + except errors.NotFound as e: + pytest.skip(e.args) + + def test_create(self, test_smb_svc): + """ + Create a keytab with `ipa-getkeytab` for an existing service. + """ + test_smb_svc.ensure_exists() + + # Request a keytab with explicit encryption types + enctypes = ['aes128-cts-hmac-sha1-96', + 'aes256-cts-hmac-sha1-96', 'arcfour-hmac'] + args = ['-e', ','.join(enctypes), '-s', api.env.host] + self.assert_success(test_smb_svc.name, args=args, raiseonerr=True) + + def test_use(self, test_smb_svc): + """ + Try to use the service keytab to regenerate ipaNTHash value + """ + # Step 1. Extend objectclass to allow ipaNTHash attribute + # We cannot verify write access to objectclass + with use_keytab(test_smb_svc.name, self.keytabname) as conn: + entry = conn.get_entry(test_smb_svc.dn, ['objectclass']) + entry['objectclass'].extend(['ipaNTUserAttrs']) + try: + conn.update_entry(entry) + except errors.ACIError: + assert ('No correct ACI to the allow ipaNTUserAttrs ' + 'for SMB service' in "failure") + + # Step 2. With ipaNTUserAttrs in place, we can ask to regenerate + # ipaNTHash value. We can also verify it is possible to write to + # ipaNTHash attribute while being an SMB service + with use_keytab(test_smb_svc.name, self.keytabname) as conn: + assert conn.can_write(test_smb_svc.dn, 'ipaNTHash') is True + entry = conn.get_entry(test_smb_svc.dn, ['ipaNTHash']) + entry['ipanthash'] = b'MagicRegen' + try: + conn.update_entry(entry) + except errors.ACIError: + assert ("No correct ACI to the ipaNTHash for SMB service" + in "failure") + except errors.EmptyResult: + assert "No arcfour-hmac in Kerberos keys" in "failure" + except errors.DatabaseError: + # Most likely ipaNTHash already existed -- we either get + # OPERATIONS_ERROR or UNWILLING_TO_PERFORM, both map to + # the same DatabaseError class. + assert "LDAP Entry corruption after generation" in "failure" + + # Update succeeded, now we have either MagicRegen (broken) or + # a real NT hash in the entry. However, we can only retrieve it as + # a cn=Directory Manager. When bind_dn is None, ldap2.connect() wil + # default to cn=Directory Manager. + conn = ldap2(api) + conn.connect(bind_dn=None, bind_pw=self.dm_password, + autobind=ipaldap.AUTOBIND_DISABLED) + entry = conn.retrieve(test_smb_svc.dn, ['ipaNTHash']) + ipanthash = entry.single_value.get('ipanthash') + conn.disconnect() + assert ipanthash is not b'MagicRegen', 'LDBM backend entry corruption'