From ae8370be44d95b9f6793ded46ef81126aebef3e0 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 17 Oct 2008 19:20:23 -0400 Subject: Port f_service to LDAP backend Add new keyword, 'filter', that can be passed to the search function. This is globbed onto the filter that is auto-created. --- ipa_server/plugins/b_ldap.py | 21 ++++++- ipalib/plugins/f_group.py | 2 +- ipalib/plugins/f_service.py | 137 +++++++++++++++++++++++++++++-------------- ipalib/plugins/f_user.py | 2 +- 4 files changed, 113 insertions(+), 49 deletions(-) diff --git a/ipa_server/plugins/b_ldap.py b/ipa_server/plugins/b_ldap.py index bc1f8951c..4845a5993 100644 --- a/ipa_server/plugins/b_ldap.py +++ b/ipa_server/plugins/b_ldap.py @@ -50,7 +50,7 @@ class ldap(CrudBackend): def make_group_dn(self, cn): """ - Construct user dn from cn. + Construct group dn from cn. """ return 'cn=%s,%s,%s' % ( self.dn.escape_dn_chars(cn), @@ -58,17 +58,28 @@ class ldap(CrudBackend): self.api.env.basedn, ) + def make_service_dn(self, principal): + """ + Construct service principal dn from principal name + """ + return 'krbprincipalname=%s,%s,%s' % ( + self.dn.escape_dn_chars(principal), + self.api.env.container_service, + self.api.env.basedn, + ) + def get_object_type(self, attribute): """ Based on attribute, make an educated guess as to the type of object we're looking for. """ + attribute = attribute.lower() object_type = None if attribute == "uid": # User object_type = "person" elif attribute == "cn": # Group object_type = "posixGroup" - elif attribute == "krbprincipal": # Service + elif attribute == "krbprincipalname": # Service object_type = "krbPrincipal" return object_type @@ -168,12 +179,18 @@ class ldap(CrudBackend): def search(self, **kw): objectclass = kw.get('objectclass') + sfilter = kw.get('filter') if objectclass: del kw['objectclass'] + if sfilter: + del kw['filter'] (exact_match_filter, partial_match_filter) = self._generate_search_filters(**kw) if objectclass: exact_match_filter = "(&(objectClass=%s)%s)" % (objectclass, exact_match_filter) partial_match_filter = "(&(objectClass=%s)%s)" % (objectclass, partial_match_filter) + if sfilter: + exact_match_filter = "(%s%s)" % (sfilter, exact_match_filter) + partial_match_filter = "(%s%s)" % (sfilter, partial_match_filter) search_base = "%s, %s" % (self.api.env.container_accounts, self.api.env.basedn) try: diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 132e45efd..e83c870e9 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -168,7 +168,7 @@ class group_find(crud.Find): object_type = ldap.get_object_type("cn") if object_type and not kw.get('objectclass'): - kw['objectclass'] = ldap.get_object_type("cn") + kw['objectclass'] = object_type return ldap.search(**kw) def output_for_cli(self, groups): diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index baed52333..38c80ad2b 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -1,5 +1,6 @@ # Authors: # Jason Gerard DeRose +# Rob Crittenden # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information @@ -27,9 +28,6 @@ from ipalib.frontend import Param from ipalib import api from ipalib import errors from ipalib import ipa_types -from ipa_server import servercore -from ipa_server import ipaldap -import ldap class service(frontend.Object): """ @@ -46,13 +44,26 @@ class service_add(crud.Add): takes_options = ( Param('force?', type=ipa_types.Bool(), default=False, doc='Force a service principal name'), ) - def execute(self, *args, **kw): - """args[0] = service principal to add - kw{force} determines whether we continue on errors + def execute(self, principal, **kw): """ - force = kw.get('force', False) + Execute the service-add operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. - principal = args[0] + Returns the entry as it will be created in LDAP. + + :param principal: The service to be added in the form: service/hostname + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'krbprincipalname' not in kw + ldap = self.api.Backend.ldap + + force = kw.get('force', False) + try: + del kw['force'] + except: + pass # Break down the principal into its component parts, which may or # may not include the realm. @@ -64,7 +75,7 @@ class service_add(crud.Add): sr = sp[1].split('@') if len(sr) == 1: hostname = sr[0].lower() - realm = servercore.realm + realm = self.api.env.realm elif len(sr) == 2: hostname = sr[0].lower() realm = sr[1] @@ -83,68 +94,104 @@ class service_add(crud.Add): logging.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) """ - service_container = servercore.DefaultServiceContainer - # At some point we'll support multiple realms - if (realm != servercore.realm): + if (realm != self.api.env.realm): raise errors.RealmMismatch # Put the principal back together again princ_name = service + "/" + hostname + "@" + realm - dn = "krbprincipalname=%s,%s,%s" % (ldap.dn.escape_dn_chars(princ_name), - service_container,servercore.basedn) - entry = ipaldap.Entry(dn) + dn = ldap.make_service_dn(princ_name) - entry.setValues('objectClass', 'krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux') - entry.setValues('krbprincipalname', princ_name) + kw['dn'] = dn + kw['objectClass'] = ['krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux'] + + return ldap.create(**kw) + + def output_to_cli(self, ret): + if ret: + print "Service added" - result = servercore.add_entry(entry) - return result - def forward(self, *args, **kw): - result = super(crud.Add, self).forward(*args, **kw) - if result: - print "Service %s added" % args[0] api.register(service_add) class service_del(crud.Del): 'Delete an existing service.' - def execute(self, *args, **kw): - """args[0] = princial to remove + def execute(self, principal, **kw): + """ + Delete a service principal. - Delete a service principal. + principal is the krbprincipalname of the entry to delete. - principal is the full DN of the entry to delete. + This should be called with much care. - This should be called with much care. + :param principal: The service to be added in the form: service/hostname + :param kw: not used """ - principal = args[0] - return False - def forward(self, *args, **kw): - result = super(crud.Del, self).forward(*args, **kw) - if result: - print "Service %s removed" % args[0] -api.register(service_del) + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("krbprincipalname", principal) + return ldap.delete(dn) + def output_to_cli(self, ret): + if ret: + print "Service removed" -class service_mod(crud.Mod): - 'Edit an existing service.' -api.register(service_mod) +api.register(service_del) +# There is no service-mod. The principal itself contains nothing that +# is user-changeable class service_find(crud.Find): 'Search the existing services.' + def execute(self, principal, **kw): + ldap = self.api.Backend.ldap + + kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=person))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" + kw['krbprincipalname'] = principal + + object_type = ldap.get_object_type("krbprincipalname") + if object_type and not kw.get('objectclass'): + kw['objectclass'] = object_type + + return ldap.search(**kw) + + def output_for_cli(self, services): + if not services: + return + + counter = services[0] + services = services[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for s in services: + for a in s.keys(): + print "%s: %s" % (a, s[a]) + api.register(service_find) class service_show(crud.Get): 'Examine an existing service.' - def execute(self, *args, **kw): - filter = "(&(objectclass=krbPrincipalAux)(!(objectClass=person))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))(&(|(krbprincipalname=%s))))" % args[0] - result = servercore.get_sub_entry(servercore.basedn, filter, ["*"]) - return result - def forward(self, *args, **kw): - result = super(crud.Get, self).forward(*args, **kw) - return result + def execute(self, principal, **kw): + """ + Execute the service-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param principal: The service principal to retrieve + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("krbprincipalname", principal) + # FIXME: should kw contain the list of attributes to display? + return ldap.retrieve(dn) + api.register(service_show) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index da0262b6c..8b4def80f 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -243,7 +243,7 @@ class user_find(crud.Find): object_type = ldap.get_object_type("uid") if object_type and not kw.get('objectclass'): - kw['objectclass'] = ldap.get_object_type("uid") + kw['objectclass'] = object_type return ldap.search(**kw) def output_for_cli(self, users): if not users: -- cgit