diff options
-rw-r--r-- | install/share/60basev2.ldif | 3 | ||||
-rw-r--r-- | install/share/default-aci.ldif | 7 | ||||
-rw-r--r-- | ipalib/plugins/cert.py | 51 | ||||
-rw-r--r-- | ipalib/plugins/rolegroup.py | 6 | ||||
-rw-r--r-- | ipalib/plugins/service.py | 28 | ||||
-rw-r--r-- | ipaserver/plugins/ldap2.py | 2 |
6 files changed, 52 insertions, 45 deletions
diff --git a/install/share/60basev2.ldif b/install/share/60basev2.ldif index 7c3fa43bd..9296e0607 100644 --- a/install/share/60basev2.ldif +++ b/install/share/60basev2.ldif @@ -4,9 +4,10 @@ attributeTypes: (2.16.840.1.113730.3.8.3.2 NAME 'ipaClientVersion' DESC 'Text st attributeTypes: (2.16.840.1.113730.3.8.3.3 NAME 'enrolledBy' DESC 'DN of administrator who performed manual enrollment of the host' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.4 NAME 'enrollmentPwd' DESC 'Password used to bulk enroll machines' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.43 NAME 'fqdn' DESC 'FQDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +attributeTypes: (2.16.840.1.113730.3.8.3.53 NAME 'managedBy' DESC 'DNs of entries allowed to manage' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2') objectClasses: (2.16.840.1.113730.3.8.4.1 NAME 'ipaHost' AUXILIARY MUST ( fqdn ) MAY ( userPassword $ ipaClientVersion $ enrolledBy $ memberOf) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.44 NAME 'ipaObject' DESC 'IPA objectclass' AUXILIARY MUST ( ipaUniqueId ) X-ORIGIN 'IPA v2' ) -objectClasses: (2.16.840.1.113730.3.8.4.2 NAME 'ipaService' DESC 'IPA service objectclass' AUXILIARY MAY ( memberOf ) X-ORIGIN 'IPA v2' ) +objectClasses: (2.16.840.1.113730.3.8.4.2 NAME 'ipaService' DESC 'IPA service objectclass' AUXILIARY MAY ( memberOf $ managedBy ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.3 NAME 'nestedGroup' DESC 'Group that supports nesting' SUP groupOfNames STRUCTURAL MAY memberOf X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.4 NAME 'ipaUserGroup' DESC 'IPA user group object class' SUP nestedGroup STRUCTURAL X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.5 NAME 'ipaHostGroup' DESC 'IPA host group object class' SUP nestedGroup STRUCTURAL X-ORIGIN 'IPA v2' ) diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif index 25bd3b224..7f08518b8 100644 --- a/install/share/default-aci.ldif +++ b/install/share/default-aci.ldif @@ -36,3 +36,10 @@ dn: cn=services,cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr="krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";) + +# Define which hosts can edit services +dn: cn=services,cn=accounts,$SUFFIX +changetype: modify +add: aci +aci: (targetattr=userCertificate)(version 3.0; aci "Hosts can modify service userCertificate"; allow(write) userattr = "parent[0,1].managedby#USERDN";) + diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py index 9750de6f4..0416730f8 100644 --- a/ipalib/plugins/cert.py +++ b/ipalib/plugins/cert.py @@ -102,6 +102,7 @@ class cert_request(VirtualCommand): ) def execute(self, csr, **kw): + ldap = self.api.Backend.ldap2 skw = {"all": True} principal = kw.get('principal') add = kw.get('add') @@ -121,35 +122,6 @@ class cert_request(VirtualCommand): if subject_host.lower() != hostname.lower(): raise errors.ACIError(info="hostname in subject of request '%s' does not match principal hostname '%s'" % (subject_host, hostname)) - # Get the IP address of the machine that submitted the request. We - # will compare this to the subjectname of the CSR. - client_ip = getattr(context, 'client_ip') - rhost = None - if client_ip not in (None, ''): - rev = client_ip.split('.') - if len(rev) == 0: - rev = client_ip.split(':') - rev.reverse() - addr = "%s.in-addr.arpa." % ".".join(rev) - else: - rev.reverse() - addr = "%s.in-addr.arpa." % ".".join(rev) - rs = dnsclient.query(addr, dnsclient.DNS_C_IN, dnsclient.DNS_T_PTR) - if len(rs) == 0: - raise errors.ACIError(info='DNS lookup on client failed for IP %s' % client_ip) - for rsn in rs: - if rsn.dns_type == dnsclient.DNS_T_PTR: - rhost = rsn - break - - if rhost is None: - raise errors.ACIError(info='DNS lookup on client failed for IP %s' % client_ip) - - client_hostname = rhost.rdata.ptrdname[:-1] - if subject_host.lower() != client_hostname.lower(): - self.log.debug("IPA: hostname in subject of request '%s' does not match requesting hostname '%s'" % (subject_host, client_hostname)) - self.check_access(operation="request certificate different host") - # See if the service exists and punt if it doesn't and we aren't # going to add it try: @@ -157,24 +129,23 @@ class cert_request(VirtualCommand): if 'usercertificate' in service: # FIXME, what to do here? Do we revoke the old cert? raise errors.GenericError(format='entry already has a certificate, serial number %s' % get_serial(service['usercertificate'])) - if not can_write(dn, "usercertificate"): - raise errors.ACIError(info='You need to be a member of the serviceadmin role to update services') - except errors.NotFound, e: if not add: raise errors.NotFound(reason="The service principal for this request doesn't exist.") + try: + (dn, service) = api.Command['service_add'](principal, **{}) + except errors.ACIError: + raise errors.ACIError(info='You need to be a member of the serviceadmin role to add services') + + # We got this far so the service entry exists, can we write it? + if not ldap.can_write(dn, "usercertificate"): + raise errors.ACIError(info="Insufficient 'write' privilege to the 'userCertificate' attribute of entry '%s'." % dn) # Request the certificate result = self.Backend.ra.request_certificate(csr, **kw) - # Success? Then add it to the service entry. We know that it - # either exists or we should add it. - if result.get('status') == '0': - if service is None: - try: - service = api.Command['service_add'](principal, **{}) - except errors.ACIError: - raise errors.ACIError(info='You need to be a member of the serviceadmin role to add services') + # Success? Then add it to the service entry. + if result.get('status') == 0: skw = {"usercertificate": str(result.get('certificate'))} api.Command['service_mod'](principal, **skw) diff --git a/ipalib/plugins/rolegroup.py b/ipalib/plugins/rolegroup.py index 85f34157e..fdc632450 100644 --- a/ipalib/plugins/rolegroup.py +++ b/ipalib/plugins/rolegroup.py @@ -40,10 +40,12 @@ class rolegroup(LDAPObject): 'cn': 'name', 'member user': 'member users', 'member group': 'member groups', + 'member host': 'member hosts', + 'member hostgroup': 'member hostgroups', 'memberof taskgroup': 'member of taskgroup', } attribute_members = { - 'member': ['user', 'group'], + 'member': ['user', 'group', 'host', 'hostgroup'], 'memberof': ['taskgroup'], } @@ -99,7 +101,7 @@ class rolegroup_show(LDAPRetrieve): """ Display rolegroup. """ - + api.register(rolegroup_show) diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py index 481a9f6dc..449acbaec 100644 --- a/ipalib/plugins/service.py +++ b/ipalib/plugins/service.py @@ -103,12 +103,16 @@ class service(LDAPObject): 'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject', 'ipaservice', 'pkiuser' ] - default_attributes = ['krbprincipalname', 'usercertificate'] + default_attributes = ['krbprincipalname', 'usercertificate', 'managedby'] uuid_attribute = 'ipauniqueid' attribute_names = { 'krbprincipalname': 'kerberos principal', 'usercertificate': 'user certificate', 'ipauniqueid': 'unique identifier', + 'managedby': 'managed by', + } + attribute_members = { + 'managedby': ['host'], } takes_params = ( @@ -131,6 +135,7 @@ class service_add(LDAPCreate): """ Add new service. """ + member_attributes = ['managedby'] takes_options = ( Flag('force', doc='force principal name even if not in DNS', @@ -176,6 +181,7 @@ class service_del(LDAPDelete): """ Delete an existing service. """ + member_attributes = ['managedby'] def pre_callback(self, ldap, dn, *keys, **options): if self.api.env.enable_ra: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) @@ -192,6 +198,7 @@ class service_mod(LDAPUpdate): """ Modify service. """ + member_attributes = ['managedby'] def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): cert = entry_attrs.get('usercertificate') if cert: @@ -213,6 +220,7 @@ class service_find(LDAPSearch): """ Search for services. """ + member_attributes = ['managedby'] def pre_callback(self, ldap, filter, attrs_list, base_dn, *args, **options): # lisp style! custom_filter = '(&(objectclass=ipaService)' \ @@ -233,6 +241,24 @@ class service_show(LDAPRetrieve): """ Display service. """ + member_attributes = ['managedby'] api.register(service_show) +class service_add_host(LDAPAddMember): + """ + Add members to service. + """ + member_attributes = ['managedby'] + +api.register(service_add_host) + + +class service_remove_host(LDAPRemoveMember): + """ + Remove members from service. + """ + member_attributes = ['managedby'] + +api.register(service_remove_host) + diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index f8e06576d..38fdb6210 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -512,7 +512,7 @@ class ldap2(CrudBackend, Encoder): attributes and the entryLevelRights for the entry itself. """ principal = getattr(context, 'principal') - (binddn, attrs) = self.find_entry_by_attr("krbprincipalname", principal, "posixAccount") + (binddn, attrs) = self.find_entry_by_attr("krbprincipalname", principal, "krbPrincipalAux") sctrl = [LDAPControl("1.3.6.1.4.1.42.2.27.9.5.2", True, "dn: " + binddn.encode('UTF-8'))] self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, sctrl) (dn, attrs) = self.get_entry(dn, entry_attrs) |