From 30471ebdc9fe5871c115ca06f78a415275a320e6 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 16 Jun 2022 20:02:51 +0000 Subject: [PATCH] Skip AD domains with posix ranges in the catalog check The catalog check is intended to ensure that the trust is working by looking up a user. For a non-posix range we can use the Administrator user because it has a predicible SID. With a posix range the UID/GID may not be set so the lookup can fail (with an empty return value). So skip domain which have a posix range associated with it. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1775199 Signed-off-by: Rob Crittenden --- src/ipahealthcheck/ipa/trust.py | 34 ++++- tests/test_ipa_trust.py | 214 +++++++++++++++++++++++++++++++- 2 files changed, 243 insertions(+), 5 deletions(-) diff --git a/src/ipahealthcheck/ipa/trust.py b/src/ipahealthcheck/ipa/trust.py index 27a2c86..b962807 100644 --- a/src/ipahealthcheck/ipa/trust.py +++ b/src/ipahealthcheck/ipa/trust.py @@ -183,6 +183,7 @@ class IPATrustDomainsCheck(IPAPlugin): except Exception as e: yield Result(self, constants.WARNING, key='domain-status', + domain=domain, error=str(e), msg='Execution of {key} failed: {error}') continue @@ -262,6 +263,10 @@ class IPATrustCatalogCheck(IPAPlugin): This should populate the 'AD Global catalog' and 'AD Domain Controller' fields in 'sssctl domain-status' output (means SSSD actually talks to AD DCs) + + If the associated idrange type is ipa-ad-trust-posix then the + check will be skipped because we can't predict what the UID of the + Administrator account will be. """ @duration def check(self): @@ -280,20 +285,41 @@ class IPATrustCatalogCheck(IPAPlugin): for trust_domain in trust_domains: sid = trust_domain.get('domainsid') + domain = trust_domain['domain'] + idrange = api.Command.idrange_find(sid) + if len(idrange['result']) == 0: + yield Result(self, constants.WARNING, + key=sid, + domain=domain, + msg='Domain {domain} does not have an idrange') + continue + + if 'ipa-ad-trust-posix' in idrange['result'][0]['iparangetyperaw']: + yield Result(self, constants.SUCCESS, + key=sid, + domain=domain, + type='ipa-ad-trust-posix') + logger.debug("Domain %s is a POSIX range, skip the lookup", + domain) + continue + try: id = pysss_nss_idmap.getnamebysid(sid + '-500') except Exception as e: yield Result(self, constants.ERROR, - key=sid, + key=id, + domain=domain, error=str(e), - msg='Look up of{key} failed: {error}') + msg='Look up of ID {key} for {domain} failed: ' + '{error}') continue if not id: yield Result(self, constants.WARNING, - key=sid, + key=id, + domain=trust_domain['domain'], error='returned nothing', - msg='Look up of {key} {error}') + msg='Look up of ID {key} for {domain} {error}') else: yield Result(self, constants.SUCCESS, key='Domain Security Identifier', diff --git a/tests/test_ipa_trust.py b/tests/test_ipa_trust.py index c314b70..6c4754a 100644 --- a/tests/test_ipa_trust.py +++ b/tests/test_ipa_trust.py @@ -129,6 +129,74 @@ def trustdomain_find(): ] +def idrange_find_adrange_type(): + """ + Return a set of idranges of type "Active Directory domain range" + """ + + return { + "result": [ + { + "cn": ["AD.EXAMPLE_id_range"], + "ipabaseid": ["1664000000"], + "ipabaserid": ["0"], + "ipaidrangesize": ["200000"], + "ipanttrusteddomainsid": ["S-1-5-21-abc"], + "iparangetype": ["Active Directory domain range"], + "iparangetyperaw": ["ipa-ad-trust"] + }, + { + "cn": ["CHILD.AD.EXAMPLE_id_range"], + "ipabaseid": ["538600000"], + "ipabaserid": ["0"], + "ipaidrangesize": ["200000"], + "ipanttrusteddomainsid": [ + "S-1-5-21-38045160-610119595-3099869984" + ], + "iparangetype": ["Active Directory domain range"], + "iparangetyperaw": ["ipa-ad-trust"] + }, + { + "cn": ["IPA.EXAMPLE_id_range"], + "ipabaseid": ["447400000"], + "ipabaserid": ["1000"], + "ipaidrangesize": ["200000"], + "iparangetype": ["local domain range"], + "iparangetyperaw": ["ipa-local"], + "ipasecondarybaserid": ["100000000"] + }] + } + + +def idrange_find_adrange_posix(): + """ + Return a set of idranges of type + "Active Directory trust range with POSIX attributes" + """ + + return { + "result": [ + { + "cn": ["AD.EXAMPLE_id_range"], + "ipabaseid": ["1664000000"], + "ipaidrangesize": ["200000"], + "ipanttrusteddomainsid": ["S-1-5-21-abc"], + "iparangetype": [ + "Active Directory trust range with POSIX attributes"], + "iparangetyperaw": ["ipa-ad-trust-posix"] + }, + { + "cn": ["IPA.EXAMPLE_id_range"], + "ipabaseid": ["447400000"], + "ipabaserid": ["1000"], + "ipaidrangesize": ["200000"], + "iparangetype": ["local domain range"], + "iparangetyperaw": ["ipa-local"], + "ipasecondarybaserid": ["100000000"] + }] + } + + class SSSDDomain: def __init__(self, return_ipa_server_mode=True, provider='ipa'): self.return_ipa_server_mode = return_ipa_server_mode @@ -454,7 +522,8 @@ class TestTrustCatalog(BaseTest): @patch('pysss_nss_idmap.getnamebysid') @patch('ipapython.ipautil.run') - def test_trust_catalog_ok(self, mock_run, mock_getnamebysid): + def test_trust_catalog_adrange(self, mock_run, mock_getnamebysid): + """The associated ID ranges are Active Directory domain range""" # id Administrator@ad.example dsresult = namedtuple('run', ['returncode', 'error_log']) dsresult.returncode = 0 @@ -478,6 +547,11 @@ class TestTrustCatalog(BaseTest): # get_trust_domains() m_api.Command.trust_find.side_effect = trust_find() m_api.Command.trustdomain_find.side_effect = trustdomain_find() + m_api.Command.idrange_find.side_effect = [ + idrange_find_adrange_type(), + idrange_find_adrange_type(), + idrange_find_adrange_type() + ] framework = object() registry.initialize(framework, config.Config) @@ -550,6 +624,144 @@ class TestTrustCatalog(BaseTest): assert result.kw.get('key') == 'AD Domain Controller' assert result.kw.get('domain') == 'child.example' + @patch('pysss_nss_idmap.getnamebysid') + @patch('ipapython.ipautil.run') + def test_trust_catalog_posix(self, mock_run, mock_getnamebysid): + """AD POSIX ranges""" + # id Administrator@ad.example + dsresult = namedtuple('run', ['returncode', 'error_log']) + dsresult.returncode = 0 + dsresult.error_log = '' + dsresult.output = 'Active servers:\nAD Global Catalog: ' \ + 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \ + 'IPA: master.ipa.vm\n\n' + ds2result = namedtuple('run', ['returncode', 'error_log']) + ds2result.returncode = 0 + ds2result.error_log = '' + ds2result.output = 'Active servers:\nAD Global Catalog: ' \ + 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \ + + mock_run.side_effect = [dsresult, dsresult, ds2result] + mock_getnamebysid.side_effect = [ + {'S-1-5-21-abc-500': {'name': 'admin@ad.example', 'type': 3}}, + {'S-1-5-21-ghi-500': {'name': 'admin@child.ad.example', 'type': 3}}, + {'S-1-5-21-def-500': {'name': 'admin@child.example', 'type': 3}} + ] + + # get_trust_domains() + m_api.Command.trust_find.side_effect = trust_find() + m_api.Command.trustdomain_find.side_effect = trustdomain_find() + m_api.Command.idrange_find.side_effect = [ + idrange_find_adrange_posix(), + idrange_find_adrange_posix(), + idrange_find_adrange_posix() + ] + + framework = object() + registry.initialize(framework, config.Config) + registry.trust_agent = True + f = IPATrustCatalogCheck(registry) + + self.results = capture_results(f) + + assert len(self.results) == 3 + + result = self.results.results[0] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'S-1-5-21-abc' + assert result.kw.get('domain') == 'ad.example' + assert result.kw.get('type') == 'ipa-ad-trust-posix' + + result = self.results.results[1] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'S-1-5-22-def' + assert result.kw.get('domain') == 'child.ad.example' + assert result.kw.get('type') == 'ipa-ad-trust-posix' + + result = self.results.results[2] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'S-1-5-21-ghi' + assert result.kw.get('domain') == 'child.example' + assert result.kw.get('type') == 'ipa-ad-trust-posix' + + @patch('pysss_nss_idmap.getnamebysid') + @patch('ipapython.ipautil.run') + def test_trust_catalog_posix_missing(self, mock_run, mock_getnamebysid): + """AD POSIX ranges""" + # id Administrator@ad.example + dsresult = namedtuple('run', ['returncode', 'error_log']) + dsresult.returncode = 0 + dsresult.error_log = '' + dsresult.output = 'Active servers:\nAD Global Catalog: ' \ + 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \ + 'IPA: master.ipa.vm\n\n' + ds2result = namedtuple('run', ['returncode', 'error_log']) + ds2result.returncode = 0 + ds2result.error_log = '' + ds2result.output = 'Active servers:\nAD Global Catalog: ' \ + 'root-dc.ad.vm\nAD Domain Controller: root-dc.ad.vm\n' \ + + mock_run.side_effect = [dsresult, dsresult, ds2result] + mock_getnamebysid.side_effect = [ + {'S-1-5-21-abc-500': {'name': 'admin@ad.example', 'type': 3}}, + {'S-1-5-21-ghi-500': {'name': 'admin@child.ad.example', 'type': 3}}, + {'S-1-5-21-def-500': {'name': 'admin@child.example', 'type': 3}} + ] + + # get_trust_domains() + m_api.Command.trust_find.side_effect = trust_find() + m_api.Command.trustdomain_find.side_effect = trustdomain_find() + m_api.Command.idrange_find.side_effect = [ + idrange_find_adrange_posix(), + {'result': []}, + {'result': []} + ] + + framework = object() + registry.initialize(framework, config.Config) + registry.trust_agent = True + f = IPATrustCatalogCheck(registry) + + self.results = capture_results(f) + + assert len(self.results) == 3 + + result = self.results.results[0] + assert result.result == constants.SUCCESS + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'S-1-5-21-abc' + assert result.kw.get('domain') == 'ad.example' + assert result.kw.get('type') == 'ipa-ad-trust-posix' + + result = self.results.results[1] + assert result.result == constants.WARNING + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'S-1-5-22-def' + assert result.kw.get('domain') == 'child.ad.example' + assert ( + result.kw.get('msg') + == 'Domain {domain} does not have an idrange' + ) + + result = self.results.results[2] + assert result.result == constants.WARNING + assert result.source == 'ipahealthcheck.ipa.trust' + assert result.check == 'IPATrustCatalogCheck' + assert result.kw.get('key') == 'S-1-5-21-ghi' + assert result.kw.get('domain') == 'child.example' + assert ( + result.kw.get('msg') + == 'Domain {domain} does not have an idrange' + ) + class Testsidgen(BaseTest): patches = { -- 2.39.2