diff --git a/docs/shared_combiners_catalog/sssd_conf.rst b/docs/shared_combiners_catalog/sssd_conf.rst new file mode 100644 index 0000000000..05ebfba40c --- /dev/null +++ b/docs/shared_combiners_catalog/sssd_conf.rst @@ -0,0 +1,3 @@ +.. automodule:: insights.combiners.sssd_conf + :members: + :show-inheritance: diff --git a/insights/combiners/identity_domain.py b/insights/combiners/identity_domain.py index e0c0cb43ed..fd146f1295 100644 --- a/insights/combiners/identity_domain.py +++ b/insights/combiners/identity_domain.py @@ -49,7 +49,7 @@ from insights.core.plugins import combiner from insights.combiners.ipa import IPA from insights.parsers.samba import SambaConfigs -from insights.parsers.sssd_conf import SSSD_Config +from insights.combiners.sssd_conf import SSSDConfAll from insights.combiners.krb5 import AllKrb5Conf @@ -124,7 +124,7 @@ class IPAMode(object): """ -@combiner(optional=[SSSD_Config, AllKrb5Conf, IPA, SambaConfigs]) +@combiner(optional=[SSSDConfAll, AllKrb5Conf, IPA, SambaConfigs]) class IdentityDomain(object): """ A combiner for identity domains. @@ -186,7 +186,7 @@ def _parse_sssd(self, sssd, ipa): Supports id_providers "ad", "ipa", and "ldap". """ id_auth_providers = set(["ldap", "krb5", "ipa", "ad", "proxy"]) - for name in sssd.domains: + for name in sssd.enabled_domains: if "/" in name: # Ignore trusted domain (subdomain) configuration. Subdomain # settings are configured as @@ -207,7 +207,7 @@ def _parse_sssd(self, sssd, ipa): dtype = DomainTypes.AD_SSSD srv = ServerSoftware.AD domain = conf.get("ad_domain", name) - realm = conf.get("krb5_domain", domain.upper()) + realm = conf.get("krb5_realm", domain.upper()) elif id_provider == "ipa": if ipa is None or not ipa.is_client: # unsupported configuration @@ -215,7 +215,7 @@ def _parse_sssd(self, sssd, ipa): dtype = DomainTypes.IPA srv = ServerSoftware.IPA domain = conf.get("ipa_domain", name) - realm = conf.get("krb5_domain", domain.upper()) + realm = conf.get("krb5_realm", domain.upper()) ipa_mode = IPAMode.IPA_SERVER if ipa.is_server else IPAMode.IPA_CLIENT elif id_provider == "ldap": if auth_provider == "ldap": @@ -278,7 +278,10 @@ def _parse_smb(self, smb): def _parse_krb5(self, krb5): """Parse krb5.conf to detect additional generic Kerberos realms""" - for realm in krb5.realms: + for realm in sorted(krb5.realms): + if realm in self._realms: + continue + self._add_domaininfo( realm.lower(), DomainTypes.KRB5, diff --git a/insights/combiners/ipa.py b/insights/combiners/ipa.py index 21306d1b6d..7d08c94292 100644 --- a/insights/combiners/ipa.py +++ b/insights/combiners/ipa.py @@ -2,35 +2,35 @@ IPA - Combiner for RHEL IdM / FreeIPA information ================================================= """ -from insights.core.plugins import combiner + +from insights.combiners.sssd_conf import SSSDConfAll from insights.core.exceptions import SkipComponent +from insights.core.plugins import combiner from insights.parsers.installed_rpms import InstalledRpms -from insights.parsers.redhat_release import RedhatRelease from insights.parsers.ipa_conf import IPAConfig -from insights.parsers.sssd_conf import SSSD_Config -@combiner(IPAConfig, SSSD_Config, InstalledRpms, RedhatRelease) +@combiner(IPAConfig, SSSDConfAll, InstalledRpms) class IPA(object): """Combiner for IPA, SSSD, and installed RPMs Provides additional information, e.g. whether the host is an IPA server. """ - def __init__(self, ipa_conf, sssd_conf, rpms, release): + def __init__(self, ipa_conf, sssd_conf, rpms): self._ipa_conf = ipa_conf self._sssd_conf = sssd_conf - # IPA package names are different on Fedora - if release.is_fedora: - self._client_rpm = rpms.get_max("freeipa-client") - self._server_rpm = rpms.get_max("freeipa-server") - else: - self._client_rpm = rpms.get_max("ipa-client") - self._server_rpm = rpms.get_max("ipa-server") - if self._client_rpm is None: - raise SkipComponent("IPA client package is not installed") + self._is_client = None self._is_server = None + self._ipa_domains = None + + self._check_installed_packages(rpms) + + def _check_installed_packages(self, rpms): + # IPA is relying on SSSD which will be installed on both client and server + if rpms.get_max("sssd") is None: + raise SkipComponent("sssd package is not installed") @property def ipa_conf(self): @@ -43,21 +43,23 @@ def sssd_conf(self): return self._sssd_conf @property - def sssd_domain_config(self): - """Get SSSD domain configuration for host's IPA domain""" - return self._sssd_conf.domain_config(self._ipa_conf.domain) + def sssd_ipa_domains(self): + """Get all SSSD domains where id_provider is set to ipa""" + if self._ipa_domains is None: + self._ipa_domains = [] + for domain in self.sssd_conf.enabled_domains: + id_provider = self.sssd_conf.domain_get(domain, "id_provider") + if id_provider == "ipa": + self._ipa_domains.append(domain) + + return self._ipa_domains @property def is_client(self): """Is the host an IPA client?""" - # IPAConfig validates that /etc/ipa/default.conf exists and is a - # valid IPA config file with all required values present. + # Check if there is at least one IPA domain in SSSD. if self._is_client is None: - id_provider = self.sssd_domain_config.get("id_provider") - if id_provider == "ipa": - self._is_client = True - else: - self._is_client = False + self._is_client = len(self.sssd_ipa_domains) > 0 return self._is_client @@ -65,20 +67,13 @@ def is_client(self): def is_server(self): """Is the host an IPA server?""" if self._is_server is None: - server_mode = self.sssd_domain_config.get( - "ipa_server_mode", "false" - ) - if ( - self._server_rpm and - # all servers are also clients - self.is_client and - # only servers use LDAPI (LDAP over Unix socket) - self._ipa_conf.ldap_uri.startswith("ldapi://") and - # SSSD domain must be in server mode - server_mode.lower() == "true" - ): - self._is_server = True - else: - self._is_server = False + for domain in self.sssd_ipa_domains: + self._is_server = self.sssd_conf.domain_getboolean( + domain, "ipa_server_mode", False + ) + + # Break if there is at least one IPA domain in server mode + if self._is_server: + break return self._is_server diff --git a/insights/combiners/sssd_conf.py b/insights/combiners/sssd_conf.py new file mode 100644 index 0000000000..bb1a845c8f --- /dev/null +++ b/insights/combiners/sssd_conf.py @@ -0,0 +1,154 @@ +""" +SSSD Configuration +================== + +Provides access to complete SSSD configuration: /etc/sssd/sssd.conf with merged +configuration snippets from /etc/sssd/conf.d. +""" + +from copy import deepcopy + +from insights.core.plugins import combiner +from insights.parsers.sssd_conf import SSSDConf, SSSDConfd + + +@combiner(SSSDConf, SSSDConfd) +class SSSDConfAll(object): + """ + Provides access to complete SSSD configuration: /etc/sssd/sssd.conf with + merged configuration snippets from /etc/sssd/conf.d. + """ + def __init__(self, sssd_conf, sssd_conf_d): + self.config = deepcopy(sssd_conf) + + for parser in sorted(sssd_conf_d, key=lambda x: x.file_name): + if parser.file_name.startswith("."): + continue + + for section in parser.sections(): + for key, value in parser.items(section).items(): + self.config._set(section, key, value) + + self._enabled_domains = None + + @property + def enabled_domains(self): + """ + Returns the list of enabled domains. + + Domains can be enabled either using the ``domains`` option in the + ``sssd`` section of the configuration file or using the ``enabled`` + option in the domain configuration. + + [sssd] + domains = a, b + + [domain/a] + ... + + [domain/b] + ... + + [domain/c] + enabled = true + + """ + if self._enabled_domains is None: + enabled_domains = [] + + if self.config.has_option("sssd", "domains"): + domains = self.config.get("sssd", "domains") + enabled_domains = [domain.strip() for domain in domains.split(",")] + + prefix = "domain/" + for section in self.config.sections(): + # Ignore if this is not a domain configuration + if not section.startswith(prefix): + continue + + name = section[len(prefix):].strip() + if not name: + # Invalid configuration + continue + + # Ignore if this is a subdomain configuration + # `domain/$dom/$subdom` + if "/" in name: + continue + + if self.config.has_option(section, "enabled"): + enabled = self.config.getboolean(section, "enabled") + + if enabled and name not in enabled_domains: + enabled_domains.append(name) + elif not enabled and name in enabled_domains: + enabled_domains.remove(name) + + self._enabled_domains = enabled_domains + + return self._enabled_domains + + def domain_config(self, domain): + """ + Return the configuration dictionary for a specific domain, given as + the raw name as listed in the 'domains' property of the sssd section. + This then looks for the equivalent 'domain/{domain}' section of the + config file. + """ + full_domain = self.domain_section(domain) + if full_domain not in self.config: + return {} + + return self.config.items(full_domain) + + def domain_section(self, domain): + """ + Transform plain SSSD domain name into a configuration section. + + ipa.test -> domain/ipa.test + + Args: + domain (str): SSSD domain name. + + Returns: + str: Returns the configuration section. + """ + return "domain/" + domain + + def domain_get(self, domain, option, default=None): + """ + Lookup option in domain. + + Args: + domain (str): The SSSD domain name. + option (str): The option str to search for. + default (any): Default value if the option is not found. + + Returns: + str: Returns the value of the option in the specified section. + """ + section = self.domain_section(domain) + + if not self.config.has_option(section, option): + return default + + return self.config.get(section, option) + + def domain_getboolean(self, domain, option, default=None): + """ + Lookup boolean option in domain. + + Args: + domain (str): The SSSD domain name. + option (str): The option str to search for. + default (any): Default value if the option is not found. + + Returns: + bool: Returns boolean form based on the data from get. + """ + section = self.domain_section(domain) + + if not self.config.has_option(section, option): + return default + + return self.config.getboolean(section, option) diff --git a/insights/parsers/sssd_conf.py b/insights/parsers/sssd_conf.py index f7adc783d5..c588711800 100644 --- a/insights/parsers/sssd_conf.py +++ b/insights/parsers/sssd_conf.py @@ -1,10 +1,88 @@ """ -SSSD_Config - file ``/etc/sssd/sssd.config`` -============================================ +SSSD Configuration - files ``/etc/sssd/sssd.conf`` and ``/etc/sssd.conf.d/*`` +============================================================================= + +SSSD configuration files are in INI format. + +Example: + [sssd] + services = nss, sudo + domains = test + + [sudo] + debug_level = 0xfff0 + + [domain/test] + id_provider = ldap + ldap_uri = ldap://ldap.test + + +SSSDConf - file ``/etc/sssd/sssd.conf`` +---------------------------------------- + +SSSDConfd - files under ``/etc/sssd/conf.d/*.conf`` +--------------------------------------------------- """ + from insights.core import IniConfigFile from insights.core.plugins import parser from insights.specs import Specs +from insights.util import deprecated + + +@parser(Specs.sssd_config) +class SSSDConf(IniConfigFile): + """ + Parse the content of the ``/etc/sssd/sssd.conf``. + + The file format is standard ini file. + """ + + def getboolean(self, section, option): + """ + Returns: + bool: Returns boolean form based on the data from get. + """ + val = self.get(section, option) + boolean_states = { + "true": True, + "false": False, + } + + if val.lower() not in boolean_states: + raise ValueError("Not a boolean: %s" % val) + + return boolean_states[val.lower()] + + def _set(self, section, option, value=None): + """ + Sets the value of the specified section option. + + Note: This should only be used by + :class:`insights.combiners.sssd_conf.SSSDConfAll`. + + Args: + section (str): The section str to set for. option (str): The option + str to set for. value (str): The value to set. + """ + section = section.strip() + option = option.strip().lower() + + if section not in self._dict: + self._dict[section] = {} + + self._dict[section][option] = value + + +@parser(Specs.sssd_conf_d) +class SSSDConfd(SSSDConf): + """ + Parse the content of configuration snippet under ``/etc/sssd/conf.d/*.conf``. + + The file format is standard ini file. + """ + + pass @parser(Specs.sssd_config) @@ -79,6 +157,10 @@ class SSSD_Config(IniConfigFile): >>> 'ldap_uri' in domain True """ + def __init__(self, context): + deprecated(SSSD_Config, "Please use the :class:`insights.combiners.sssd_conf.SSSDConfAll` instead.", "3.6.0") + super(SSSD_Config, self).__init__(context) + @property def domains(self): """ diff --git a/insights/parsr/query/__init__.py b/insights/parsr/query/__init__.py index fbcbc06b79..d6264b99b5 100644 --- a/insights/parsr/query/__init__.py +++ b/insights/parsr/query/__init__.py @@ -105,6 +105,13 @@ def __getattr__(self, name): Allows queries based on attribute access so long as they don't conflict with members of the Entry class itself. """ + if name.startswith("__") and name.endswith("__"): + raise AttributeError( + "'{cls}' object has no attribute '{attr}'".format( + cls=self.__class__.__name__, attr=name + ) + ) + if name == "name" and self._name is not None: return self._name diff --git a/insights/parsr/tests/test_iniparser.py b/insights/parsr/tests/test_iniparser.py index 62bdbbd31e..b7ee8bfac6 100644 --- a/insights/parsr/tests/test_iniparser.py +++ b/insights/parsr/tests/test_iniparser.py @@ -2,6 +2,7 @@ from insights.parsr.iniparser import parse_doc from insights.parsr.query import last from six import PY2 +from copy import deepcopy DATA = """ @@ -86,3 +87,10 @@ def test_unicode(): else: assert res["workspace"]["datacenter"][last].value == "1-???" assert res["workspace"]["folder"][last].value == '"/1-???/xxxxxxxxx"' + + +def test_deepcopy(): + res = parse_doc(DATA, None) + + # This should not throw an exception + deepcopy(res) diff --git a/insights/specs/__init__.py b/insights/specs/__init__.py index be650bdbf9..7846b88c7e 100644 --- a/insights/specs/__init__.py +++ b/insights/specs/__init__.py @@ -728,6 +728,7 @@ class Specs(SpecSet): sshd_config_perms = RegistryPoint(no_obfuscate=['hostname', 'ip']) sshd_test_mode = RegistryPoint(filterable=True) sssd_config = RegistryPoint() + sssd_conf_d = RegistryPoint(multi_output=True) sssd_logs = RegistryPoint(multi_output=True, filterable=True) sys_block_queue_stable_writes = RegistryPoint(multi_output=True) subscription_manager_facts = RegistryPoint(filterable=True) diff --git a/insights/specs/default.py b/insights/specs/default.py index 8a5cca1e07..c27cc523be 100644 --- a/insights/specs/default.py +++ b/insights/specs/default.py @@ -639,6 +639,7 @@ class DefaultSpecs(Specs): sshd_config_perms = simple_command("/bin/ls -lH /etc/ssh/sshd_config") sshd_test_mode = simple_command("/usr/sbin/sshd -T") sssd_config = simple_file("/etc/sssd/sssd.conf") + sssd_conf_d = glob_file("/etc/sssd/conf.d/*.conf") subscription_manager_facts = simple_command("/usr/sbin/subscription-manager facts", override_env={"LC_ALL": "C.UTF-8"}) subscription_manager_id = simple_command("/usr/sbin/subscription-manager identity", # use "/usr/sbin" here, BZ#1690529 diff --git a/insights/tests/combiners/test_identity_domain.py b/insights/tests/combiners/test_identity_domain.py index e65343cf11..81a5c4d053 100644 --- a/insights/tests/combiners/test_identity_domain.py +++ b/insights/tests/combiners/test_identity_domain.py @@ -1,239 +1,564 @@ +import textwrap + import pytest -from insights.core.exceptions import SkipComponent -from insights.combiners.krb5 import AllKrb5Conf from insights.combiners.identity_domain import ( - IdentityDomain, - DomainInfo, - DomainTypes, ClientSoftware, - ServerSoftware, + DomainTypes, + IdentityDomain, IPAMode, + ServerSoftware, ) from insights.combiners.ipa import IPA +from insights.combiners.krb5 import AllKrb5Conf +from insights.combiners.sssd_conf import SSSDConfAll +from insights.core.exceptions import SkipComponent from insights.parsers.installed_rpms import InstalledRpms from insights.parsers.ipa_conf import IPAConfig from insights.parsers.krb5 import Krb5Configuration -from insights.parsers.redhat_release import RedhatRelease from insights.parsers.samba import SambaConfigs -from insights.parsers.sssd_conf import SSSD_Config +from insights.parsers.sssd_conf import SSSDConf from insights.tests import context_wrap -KRB5_CONF = """ -[libdefaults] - dns_lookup_realm = false - default_realm = IPA.TEST - dns_canonicalize_hostname = false - ticket_lifetime = 24h - renew_lifetime = 7d - rdns = false - -[realms] - IPA.TEST = { - pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem - pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem - } - KERBEROS-LDAP.TEST = { - kdc = kdc.kerberos-ldap.test - } - - KERBEROS.TEST = { - kdc = kdc.kerberos.test - } - - # "realm join" for AD does not add an entry to krb5.conf. - # AD-WINBIND.TEST = {} - # AD-SSSD.TEST = {} - -[domain_realm] - .ipa.test = IPA.TEST - ipa.test = IPA.TEST -""" - -SMB_CONF_WINBIND = """ -# output of testparm -s -Server role: ROLE_DOMAIN_MEMBER - -[global] - realm = AD-WINBIND.TEST - security = ADS - template homedir = /home/%U@%D - template shell = /bin/bash - winbind offline logon = Yes - winbind refresh tickets = Yes - workgroup = AD-WINBIND - idmap config * : range = 10000-999999 - idmap config sub1 : backend = rid - idmap config sub1 : range = 2000000-2999999 - idmap config * : backend = tdb -""" - -REDHAT_RELEASE_RHEL = """ -Red Hat Enterprise Linux release 9.2 (Plow) -""" - -IPA_RPMS_CLIENT = """ -ipa-client-4.10.1-6.el9.x86_64 -""" - -IPA_DEFAULT_CONF = """ -[global] -basedn = dc=ipa,dc=test -realm = IPA.TEST -domain = ipa.test -server = server.ipa.test -xmlrpc_uri = https://server.ipa.test/ipa/xml -enable_ra = True -""" - -SSSD_CONF = """ -[sssd] -domains = ad-sssd.test, ipa.test, kerberos-ldap, ldap -config_file_version = 2 -services = nss, pam - -[domain/ad-sssd.test] -default_shell = /bin/bash -krb5_store_password_if_offline = True -cache_credentials = True -krb5_realm = AD-SSSD.TEST -realmd_tags = manages-system joined-with-adcli -id_provider = ad -fallback_homedir = /home/%u@%d -ad_domain = ad-sssd.test -use_fully_qualified_names = True -ldap_id_mapping = True -access_provider = ad - -[domain/ipa.test] -id_provider = ipa -ipa_server = _srv_, server.ipa.test -ipa_domain = ipa.test -ipa_hostname = client91.ipa.test -auth_provider = ipa -chpass_provider = ipa -access_provider = ipa -cache_credentials = True -ldap_tls_cacert = /etc/ipa/ca.crt -krb5_store_password_if_offline = True - -[domain/kerberos-ldap] -id_provider = ldap -ldap_uri = ldap://ldap.kerberos-ldap.test -ldap_search_base = dc=kerberos-ldap,dc=test -auth_provider = krb5 -krb5_server = kdc.kerberos-ldap.test -krb5_realm = KERBEROS-LDAP.TEST - -[domain/ldap] -id_provider = ldap -ldap_uri = ldap://ldap.ldap.test -ldap_search_base = dc=ldap,dc=test?subtree? -cache_credentials = true -""" - -IPA_DOMAIN = DomainInfo( - "ipa.test", - DomainTypes.IPA, - ServerSoftware.IPA, - ClientSoftware.SSSD, - "ipa.test", - "IPA.TEST", - None, - IPAMode.IPA_CLIENT, -) -KERBEROS_LDAP_DOMAIN = DomainInfo( - "kerberos-ldap", - DomainTypes.LDAP_KRB5, - ServerSoftware.LDAP_KRB5, - ClientSoftware.SSSD, - None, - "KERBEROS-LDAP.TEST", - None, - None, -) +def test_identity_domain__sssd_ldap(): + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = ldap.test -LDAP_DOMAIN = DomainInfo( - "ldap", - DomainTypes.LDAP, - ServerSoftware.LDAP, - ClientSoftware.SSSD, - None, - None, - None, - None, -) + [domain/ldap.test] + id_provider = ldap + """ + ).strip() -AD_SSSD_DOMAIN = DomainInfo( - "ad-sssd.test", - DomainTypes.AD_SSSD, - ServerSoftware.AD, - ClientSoftware.SSSD, - "ad-sssd.test", - "AD-SSSD.TEST", - None, - None, -) + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] + ) + + identity_domain = IdentityDomain(sssd_conf, None, None, None) + + assert len(identity_domain.domains) == 1 + domain = identity_domain.domains[0] -KERBEROS_DOMAIN = DomainInfo( - "kerberos.test", - DomainTypes.KRB5, - ServerSoftware.KRB5, - ClientSoftware.KRB5, - None, - "KERBEROS.TEST", - None, - None, + assert domain.name == "ldap.test" + assert domain.domain_type == DomainTypes.LDAP + assert domain.server_software == ServerSoftware.LDAP + assert domain.client_software == ClientSoftware.SSSD + assert domain.domain is None + assert domain.realm is None + assert domain.workgroup is None + assert domain.ipa_mode is None + + assert identity_domain.default_realm is None + assert identity_domain.dns_lookup_kdc is True + assert identity_domain.dns_lookup_realm is True + + +@pytest.mark.parametrize( + "explicit_realm", [True, False], ids=["realm_set", "realm_unset"] ) +def test_identity_domain__sssd_ldap_krb5(explicit_realm): + realm = "LDAP.TEST" if not explicit_realm else "MYREALM" + + krb5_conf = textwrap.dedent( + """ + [libdefaults] + default_realm = {realm} + + [realms] + {realm} = {{ + kdc = kdc.realm1.test + }} + [domain_realm] + """.format( + realm=realm + ) + ).strip() + + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = ldap.test + + [domain/ldap.test] + id_provider = ldap + auth_provider = krb5 + """ + ).strip() + + if explicit_realm: + sssd_conf += "\nkrb5_realm = " + realm + + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] + ) + krb5_conf = AllKrb5Conf( + [Krb5Configuration(context_wrap(krb5_conf, path="/etc/krb5.conf"))] + ) + identity_domain = IdentityDomain(sssd_conf, krb5_conf, None, None) + + assert len(identity_domain.domains) == 1 + domain = identity_domain.domains[0] -AD_WINBIND_DOMAIN = DomainInfo( - "ad-winbind.test", - DomainTypes.AD_WINBIND, - ServerSoftware.AD, - ClientSoftware.WINBIND, - "ad-winbind.test", - "AD-WINBIND.TEST", - "AD-WINBIND", - None, + assert domain.name == "ldap.test" + assert domain.domain_type == DomainTypes.LDAP_KRB5 + assert domain.server_software == ServerSoftware.LDAP_KRB5 + assert domain.client_software == ClientSoftware.SSSD + assert domain.domain is None + assert domain.realm == realm + assert domain.workgroup is None + assert domain.ipa_mode is None + + assert identity_domain.default_realm == realm + assert identity_domain.dns_lookup_kdc is True + assert identity_domain.dns_lookup_realm is True + + +@pytest.mark.parametrize( + "explicit_realm", [True, False], ids=["realm_set", "realm_unset"] ) +@pytest.mark.parametrize("ipa_server", [True, False], ids=["ipa_server", "ipa_client"]) +@pytest.mark.parametrize("sssd_domain", ["ipa.test", "IPA"]) +def test_identity_domain__sssd_ipa(explicit_realm, ipa_server, sssd_domain): + realm = "IPA.TEST" if not explicit_realm else "MYREALM" + + ipa_conf = textwrap.dedent( + """ + [global] + basedn = dc=ipahcc,dc=test + realm = {realm} + domain = ipa.test + server = server.ipa.test + host = client91.ipa.test + xmlrpc_uri = https://server.ipa.test/ipa/xml + enable_ra = True + """.format( + realm=realm + ) + ).strip() + + krb5_conf = textwrap.dedent( + """ + [libdefaults] + dns_lookup_realm = true + dns_lookup_kdc = true + default_realm = {realm} + dns_canonicalize_hostname = false + ticket_lifetime = 24h + renew_lifetime = 7d + rdns = false + + [realms] + {realm} = {{ + pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem + pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem + }} + + [domain_realm] + .ipa.test = {realm} + ipa.test = {realm} + """.format( + realm=realm + ) + ).strip() + + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = {domain} + + [domain/{domain}] + id_provider = ipa + ipa_server_mode = false + """.format( + domain=sssd_domain + ) + ).strip() + + sssd_conf += "\nipa_server_mode = " + str(ipa_server) + + if explicit_realm: + sssd_conf += "\nkrb5_realm = " + realm + + if sssd_domain != "ipa.test": + sssd_conf += "\nipa_domain = ipa.test" + + rpms = InstalledRpms(context_wrap("sssd-2.9.1-1.el9.x86_64")) + ipa_conf = IPAConfig(context_wrap(ipa_conf)) + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] + ) + krb5_conf = AllKrb5Conf( + [Krb5Configuration(context_wrap(krb5_conf, path="/etc/krb5.conf"))] + ) + ipa = IPA(ipa_conf, sssd_conf, rpms) + + identity_domain = IdentityDomain(sssd_conf, krb5_conf, ipa, None) + ipa_mode = IPAMode.IPA_SERVER if ipa_server else IPAMode.IPA_CLIENT + assert len(identity_domain.domains) == 1 + domain = identity_domain.domains[0] -def test_identity_domain_sssd(): - krb5 = AllKrb5Conf( - [Krb5Configuration(context_wrap(KRB5_CONF, path="/etc/krb5.conf"))] + assert domain.name == sssd_domain + assert domain.domain_type == DomainTypes.IPA + assert domain.server_software == ServerSoftware.IPA + assert domain.client_software == ClientSoftware.SSSD + assert domain.domain == "ipa.test" + assert domain.realm == realm + assert domain.workgroup is None + assert domain.ipa_mode is ipa_mode + + assert identity_domain.default_realm == realm + assert identity_domain.dns_lookup_kdc is True + assert identity_domain.dns_lookup_realm is True + + +@pytest.mark.parametrize( + "explicit_realm", [True, False], ids=["realm_set", "realm_unset"] +) +@pytest.mark.parametrize("sssd_domain", ["ad.test", "AD"]) +def test_identity_domain__sssd_ad(explicit_realm, sssd_domain): + realm = "AD.TEST" if not explicit_realm else "MYREALM" + + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = {domain} + + [domain/{domain}] + id_provider = ad + """.format( + domain=sssd_domain + ) + ).strip() + + if explicit_realm: + sssd_conf += "\nkrb5_realm = " + realm + + if sssd_domain != "ad.test": + sssd_conf += "\nad_domain = ad.test" + + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] ) - sssd = SSSD_Config(context_wrap(SSSD_CONF, path="/etc/sssd/sssd.conf")) - redhat_release = RedhatRelease(context_wrap(REDHAT_RELEASE_RHEL)) - rpms_client = InstalledRpms(context_wrap(IPA_RPMS_CLIENT)) - ipa_conf = IPAConfig(context_wrap(IPA_DEFAULT_CONF, path="/etc/ipa/default.conf")) - ipa = IPA(ipa_conf, sssd, rpms_client, redhat_release) - - identity_domain = IdentityDomain(sssd, krb5, ipa, None) - - assert identity_domain.domains == [ - AD_SSSD_DOMAIN, - IPA_DOMAIN, - KERBEROS_LDAP_DOMAIN, - LDAP_DOMAIN, - KERBEROS_DOMAIN, - ] - assert identity_domain.default_realm == "IPA.TEST" + identity_domain = IdentityDomain(sssd_conf, None, None, None) + + assert len(identity_domain.domains) == 1 + domain = identity_domain.domains[0] + + assert domain.name == sssd_domain + assert domain.domain_type == DomainTypes.AD_SSSD + assert domain.server_software == ServerSoftware.AD + assert domain.client_software == ClientSoftware.SSSD + assert domain.domain == "ad.test" + assert domain.realm == realm + assert domain.workgroup is None + assert domain.ipa_mode is None + + assert identity_domain.default_realm is None assert identity_domain.dns_lookup_kdc is True - assert identity_domain.dns_lookup_realm is False + assert identity_domain.dns_lookup_realm is True -def test_identity_domain_samba(): - smbwb = SambaConfigs(context_wrap(SMB_CONF_WINBIND, path="/etc/samba/smb.conf")) - identity_domain = IdentityDomain(None, None, None, smbwb) - assert identity_domain.domains == [AD_WINBIND_DOMAIN] +@pytest.mark.parametrize( + "explicit_workgroup", [True, False], ids=["workgroup_set", "workgroup_unset"] +) +def test_identity_domain__winbind_ad(explicit_workgroup): + smb_conf = textwrap.dedent( + """ + # output of testparm -s + Server role: ROLE_DOMAIN_MEMBER + + [global] + realm = AD-WINBIND.TEST + security = ADS + template homedir = /home/%U@%D + template shell = /bin/bash + winbind offline logon = Yes + winbind refresh tickets = Yes + idmap config * : range = 10000-999999 + idmap config sub1 : backend = rid + idmap config sub1 : range = 2000000-2999999 + idmap config * : backend = tdb + """ + ).strip() + + if explicit_workgroup: + smb_conf += "\n workgroup = MYWORKGROUP" + + smb_conf = SambaConfigs(context_wrap(smb_conf, path="/etc/samba/smb.conf")) + identity_domain = IdentityDomain(None, None, None, smb_conf) + workgroup = "AD-WINBIND" if not explicit_workgroup else "MYWORKGROUP" + + assert len(identity_domain.domains) == 1 + domain = identity_domain.domains[0] + + assert domain.name == "ad-winbind.test" + assert domain.domain_type == DomainTypes.AD_WINBIND + assert domain.server_software == ServerSoftware.AD + assert domain.client_software == ClientSoftware.WINBIND + assert domain.domain == "ad-winbind.test" + assert domain.realm == "AD-WINBIND.TEST" + assert domain.workgroup == workgroup + assert domain.ipa_mode is None assert identity_domain.default_realm is None assert identity_domain.dns_lookup_kdc is True assert identity_domain.dns_lookup_realm is True +@pytest.mark.parametrize( + "dns_lookup_realm", + [True, False], + ids=["dns_lookup_realm_true", "dns_lookup_realm_false"], +) +@pytest.mark.parametrize( + "dns_lookup_kdc", [True, False], ids=["dns_lookup_kdc_true", "dns_lookup_kdc_false"] +) +def test_identity_domain__krb5_one_realm(dns_lookup_realm, dns_lookup_kdc): + krb5_conf = textwrap.dedent( + """ + [libdefaults] + dns_lookup_realm = {dns_lookup_realm} + dns_lookup_kdc = {dns_lookup_kdc} + default_realm = KERBEROS.TEST + + [realms] + KERBEROS.TEST = {{ + kdc = kdc.kerberos.test + }} + + [domain_realm] + .kerberos.test = KERBEROS.TEST + kerberos.test = KERBEROS.TEST + """.format( + dns_lookup_realm=str(dns_lookup_realm).lower(), + dns_lookup_kdc=str(dns_lookup_kdc).lower(), + ) + ).strip() + + krb5_conf = AllKrb5Conf( + [Krb5Configuration(context_wrap(krb5_conf, path="/etc/krb5.conf"))] + ) + + identity_domain = IdentityDomain(None, krb5_conf, None, None) + + assert len(identity_domain.domains) == 1 + domain = identity_domain.domains[0] + + assert domain.name == "kerberos.test" + assert domain.domain_type == DomainTypes.KRB5 + assert domain.server_software == ServerSoftware.KRB5 + assert domain.client_software == ClientSoftware.KRB5 + assert domain.domain is None + assert domain.realm == "KERBEROS.TEST" + assert domain.workgroup is None + assert domain.ipa_mode is None + + assert identity_domain.default_realm == "KERBEROS.TEST" + assert identity_domain.dns_lookup_kdc is dns_lookup_kdc + assert identity_domain.dns_lookup_realm is dns_lookup_realm + + +@pytest.mark.parametrize( + "dns_lookup_realm", + [True, False], + ids=["dns_lookup_realm_true", "dns_lookup_realm_false"], +) +@pytest.mark.parametrize( + "dns_lookup_kdc", [True, False], ids=["dns_lookup_kdc_true", "dns_lookup_kdc_false"] +) +def test_identity_domain__krb5_multi_realm(dns_lookup_realm, dns_lookup_kdc): + krb5_conf = textwrap.dedent( + """ + [libdefaults] + dns_lookup_realm = {dns_lookup_realm} + dns_lookup_kdc = {dns_lookup_kdc} + default_realm = REALM2.TEST + + [realms] + REALM1.TEST = {{ + kdc = kdc.realm1.test + }} + + REALM2.TEST = {{ + kdc = kdc.realm2.test + }} + + [domain_realm] + """.format( + dns_lookup_realm=str(dns_lookup_realm).lower(), + dns_lookup_kdc=str(dns_lookup_kdc).lower(), + ) + ).strip() + + krb5_conf = AllKrb5Conf( + [Krb5Configuration(context_wrap(krb5_conf, path="/etc/krb5.conf"))] + ) + + identity_domain = IdentityDomain(None, krb5_conf, None, None) + + assert len(identity_domain.domains) == 2 + + domain = identity_domain.domains[0] + assert domain.name == "realm1.test" + assert domain.domain_type == DomainTypes.KRB5 + assert domain.server_software == ServerSoftware.KRB5 + assert domain.client_software == ClientSoftware.KRB5 + assert domain.domain is None + assert domain.realm == "REALM1.TEST" + assert domain.workgroup is None + assert domain.ipa_mode is None + + domain = identity_domain.domains[1] + assert domain.name == "realm2.test" + assert domain.domain_type == DomainTypes.KRB5 + assert domain.server_software == ServerSoftware.KRB5 + assert domain.client_software == ClientSoftware.KRB5 + assert domain.domain is None + assert domain.realm == "REALM2.TEST" + assert domain.workgroup is None + assert domain.ipa_mode is None + + assert identity_domain.default_realm == "REALM2.TEST" + assert identity_domain.dns_lookup_kdc is dns_lookup_kdc + assert identity_domain.dns_lookup_realm is dns_lookup_realm + + +def test_identity_domain__multi_domain(): + ipa_conf = textwrap.dedent( + """ + [global] + basedn = dc=ipahcc,dc=test + realm = IPA.TEST + domain = ipa.test + server = server.ipa.test + host = client91.ipa.test + xmlrpc_uri = https://server.ipa.test/ipa/xml + enable_ra = True + """ + ).strip() + + krb5_conf = textwrap.dedent( + """ + [libdefaults] + default_realm = IPA.TEST + dns_canonicalize_hostname = false + ticket_lifetime = 24h + renew_lifetime = 7d + rdns = false + + [realms] + IPA.TEST = { + pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem + pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem + } + + KERBEROS.TEST = { + kdc = kdc.realm1.test + } + + [domain_realm] + .ipa.test = IPA.TEST + ipa.test = IPA.TEST + .kerberos.test = KERBEROS.TEST + kerberos.test = KERBEROS.TEST + """ + ).strip() + + sssd_conf = textwrap.dedent( + """ + [domain/ipa.test] + enabled = true + id_provider = ipa + ipa_server_mode = false + + [domain/ldap.test] + enabled = true + id_provider = ldap + """ + ).strip() + + smb_conf = textwrap.dedent( + """ + # output of testparm -s + Server role: ROLE_DOMAIN_MEMBER + + [global] + realm = AD-WINBIND.TEST + security = ADS + template homedir = /home/%U@%D + template shell = /bin/bash + winbind offline logon = Yes + winbind refresh tickets = Yes + idmap config * : range = 10000-999999 + idmap config sub1 : backend = rid + idmap config sub1 : range = 2000000-2999999 + idmap config * : backend = tdb + """ + ).strip() + + rpms = InstalledRpms(context_wrap("sssd-2.9.1-1.el9.x86_64")) + ipa_conf = IPAConfig(context_wrap(ipa_conf)) + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] + ) + krb5_conf = AllKrb5Conf( + [Krb5Configuration(context_wrap(krb5_conf, path="/etc/krb5.conf"))] + ) + ipa = IPA(ipa_conf, sssd_conf, rpms) + smb_conf = SambaConfigs(context_wrap(smb_conf, path="/etc/samba/smb.conf")) + identity_domain = IdentityDomain(sssd_conf, krb5_conf, ipa, smb_conf) + + assert len(identity_domain.domains) == 4 + + domain = identity_domain.domains[0] + assert domain.name == "ipa.test" + assert domain.domain_type == DomainTypes.IPA + assert domain.server_software == ServerSoftware.IPA + assert domain.client_software == ClientSoftware.SSSD + assert domain.domain == "ipa.test" + assert domain.realm == "IPA.TEST" + assert domain.workgroup is None + assert domain.ipa_mode is IPAMode.IPA_CLIENT + + domain = identity_domain.domains[1] + assert domain.name == "ldap.test" + assert domain.domain_type == DomainTypes.LDAP + assert domain.server_software == ServerSoftware.LDAP + assert domain.client_software == ClientSoftware.SSSD + assert domain.domain is None + assert domain.realm is None + assert domain.workgroup is None + assert domain.ipa_mode is None + + domain = identity_domain.domains[2] + assert domain.name == "ad-winbind.test" + assert domain.domain_type == DomainTypes.AD_WINBIND + assert domain.server_software == ServerSoftware.AD + assert domain.client_software == ClientSoftware.WINBIND + assert domain.domain == "ad-winbind.test" + assert domain.realm == "AD-WINBIND.TEST" + assert domain.workgroup == "AD-WINBIND" + assert domain.ipa_mode is None + + domain = identity_domain.domains[3] + assert domain.name == "kerberos.test" + assert domain.domain_type == DomainTypes.KRB5 + assert domain.server_software == ServerSoftware.KRB5 + assert domain.client_software == ClientSoftware.KRB5 + assert domain.domain is None + assert domain.realm == "KERBEROS.TEST" + assert domain.workgroup is None + assert domain.ipa_mode is None + + assert identity_domain.default_realm == "IPA.TEST" + assert identity_domain.dns_lookup_kdc is True + assert identity_domain.dns_lookup_realm is True + + def test_identity_domain_empty(): with pytest.raises(SkipComponent): IdentityDomain(None, None, None, None) diff --git a/insights/tests/combiners/test_ipa.py b/insights/tests/combiners/test_ipa.py index a431019788..61c47a0942 100644 --- a/insights/tests/combiners/test_ipa.py +++ b/insights/tests/combiners/test_ipa.py @@ -1,122 +1,144 @@ +import textwrap + +import pytest + from insights.combiners.ipa import IPA +from insights.combiners.sssd_conf import SSSDConfAll +from insights.core.exceptions import SkipComponent from insights.parsers.installed_rpms import InstalledRpms from insights.parsers.ipa_conf import IPAConfig -from insights.parsers.redhat_release import RedhatRelease -from insights.parsers.sssd_conf import SSSD_Config - +from insights.parsers.sssd_conf import SSSDConf from insights.tests import context_wrap -REDHAT_RELEASE_RHEL = """ -Red Hat Enterprise Linux release 9.2 (Plow) -""" - -IPA_RPMS_CLIENT = """ -ipa-client-4.10.1-6.el9.x86_64 -""" - -IPA_RPMS_SERVER = """ -ipa-client-4.10.1-6.el9.x86_64 -ipa-server-4.10.1-6.el9.x86_64 -""" - -SSSD_CONF_SERVER = """ -[domain/ipa.test] -id_provider = ipa -ipa_server_mode = True -ipa_server = server.ipa.test -ipa_domain = ipa.test -ipa_hostname = server.ipa.test -auth_provider = ipa -chpass_provider = ipa -access_provider = ipa -cache_credentials = True -ldap_tls_cacert = /etc/ipa/ca.crt -krb5_store_password_if_offline = True -sudo_provider = ipa -autofs_provider = ipa -subdomains_provider = ipa -session_provider = ipa -hostid_provider = ipa - -[sssd] -domains = ipa.test -""" - -IPA_DEFAULT_CONF_SERVER = """ -[global] -host = server.ipa.test -basedn = dc=ipahcc,dc=test -realm = ipa.test -domain = ipa.test -xmlrpc_uri = https://server.ipa.test/ipa/xml -ldap_uri = ldapi://%2Frun%2Fslapd-IPAHCC-TEST.socket -mode = production -enable_ra = True -ra_plugin = dogtag -dogtag_version = 10 -""" - -SSSD_CONF_CLIENT = """ -[domain/ipa.test] -id_provider = ipa -ipa_server = _srv_, server.ipa.test -ipa_domain = ipa.test -ipa_hostname = client91.ipa.test -auth_provider = ipa -chpass_provider = ipa -access_provider = ipa -cache_credentials = True -ldap_tls_cacert = /etc/ipa/ca.crt -krb5_store_password_if_offline = True - -[sssd] -domains = ipa.test -""" - -IPA_DEFAULT_CONF_CLIENT = """ -[global] -basedn = dc=ipahcc,dc=test -realm = ipa.test -domain = ipa.test -server = server.ipa.test -host = client91.ipa.test -xmlrpc_uri = https://server.ipa.test/ipa/xml -enable_ra = True -""" - - -def test_ipa(): - redhat_release = RedhatRelease(context_wrap(REDHAT_RELEASE_RHEL)) - - rpms_client = InstalledRpms(context_wrap(IPA_RPMS_CLIENT)) - sssd_conf_client = SSSD_Config(context_wrap(SSSD_CONF_CLIENT)) - ipa_conf_client = IPAConfig(context_wrap(IPA_DEFAULT_CONF_CLIENT)) - - rpms_server = InstalledRpms(context_wrap(IPA_RPMS_SERVER)) - sssd_conf_server = SSSD_Config(context_wrap(SSSD_CONF_SERVER)) - ipa_conf_server = IPAConfig(context_wrap(IPA_DEFAULT_CONF_SERVER)) - - ipa_client = IPA( - ipa_conf_client, sssd_conf_client, rpms_client, redhat_release + +@pytest.mark.parametrize("sssd_domain", ["ipa.test", "IPA"]) +def test_ipa__server(sssd_domain): + ipa_conf = textwrap.dedent( + """ + [global] + host = server.ipa.test + basedn = dc=ipahcc,dc=test + realm = ipa.test + domain = ipa.test + xmlrpc_uri = https://server.ipa.test/ipa/xml + ldap_uri = ldapi://%2Frun%2Fslapd-IPAHCC-TEST.socket + mode = production + enable_ra = True + ra_plugin = dogtag + dogtag_version = 10 + """ + ).strip() + + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = {domain} + + [domain/{domain}] + id_provider = ipa + ipa_server_mode = True + """.format( + domain=sssd_domain + ) + ).strip() + + rpms = InstalledRpms(context_wrap("sssd-2.9.1-1.el9.x86_64")) + ipa_conf = IPAConfig(context_wrap(ipa_conf)) + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] ) - assert ipa_client.sssd_conf.domains == [ipa_client.ipa_conf.domain] - assert ipa_client._is_client is None - assert ipa_client._is_server is None - assert ipa_client.is_client - assert ipa_client._is_client - assert not ipa_client.is_server - assert not ipa_client._is_server - - ipa_server = IPA( - ipa_conf_server, sssd_conf_server, rpms_server, redhat_release + + ipa = IPA(ipa_conf, sssd_conf, rpms) + + assert ipa.sssd_ipa_domains == [sssd_domain] + assert ipa.is_server + assert ipa.is_client + + +@pytest.mark.parametrize("sssd_domain", ["ipa.test", "IPA"]) +@pytest.mark.parametrize( + "explicit_server_mode", [True, False], ids=["server_mode_set", "server_mode_unset"] +) +@pytest.mark.parametrize( + "multidomain", [True, False], ids=["multidomain", "singledomain"] +) +def test_ipa__client(sssd_domain, explicit_server_mode, multidomain): + ipa_conf = textwrap.dedent( + """ + [global] + basedn = dc=ipahcc,dc=test + realm = ipa.test + domain = ipa.test + server = server.ipa.test + host = client91.ipa.test + xmlrpc_uri = https://server.ipa.test/ipa/xml + enable_ra = True + """ + ).strip() + + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = {domain} + + [domain/{domain}] + id_provider = ipa + """.format( + domain=sssd_domain + ) + ).strip() + + if explicit_server_mode: + sssd_conf += "\nipa_server_mode = false" + + if multidomain: + sssd_conf += "\n\n[domain/ad]\nid_provider=ad" + + rpms = InstalledRpms(context_wrap("sssd-2.9.1-1.el9.x86_64")) + ipa_conf = IPAConfig(context_wrap(ipa_conf)) + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] ) - assert ipa_server.sssd_conf.domains == [ipa_server.ipa_conf.domain] - assert ipa_server.is_client - assert ipa_server.is_server - ipa_mixed = IPA( - ipa_conf_client, sssd_conf_server, rpms_client, redhat_release + ipa = IPA(ipa_conf, sssd_conf, rpms) + + assert ipa.sssd_ipa_domains == [sssd_domain] + assert not ipa.is_server + assert ipa.is_client + + +@pytest.mark.parametrize("sssd_domain", ["ipa.test", "IPA"]) +def test_ipa__raises_skip(sssd_domain): + ipa_conf = textwrap.dedent( + """ + [global] + basedn = dc=ipahcc,dc=test + realm = ipa.test + domain = ipa.test + server = server.ipa.test + host = client91.ipa.test + xmlrpc_uri = https://server.ipa.test/ipa/xml + enable_ra = True + """ + ).strip() + + sssd_conf = textwrap.dedent( + """ + [sssd] + domains = {domain} + + [domain/{domain}] + id_provider = ipa + """.format( + domain=sssd_domain + ) + ).strip() + + rpms = InstalledRpms(context_wrap("other-package-2.9.1-1.el9.x86_64")) + ipa_conf = IPAConfig(context_wrap(ipa_conf)) + sssd_conf = SSSDConfAll( + SSSDConf(context_wrap(sssd_conf, "/etc/sssd/sssd.conf")), [] ) - assert ipa_mixed.sssd_conf.domains == [ipa_mixed.ipa_conf.domain] - assert ipa_mixed.is_client - assert not ipa_mixed.is_server + + with pytest.raises(SkipComponent): + IPA(ipa_conf, sssd_conf, rpms) diff --git a/insights/tests/combiners/test_sssd_conf.py b/insights/tests/combiners/test_sssd_conf.py new file mode 100644 index 0000000000..700f46c2a2 --- /dev/null +++ b/insights/tests/combiners/test_sssd_conf.py @@ -0,0 +1,209 @@ +import textwrap + +from insights.combiners.sssd_conf import SSSDConfAll +from insights.parsers.sssd_conf import SSSDConf +from insights.tests import context_wrap + + +def test_sssd_conf_all__domains_with_space(): + conf = textwrap.dedent( + """ + [sssd] + domains = a, b, c + + [domain/a] + id_provider = ldap + + [domain/b] + id_provider = ipa + + [domain/c] + id_provider = ad + """ + ).strip() + + sssd_conf = SSSDConf(context_wrap(conf, path="/etc/sssd/sssd.conf")) + sssd_conf_all = SSSDConfAll(sssd_conf, []) + + assert sssd_conf_all.enabled_domains == ["a", "b", "c"] + assert sssd_conf_all.domain_config("a") == {"id_provider": "ldap"} + assert sssd_conf_all.domain_config("b") == {"id_provider": "ipa"} + assert sssd_conf_all.domain_config("c") == {"id_provider": "ad"} + + +def test_sssd_conf_all__domains_without_space(): + conf = textwrap.dedent( + """ + [sssd] + domains = a,b,c + + [domain/a] + id_provider = ldap + + [domain/b] + id_provider = ipa + + [domain/c] + id_provider = ad + """ + ).strip() + + sssd_conf = SSSDConf(context_wrap(conf, path="/etc/sssd/sssd.conf")) + sssd_conf_all = SSSDConfAll(sssd_conf, []) + + assert sssd_conf_all.enabled_domains == ["a", "b", "c"] + assert sssd_conf_all.domain_config("a") == {"id_provider": "ldap"} + assert sssd_conf_all.domain_config("b") == {"id_provider": "ipa"} + assert sssd_conf_all.domain_config("c") == {"id_provider": "ad"} + + +def test_sssd_conf_all__enabled(): + conf = textwrap.dedent( + """ + [sssd] + + [domain/a] + enabled = true + id_provider = ldap + + [domain/b] + enabled = true + id_provider = ipa + + [domain/c] + id_provider = ad + """ + ).strip() + + sssd_conf = SSSDConf(context_wrap(conf, path="/etc/sssd/sssd.conf")) + sssd_conf_all = SSSDConfAll(sssd_conf, []) + + assert sssd_conf_all.enabled_domains == ["a", "b"] + assert sssd_conf_all.domain_config("a") == { + "enabled": "true", + "id_provider": "ldap", + } + assert sssd_conf_all.domain_config("b") == {"enabled": "true", "id_provider": "ipa"} + assert sssd_conf_all.domain_config("c") == {"id_provider": "ad"} + + +def test_sssd_conf_all__domains_and_enabled(): + conf = textwrap.dedent( + """ + [sssd] + domains = c + + [domain/a] + enabled = true + id_provider = ldap + + [domain/b] + enabled = true + id_provider = ipa + + [domain/c] + id_provider = ad + """ + ).strip() + + sssd_conf = SSSDConf(context_wrap(conf, path="/etc/sssd/sssd.conf")) + sssd_conf_all = SSSDConfAll(sssd_conf, []) + + assert sssd_conf_all.enabled_domains == ["c", "a", "b"] + assert sssd_conf_all.domain_config("a") == { + "enabled": "true", + "id_provider": "ldap", + } + assert sssd_conf_all.domain_config("b") == {"enabled": "true", "id_provider": "ipa"} + assert sssd_conf_all.domain_config("c") == {"id_provider": "ad"} + + +def test_sssd_conf_all__conf_d(): + conf = textwrap.dedent( + """ + [sssd] + domains = a, b + + [domain/a] + id_provider = ldap + + [domain/b] + id_provider = ipa + """ + ).strip() + + # overwrite domain a config + # disable domain b + conf_d_1 = textwrap.dedent( + """ + [domain/a] + id_provider = ipa + + [domain/b] + enabled = false + """ + ).strip() + + # overwrite domain a config + # add domain c + conf_d_2 = textwrap.dedent( + """ + [domain/a] + debug_level = 0xfff0 + + [domain/c] + enabled = true + """ + ).strip() + + # dot file is ignored + conf_d_dot = textwrap.dedent( + """ + [domain/d] + enabled = true + """ + ).strip() + + sssd_conf = SSSDConf(context_wrap(conf, path="/etc/sssd/sssd.conf")) + sssd_conf_d_1 = SSSDConf(context_wrap(conf_d_1, path="/etc/sssd/conf.d/1.conf")) + sssd_conf_d_2 = SSSDConf(context_wrap(conf_d_2, path="/etc/sssd/conf.d/2.conf")) + sssd_conf_d_dot = SSSDConf( + context_wrap(conf_d_dot, path="/etc/sssd/conf.d/.3.conf") + ) + sssd_conf_all = SSSDConfAll( + sssd_conf, [sssd_conf_d_1, sssd_conf_d_2, sssd_conf_d_dot] + ) + + assert sssd_conf_all.enabled_domains == ["a", "c"] + assert sssd_conf_all.domain_config("a") == { + "id_provider": "ipa", + "debug_level": "0xfff0", + } + assert sssd_conf_all.domain_config("b") == { + "enabled": "false", + "id_provider": "ipa", + } + assert sssd_conf_all.domain_config("c") == {"enabled": "true"} + assert "domain/d" not in sssd_conf_all.config + + +def test_sssd_conf_all__domain_getters(): + conf = textwrap.dedent( + """ + [domain/a] + enabled = true + id_provider = ldap + """ + ).strip() + + sssd_conf = SSSDConf(context_wrap(conf, path="/etc/sssd/sssd.conf")) + sssd_conf_all = SSSDConfAll(sssd_conf, []) + + assert sssd_conf_all.domain_section("a") == "domain/a" + assert sssd_conf_all.domain_get("a", "enabled") == "true" + assert sssd_conf_all.domain_get("a", "id_provider") == "ldap" + assert sssd_conf_all.domain_get("a", "auth_provider", "ldap") == "ldap" + assert sssd_conf_all.domain_get("a", "auth_provider") is None + assert sssd_conf_all.domain_getboolean("a", "enabled") is True + assert sssd_conf_all.domain_getboolean("a", "enumerate", False) is False + assert sssd_conf_all.domain_getboolean("a", "enumerate") is None diff --git a/insights/tests/parsers/test_sssd_conf.py b/insights/tests/parsers/test_sssd_conf.py index fc77b7a67f..b1ec65128d 100644 --- a/insights/tests/parsers/test_sssd_conf.py +++ b/insights/tests/parsers/test_sssd_conf.py @@ -1,95 +1,40 @@ -import doctest +import pytest -from insights.parsers import sssd_conf +from insights.parsers.sssd_conf import SSSDConf, SSSDConfd from insights.tests import context_wrap sssd_conf_cnt = """ - [sssd] config_file_version = 2 - -# Number of times services should attempt to reconnect in the -# event of a crash or restart before they give up -reconnection_retries = 3 - -# If a back end is particularly slow you can raise this timeout here -sbus_timeout = 30 -services = nss, pam - -# SSSD will not start if you do not configure any domains. -# Add new domain configurations as [domain/] sections, and -# then add the list of domains (in the order you want them to be -# queried) to the "domains" attribute below and uncomment it. -# domains = LOCAL,LDAP domains = example.com -debug_level = 9 - -[nss] -# The following prevents SSSD from searching for the root user/group in -# all domains (you can add here a comma-separated list of system accounts that -# are always going to be /etc/passwd users, or that you want to filter out). -filter_groups = root -filter_users = root -reconnection_retries = 3 - -[pam] -reconnection_retries = 3 +debug_level = 0xfff0 [domain/example.com] id_provider = ldap -lookup_family_order = ipv4_only -ldap_uri = ldap://ldap.example.com/ -ldap_search_base = dc=example,dc=com -enumerate = False -hbase_directory= /home -create_homedir = True -override_homedir = /home/%u -auth_provider = krb5 -krb5_server = kerberos.example.com -krb5_realm = EXAMPLE.COM +enumerate = {0} """ -sssd_conf_no_domains = """ -[sssd] -debug_level = 5 -""" - -sssd_conf_blank_domains = """ -[sssd] -debug_level = 5 -domains = -""" - - -def test_sssd_conf(): - result = sssd_conf.SSSD_Config(context_wrap(sssd_conf_cnt)) - assert 'sssd' in result - assert 'domain/example.com' in result - - assert result.getint('pam', 'reconnection_retries') == 3 - - assert ['example.com'] == result.domains - - domain = result.domain_config('example.com') - assert type(domain) is dict - assert domain['id_provider'] == 'ldap' - - absent_domain = result.domain_config('example.org') - assert type(absent_domain) is dict - assert absent_domain == {} +@pytest.mark.parametrize("cls", [SSSDConf, SSSDConfd]) +@pytest.mark.parametrize( + "bool_val", ["True", "true", "TRUE", "False", "false", "FALSE"] +) +def test_sssd_conf(cls, bool_val): + result = cls( + context_wrap(sssd_conf_cnt.format(bool_val), path="/etc/sssd/sssd.conf") + ) -def test_sssd_conf_empty_domains(): - conf = sssd_conf.SSSD_Config(context_wrap(sssd_conf_no_domains)) - assert conf.domains == [] + assert result.file_name == "sssd.conf" + assert result.file_path == "/etc/sssd/sssd.conf" - conf = sssd_conf.SSSD_Config(context_wrap(sssd_conf_blank_domains)) - assert conf.domains == [] + assert "sssd" in result + assert "domain/example.com" in result + assert result.sections() == ["sssd", "domain/example.com"] + assert result.getint("sssd", "config_file_version") == 2 + assert result.get("sssd", "domains") == "example.com" + assert result.get("sssd", "debug_level") == "0xfff0" -def test_doc_examples(): - failed_count, tests = doctest.testmod( - sssd_conf, - globs={'conf': sssd_conf.SSSD_Config(context_wrap(sssd_conf_cnt))} - ) - assert failed_count == 0 + expected = bool_val.lower() == "true" + assert result.get("domain/example.com", "id_provider") == "ldap" + assert result.getboolean("domain/example.com", "enumerate") == expected