diff options
-rw-r--r-- | ipalib/plugins/baseldap.py | 14 | ||||
-rw-r--r-- | ipalib/plugins/host.py | 1 | ||||
-rw-r--r-- | ipalib/plugins/service.py | 10 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_host_plugin.py | 9 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_service_plugin.py | 17 |
5 files changed, 51 insertions, 0 deletions
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index d619f14e..725704ee 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -387,6 +387,20 @@ def remove_external_post_callback(memberattr, membertype, externalattr, ldap, co return (completed + completed_external, dn) +def host_is_master(ldap, fqdn): + """ + Check to see if this host is a master. + + Raises an exception if a master, otherwise returns nothing. + """ + master_dn = str(DN('cn=%s' % fqdn, 'cn=masters,cn=ipa,cn=etc', api.env.basedn)) + try: + (dn, entry_attrs) = ldap.get_entry(master_dn, ['objectclass']) + raise errors.ValidationError(name='hostname', error=_('An IPA master host cannot be deleted')) + except errors.NotFound: + # Good, not a master + return + class LDAPObject(Object): """ diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py index 682b8142..012817e6 100644 --- a/ipalib/plugins/host.py +++ b/ipalib/plugins/host.py @@ -560,6 +560,7 @@ class host_del(LDAPDelete): fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] + host_is_master(ldap, fqdn) # Remove all service records for this host truncated = True while truncated: diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py index dad3ded4..71e4ac46 100644 --- a/ipalib/plugins/service.py +++ b/ipalib/plugins/service.py @@ -288,6 +288,16 @@ class service_del(LDAPDelete): msg_summary = _('Deleted service "%(value)s"') member_attributes = ['managedby'] def pre_callback(self, ldap, dn, *keys, **options): + # In the case of services we don't want IPA master services to be + # deleted. This is a limited few though. If the user has their own + # custom services allow them to manage them. + (service, hostname, realm) = split_principal(keys[-1]) + try: + host_is_master(ldap, hostname) + except errors.ValidationError, e: + service_types = ['HTTP', 'ldap', 'DNS' 'dogtagldap'] + if service in service_types: + raise errors.ValidationError(name='principal', error=_('This principal is required by the IPA master')) if self.api.env.enable_ra: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) cert = entry_attrs.get('usercertificate') diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py index 372ee256..0323ac39 100644 --- a/tests/test_xmlrpc/test_host_plugin.py +++ b/tests/test_xmlrpc/test_host_plugin.py @@ -661,4 +661,13 @@ class test_host(Declarative): ), ), + + # This test will only succeed when running against lite-server.py + # on same box as IPA install. + dict( + desc='Delete the current host (master?) %s should be caught' % api.env.host, + command=('host_del', [api.env.host], {}), + expected=errors.ValidationError(name='fqdn', error='An IPA master host cannot be deleted'), + ), + ] diff --git a/tests/test_xmlrpc/test_service_plugin.py b/tests/test_xmlrpc/test_service_plugin.py index d36dac98..e97fb7c8 100644 --- a/tests/test_xmlrpc/test_service_plugin.py +++ b/tests/test_xmlrpc/test_service_plugin.py @@ -467,4 +467,21 @@ class test_service(Declarative): expected=errors.HostService() ), + + # These tests will only succeed when running against lite-server.py + # on same box as IPA install. + dict( + desc='Delete the current host (master?) %s HTTP service, should be caught' % api.env.host, + command=('service_del', ['HTTP/%s' % api.env.host], {}), + expected=errors.ValidationError(name='principal', error='This principal is required by the IPA master'), + ), + + + dict( + desc='Delete the current host (master?) %s ldap service, should be caught' % api.env.host, + command=('service_del', ['ldap/%s' % api.env.host], {}), + expected=errors.ValidationError(name='principal', error='This principal is required by the IPA master'), + ), + + ] |