diff options
-rw-r--r-- | install/share/default-aci.ldif | 8 | ||||
-rw-r--r-- | ipalib/plugins/host.py | 36 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_host_plugin.py | 112 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_hostgroup_plugin.py | 1 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_netgroup_plugin.py | 1 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_service_plugin.py | 2 |
6 files changed, 154 insertions, 6 deletions
diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif index 2ca30069..e03c65c4 100644 --- a/install/share/default-aci.ldif +++ b/install/share/default-aci.ldif @@ -51,3 +51,11 @@ changetype: modify add: aci aci: (targetattr="userCertificate || krbLastPwdChange")(version 3.0; acl "Hosts can modify service userCertificate"; allow(write) userdn = "ldap:///self";) +# Define which hosts can edit other hosts +# The managedby attribute stores the DN of hosts that are allowed to manage +# another host. +dn: cn=computers,cn=accounts,$SUFFIX +changetype: modify +add: aci +aci: (targetattr="userCertificate || krbPrincipalKey")(version 3.0; acl "Hosts can manage other host Certificates and kerberos keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";) + diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py index 23728fad..2e77dd5f 100644 --- a/ipalib/plugins/host.py +++ b/ipalib/plugins/host.py @@ -65,6 +65,9 @@ EXAMPLES: Disable the host kerberos key: ipa host-disable test.example.com + + Add a host that can manage this host's keytab and certificate: + ipa host-add-managedby --hosts=test2 test """ import platform @@ -98,6 +101,9 @@ host_output_params = ( Flag('has_keytab', label=_('Keytab'), ), + Str('managedby_host', + label='Managed by', + ), Str('subject', label=_('Subject'), ), @@ -135,17 +141,18 @@ class host(LDAPObject): # object_class_config = 'ipahostobjectclasses' search_attributes = [ 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', - 'nshardwareplatform', 'nsosversion', + 'nshardwareplatform', 'nsosversion', 'managedby' ] default_attributes = [ 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', 'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof', - 'krblastpwdchange', + 'krblastpwdchange', 'managedby' ] uuid_attribute = 'ipauniqueid' attribute_members = { 'enrolledby': ['user'], 'memberof': ['hostgroup', 'netgroup', 'rolegroup'], + 'managedby': ['host'], } label = _('Hosts') @@ -233,6 +240,7 @@ class host_add(LDAPCreate): has_output_params = LDAPCreate.has_output_params + host_output_params msg_summary = _('Added host "%(value)s"') + member_attributes = ['managedby'] takes_options = ( Flag('force', doc=_('force host name even if not in DNS'), @@ -286,6 +294,7 @@ class host_del(LDAPDelete): """ msg_summary = _('Deleted host "%(value)s"') + member_attributes = ['managedby'] def pre_callback(self, ldap, dn, *keys, **options): # If we aren't given a fqdn, find it @@ -346,6 +355,7 @@ class host_mod(LDAPUpdate): has_output_params = LDAPUpdate.has_output_params + host_output_params msg_summary = _('Modified host "%(value)s"') + member_attributes = ['managedby'] takes_options = LDAPUpdate.takes_options + ( Str('krbprincipalname?', @@ -404,7 +414,6 @@ class host_mod(LDAPUpdate): entry_attrs['userpassword'] = ipa_generate_password() setattr(context, 'randompassword', entry_attrs['userpassword']) del entry_attrs['random'] - entry_attrs['managedby'] = dn return dn @@ -426,6 +435,7 @@ class host_find(LDAPSearch): msg_summary = ngettext( '%(count)d host matched', '%(count)d hosts matched' ) + member_attributes = ['managedby'] def pre_callback(self, ldap, filter, attrs_list, base_dn, *args, **options): if 'locality' in attrs_list: @@ -446,6 +456,7 @@ class host_show(LDAPRetrieve): Display information about a host. """ has_output_params = LDAPRetrieve.has_output_params + host_output_params + member_attributes = ['managedby'] def post_callback(self, ldap, dn, entry_attrs, *keys, **options): if 'krblastpwdchange' in entry_attrs: @@ -545,3 +556,22 @@ class host_disable(LDAPQuery): ) api.register(host_disable) + +class host_add_managedby(LDAPAddMember): + """ + Add hosts that can manage this host. + """ + member_attributes = ['managedby'] + has_output_params = LDAPAddMember.has_output_params + host_output_params + +api.register(host_add_managedby) + + +class host_remove_managedby(LDAPRemoveMember): + """ + Remove hosts that can manage this host. + """ + member_attributes = ['managedby'] + has_output_params = LDAPRemoveMember.has_output_params + host_output_params + +api.register(host_remove_managedby) diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py index 283674c2..6026efea 100644 --- a/tests/test_xmlrpc/test_host_plugin.py +++ b/tests/test_xmlrpc/test_host_plugin.py @@ -35,6 +35,9 @@ service1 = u'dns/%s@%s' % (fqdn1, api.env.realm) service1dn = u'krbprincipalname=%s,cn=services,cn=accounts,%s' % (service1.lower(), api.env.basedn) fqdn2 = u'shouldnotexist.%s' % api.env.domain dn2 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn) +fqdn3 = u'testhost2.%s' % api.env.domain +short3 = u'testhost2' +dn3 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn3, api.env.basedn) servercert = 'MIICbzCCAdigAwIBAgICA/4wDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBBIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgwOTE1MDIyN1oXDTIwMDgwOTE1MDIyN1owKTEMMAoGA1UEChMDSVBBMRkwFwYDVQQDExBwdW1hLmdyZXlvYWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwYbfEOQPgGenPn9vt1JFKvWm/Je3y2tawGWA3LXDuqfFJyYtZ8ib3TcBUOnLk9WK5g2qCwHaNlei7bj8ggIfr5hegAVe10cun+wYErjnYo7hsHYd+57VZezeipWrXu+7NoNd4+c4A5lk4A/xJay9j3bYx2oOM8BEox4xWYoWge1ljPrc5JK46f0X7AGW4F2VhnKPnf8rwSuzI1U8VGjutyM9TWNy3m9KMWeScjyG/ggIpOjUDMV7HkJL0Di61lznR9jXubpiEC7gWGbTp84eGl/Nn9bgK1AwHfJ2lHwfoY4uiL7ge1gyP6EvuUlHoBzdb7pekiX28iePjW3iEG9IawIDAQABoyIwIDARBglghkgBhvhCAQEEBAMCBkAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4GBACRESLemRV9BPxfEgbALuxH5oE8jQm8WZ3pm2pALbpDlAd9wQc3yVf6RtkfVthyDnM18bg7IhxKpd77/p3H8eCnS8w5MLVRda6ktUC6tGhFTS4QKAf0WyDGTcIgkXbeDw0OPAoNHivoXbIXIIRxlw/XgaSaMzJQDBG8iROsN4kCv' @@ -44,6 +47,7 @@ class test_host(Declarative): cleanup_commands = [ ('host_del', [fqdn1], {}), ('host_del', [fqdn2], {}), + ('host_del', [fqdn3], {}), ('service_del', [service1], {}), ] @@ -90,6 +94,7 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[fqdn1], ), ), ), @@ -120,7 +125,8 @@ class test_host(Declarative): description=[u'Test host 1'], l=[u'Undisclosed location 1'], krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - has_keytab=False + has_keytab=False, + managedby_host=[fqdn1], ), ), ), @@ -145,7 +151,7 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], serverhostname=[u'testhost1'], objectclass=objectclasses.host, - managedby=[dn1], + managedby_host=[fqdn1], ipauniqueid=[fuzzy_uuid], has_keytab=False ), @@ -167,6 +173,7 @@ class test_host(Declarative): description=[u'Test host 1'], l=[u'Undisclosed location 1'], krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], + managedby_host=[u'%s' % fqdn1], ), ], ), @@ -194,8 +201,8 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], serverhostname=[u'testhost1'], objectclass=objectclasses.host, - managedby=[dn1], ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn1], ), ], ), @@ -214,6 +221,7 @@ class test_host(Declarative): fqdn=[fqdn1], l=[u'Undisclosed location 1'], krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], + managedby_host=[u'%s' % fqdn1], usercertificate=[base64.b64decode(servercert)], valid_not_before=u'Mon Aug 09 15:02:27 2010 UTC', valid_not_after=u'Sun Aug 09 15:02:27 2020 UTC', @@ -240,6 +248,7 @@ class test_host(Declarative): l=[u'Undisclosed location 1'], krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], has_keytab=False, + managedby_host=[u'%s' % fqdn1], usercertificate=[base64.b64decode(servercert)], valid_not_before=u'Mon Aug 09 15:02:27 2010 UTC', valid_not_after=u'Sun Aug 09 15:02:27 2020 UTC', @@ -252,6 +261,101 @@ class test_host(Declarative): ), ), + dict( + desc='Create %r' % fqdn3, + command=('host_add', [fqdn3], + dict( + description=u'Test host 2', + l=u'Undisclosed location 2', + force=True, + ), + ), + expected=dict( + value=fqdn3, + summary=u'Added host "%s"' % fqdn3, + result=dict( + dn=dn3, + fqdn=[fqdn3], + description=[u'Test host 2'], + l=[u'Undisclosed location 2'], + krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)], + objectclass=objectclasses.host, + ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn3], + ), + ), + ), + + + dict( + desc='Add managedby_host %r to %r' % (fqdn1, fqdn3), + command=('host_add_managedby', [fqdn3], + dict( + host=u'%s' % fqdn1, + ), + ), + expected=dict( + completed=1, + failed=dict( + managedby = dict( + host=tuple(), + ), + ), + result=dict( + dn=dn3, + fqdn=[fqdn3], + description=[u'Test host 2'], + l=[u'Undisclosed location 2'], + krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)], + managedby_host=[u'%s' % fqdn3, u'%s' % fqdn1], + ), + ), + ), + + dict( + desc='Retrieve %r' % fqdn3, + command=('host_show', [fqdn3], {}), + expected=dict( + value=fqdn3, + summary=None, + result=dict( + dn=dn3, + fqdn=[fqdn3], + description=[u'Test host 2'], + l=[u'Undisclosed location 2'], + krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)], + has_keytab=False, + managedby_host=[u'%s' % fqdn3, u'%s' % fqdn1], + ), + ), + ), + + dict( + desc='Remove managedby_host %r from %r' % (fqdn1, fqdn3), + command=('host_remove_managedby', [fqdn3], + dict( + host=u'%s' % fqdn1, + ), + ), + expected=dict( + completed=1, + failed=dict( + managedby = dict( + host=tuple(), + ), + ), + result=dict( + dn=dn3, + fqdn=[fqdn3], + description=[u'Test host 2'], + l=[u'Undisclosed location 2'], + krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)], + managedby_host=[u'%s' % fqdn3], + ), + ), + ), + + dict( desc='Try to rename %r' % fqdn1, @@ -313,6 +417,7 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn1], ), ), ), @@ -383,6 +488,7 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn2, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn2], ), ), ), diff --git a/tests/test_xmlrpc/test_hostgroup_plugin.py b/tests/test_xmlrpc/test_hostgroup_plugin.py index 70cbe3d4..1d143f0c 100644 --- a/tests/test_xmlrpc/test_hostgroup_plugin.py +++ b/tests/test_xmlrpc/test_hostgroup_plugin.py @@ -113,6 +113,7 @@ class test_hostgroup(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[fqdn1], ), ), ), diff --git a/tests/test_xmlrpc/test_netgroup_plugin.py b/tests/test_xmlrpc/test_netgroup_plugin.py index 76874daa..4c3aeafc 100644 --- a/tests/test_xmlrpc/test_netgroup_plugin.py +++ b/tests/test_xmlrpc/test_netgroup_plugin.py @@ -164,6 +164,7 @@ class test_netgroup(Declarative): krbprincipalname=[u'host/%s@%s' % (host1, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[host1], ), ), ), diff --git a/tests/test_xmlrpc/test_service_plugin.py b/tests/test_xmlrpc/test_service_plugin.py index fc8e08e9..5cd9cff9 100644 --- a/tests/test_xmlrpc/test_service_plugin.py +++ b/tests/test_xmlrpc/test_service_plugin.py @@ -88,6 +88,7 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn1], ), ), ), @@ -113,6 +114,7 @@ class test_host(Declarative): krbprincipalname=[u'host/%s@%s' % (fqdn2, api.env.realm)], objectclass=objectclasses.host, ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn2], ), ), ), |