From 48f20550f175503cb226bac47c570a2ff3e79be1 Mon Sep 17 00:00:00 2001 From: Martin Babinsky Date: Fri, 12 May 2017 15:15:37 +0200 Subject: [PATCH] Add an attribute reporting client PKINIT-capable servers A new multi-valued server attribute `pkinit_server` was added which reports IPA masters that have PKINIT configuration usable by clients. The existing tests were modified to allow for testing the new attribute. https://pagure.io/freeipa/issue/6937 Reviewed-By: Jan Cholasta Reviewed-By: Stanislav Laznicka --- ipaserver/servroles.py | 7 ++ ipatests/test_ipaserver/test_serverroles.py | 109 +++++++++++++--------------- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py index 84fed1046b3b46dc9f5f8bbe6e03354725f1136c..f6e79338b9187aa741fe45b9fae42476cc65f724 100644 --- a/ipaserver/servroles.py +++ b/ipaserver/servroles.py @@ -625,4 +625,11 @@ attribute_instances = ( u"DNSSEC", u"dnssecKeyMaster", ), + ServerAttribute( + u"pkinit_server_server", + u"PKINIT enabled server", + u"ipa_master_server", + u"KDC", + u"pkinitEnabled" + ) ) diff --git a/ipatests/test_ipaserver/test_serverroles.py b/ipatests/test_ipaserver/test_serverroles.py index e671272783d8d71c2ee56074459433b98b79dd0a..b373a4d32f60e5ef48bcf07ac29162516113e8a8 100644 --- a/ipatests/test_ipaserver/test_serverroles.py +++ b/ipatests/test_ipaserver/test_serverroles.py @@ -58,7 +58,7 @@ _adtrust_agents = DN( master_data = { - 'ca-dns-dnssec-keymaster': { + 'ca-dns-dnssec-keymaster-pkinit-server': { 'services': { 'CA': { 'enabled': True, @@ -72,14 +72,19 @@ master_data = { 'DNSSEC': { 'enabled': True, 'config': ['DNSSecKeyMaster'] + }, + 'KDC': { + 'enabled': True, + 'config': ['pkinitEnabled'] } }, 'expected_roles': { 'enabled': ['IPA master', 'CA server', 'DNS server'] }, - 'expected_attributes': {'DNS server': 'dnssec_key_master_server'} + 'expected_attributes': {'DNS server': 'dnssec_key_master_server', + 'IPA master': 'pkinit_server_server'} }, - 'ca-kra-renewal-master': { + 'ca-kra-renewal-master-pkinit-server': { 'services': { 'CA': { 'enabled': True, @@ -88,11 +93,16 @@ master_data = { 'KRA': { 'enabled': True, }, + 'KDC': { + 'enabled': True, + 'config': ['pkinitEnabled'] + }, }, 'expected_roles': { 'enabled': ['IPA master', 'CA server', 'KRA server'] }, - 'expected_attributes': {'CA server': 'ca_renewal_master_server'} + 'expected_attributes': {'CA server': 'ca_renewal_master_server', + 'IPA master': 'pkinit_server_server'} }, 'dns-trust-agent': { 'services': { @@ -234,7 +244,7 @@ class MockMasterTopology(object): no_members=True, raw=True)['result']} - self.existing_attributes = self._check_test_host_attributes() + self.original_dns_configs = self._remove_test_host_attrs() def iter_domain_data(self): MasterData = namedtuple('MasterData', @@ -287,7 +297,6 @@ class MockMasterTopology(object): pass def _add_svc_entries(self, master_dn, svc_desc): - self._add_ipamaster_services(master_dn) for name in svc_desc: svc_dn = self.get_service_dn(name, master_dn) svc_mods = svc_desc[name] @@ -298,6 +307,8 @@ class MockMasterTopology(object): enabled=svc_mods['enabled'], other_config=svc_mods.get('config', None))) + self._add_ipamaster_services(master_dn) + def _remove_svc_master_entries(self, master_dn): try: entries = self.ldap.connection.search_s( @@ -317,7 +328,11 @@ class MockMasterTopology(object): """ for svc_name in self.ipamaster_services: svc_dn = self.get_service_dn(svc_name, master_dn) - self.ldap.add_entry(str(svc_dn), _make_service_entry_mods()) + try: + self.api.Backend.ldap2.get_entry(svc_dn) + except errors.NotFound: + self.ldap.add_entry( + str(svc_dn), _make_service_entry_mods()) def _add_members(self, dn, fqdn, member_attrs): _entry, attrs = self.ldap.connection.search_s( @@ -376,57 +391,36 @@ class MockMasterTopology(object): except (ldap.NO_SUCH_OBJECT, ldap.NO_SUCH_ATTRIBUTE): pass - def _check_test_host_attributes(self): - existing_attributes = set() - - for service, value, attr_name in ( - ('CA', 'caRenewalMaster', 'ca renewal master'), - ('DNSSEC', 'DNSSecKeyMaster', 'dnssec key master')): + def _remove_test_host_attrs(self): + original_dns_configs = [] - svc_dn = DN(('cn', service), self.test_master_dn) + for attr_name in ( + 'caRenewalMaster', 'dnssecKeyMaster', 'pkinitEnabled'): try: - svc_entry = self.api.Backend.ldap2.get_entry(svc_dn) + svc_entry = self.api.Backend.ldap2.find_entry_by_attr( + 'ipaConfigString', attr_name, 'ipaConfigObject', + base_dn=self.test_master_dn) except errors.NotFound: continue else: - config_string_val = svc_entry.get('ipaConfigString', []) + original_dns_configs.append( + (svc_entry.dn, list(svc_entry.get('ipaConfigString', []))) + ) + svc_entry[u'ipaConfigString'].remove(attr_name) + self.api.Backend.ldap2.update_entry(svc_entry) - if value in config_string_val: - existing_attributes.add(attr_name) - - return existing_attributes - - def _remove_ca_renewal_master(self): - if 'ca renewal master' not in self.existing_attributes: - return + return original_dns_configs - ca_dn = DN(('cn', 'CA'), self.test_master_dn) - ca_entry = self.api.Backend.ldap2.get_entry(ca_dn) - - config_string_val = ca_entry.get('ipaConfigString', []) - try: - config_string_val.remove('caRenewalMaster') - except KeyError: - return - - ca_entry.update({'ipaConfigString': config_string_val}) - self.api.Backend.ldap2.update_entry(ca_entry) - - def _restore_ca_renewal_master(self): - if 'ca renewal master' not in self.existing_attributes: - return - - ca_dn = DN(('cn', 'CA'), self.test_master_dn) - ca_entry = self.api.Backend.ldap2.get_entry(ca_dn) - - config_string_val = ca_entry.get('ipaConfigString', []) - config_string_val.append('caRenewalMaster') - - ca_entry.update({'ipaConfigString': config_string_val}) - self.api.Backend.ldap2.update_entry(ca_entry) + def _restore_test_host_attrs(self): + for dn, config in self.original_dns_configs: + try: + svc_entry = self.api.Backend.ldap2.get_entry(dn) + svc_entry['ipaConfigString'] = config + self.api.Backend.ldap2.update_entry(svc_entry) + except (errors.NotFound, errors.EmptyModlist): + continue def setup_data(self): - self._remove_ca_renewal_master() for master_data in self.iter_domain_data(): # create host self._add_host_entry(master_data.fqdn) @@ -449,7 +443,6 @@ class MockMasterTopology(object): ) def teardown_data(self): - self._restore_ca_renewal_master() for master_data in self.iter_domain_data(): # first remove the master entries and service containers self._remove_svc_master_entries(master_data.dn) @@ -466,6 +459,8 @@ class MockMasterTopology(object): # finally remove host entry self._del_host_entry(master_data.fqdn) + self._restore_test_host_attrs() + @pytest.fixture(scope='module') def mock_api(request): @@ -665,14 +660,14 @@ class TestServerRoleStatusRetrieval(object): def test_unknown_role_status_raises_notfound(self, mock_api, mock_masters): unknown_role = 'IAP maestr' - fqdn = mock_masters.get_fqdn('ca-dns-dnssec-keymaster') + fqdn = mock_masters.get_fqdn('ca-dns-dnssec-keymaster-pkinit-server') with pytest.raises(errors.NotFound): mock_api.Backend.serverroles.server_role_retrieve( fqdn, unknown_role) def test_no_servrole_queries_all_roles_on_server(self, mock_api, mock_masters): - master_name = 'ca-dns-dnssec-keymaster' + master_name = 'ca-dns-dnssec-keymaster-pkinit-server' enabled_roles = master_data[master_name]['expected_roles']['enabled'] result = self.find_role(None, mock_api, mock_masters, master=master_name) @@ -688,7 +683,7 @@ class TestServerRoleStatusRetrieval(object): invalid_substr = 'fwfgbb' assert (not self.find_role(invalid_substr, mock_api, mock_masters, - 'ca-dns-dnssec-keymaster')) + 'ca-dns-dnssec-keymaster-pkinit-server')) class TestServerAttributes(object): @@ -706,7 +701,7 @@ class TestServerAttributes(object): actual_attr_masters = self.config_retrieve( assoc_role, mock_api)[attr_name] - assert actual_attr_masters == [fqdn] + assert fqdn in actual_attr_masters def test_set_attribute_on_the_same_provider_raises_emptymodlist( self, mock_api, mock_masters): @@ -744,10 +739,10 @@ class TestServerAttributes(object): original_renewal_master = self.config_retrieve( role_name, mock_api)[attr_name] - other_ca_server = mock_masters.get_fqdn('trust-controller-ca') + other_ca_server = [mock_masters.get_fqdn('trust-controller-ca')] for host in (other_ca_server, original_renewal_master): - self.config_update(mock_api, **{attr_name: [host]}) + self.config_update(mock_api, **{attr_name: host}) assert ( - self.config_retrieve(role_name, mock_api)[attr_name] == [host]) + self.config_retrieve(role_name, mock_api)[attr_name] == host) -- 2.9.4