diff --git a/ipa_server/plugins/b_ldap.py b/ipa_server/plugins/b_ldap.py index 600f1c86f..c48230382 100644 --- a/ipa_server/plugins/b_ldap.py +++ b/ipa_server/plugins/b_ldap.py @@ -29,7 +29,6 @@ from ipalib import errors from ipalib.crud import CrudBackend from ipa_server import servercore from ipa_server import ipaldap -import ldap class ldap(CrudBackend): @@ -39,7 +38,7 @@ class ldap(CrudBackend): dn = _ldap.dn - def get_user_dn(self, uid): + def make_user_dn(self, uid): """ Construct user dn from uid. """ @@ -49,6 +48,34 @@ class ldap(CrudBackend): self.api.env.basedn, ) + def find_entry_dn(self, key_attribute, primary_key, object_type=None): + """ + Find an existing entry's dn from an attribute + """ + key_attribute = key_attribute.lower() + if not object_type: + if key_attribute == "uid": # User + filter = "posixAccount" + elif key_attribute == "cn": # Group + object_type = "posixGroup" + elif key_attribute == "krbprincipal": # Service + object_type = "krbPrincipal" + + if not object_type: + return None + + filter = "(&(%s=%s)(objectclass=%s))" % ( + key_attribute, + self.dn.escape_dn_chars(primary_key), + object_type + ) + + search_base = "%s, %s" % (self.api.env.container_accounts, self.api.env.basedn) + + entry = servercore.get_sub_entry(search_base, filter, ['dn', 'objectclass']) + + return entry['dn'] + def create(self, **kw): if servercore.entry_exists(kw['dn']): raise errors.DuplicateEntry("entry already exists") @@ -64,4 +91,25 @@ class ldap(CrudBackend): return servercore.add_entry(entry) + def retrieve(self, dn, attributes=None): + return servercore.get_entry_by_dn(dn, attributes) + + def update(self, dn, **kw): + result = self.retrieve(dn, ["*"]) + + entry = ipaldap.Entry((dn, servercore.convert_scalar_values(result))) + + for k in kw: + entry.setValues(k, kw[k]) + + return servercore.update_entry(entry.toDict()) + + def delete(self, dn): + return servercore.delete_entry(dn) + +api.register(ldap) + + def delete(self, dn): + return servercore.delete_entry(dn) + api.register(ldap) diff --git a/ipalib/config.py b/ipalib/config.py index a606a40b1..42bf7787b 100644 --- a/ipalib/config.py +++ b/ipalib/config.py @@ -25,8 +25,11 @@ DEFAULT_CONF='/etc/ipa/ipa.conf' def generate_env(d={}): default = dict( + container_accounts = 'cn=accounts', basedn = 'dc=example,dc=com', container_user = 'cn=users,cn=accounts', + container_group = 'cn=groups,cn=accounts', + container_service = 'cn=services,cn=accounts', domain = LazyProp(get_domain), interactive = True, query_dns = True, diff --git a/ipalib/crud.py b/ipalib/crud.py index 5a60ac8c6..ba4d57187 100644 --- a/ipalib/crud.py +++ b/ipalib/crud.py @@ -70,7 +70,7 @@ class CrudBackend(backend.Backend): Base class defining generic CRUD backend API. """ - def create(self, *kw): + def create(self, **kw): """ Create a new entry. @@ -87,12 +87,14 @@ class CrudBackend(backend.Backend): """ raise NotImplementedError('%s.create()' % self.name) - def retrieve(self, primary_key): + def retrieve(self, primary_key, attributes): """ Retrieve an existing entry. - This method should take a single argument, the primary_key of the - entry in question. + This method should take a two arguments: the primary_key of the + entry in question and a list of the attributes to be retrieved. + If the list of attributes is None then all non-operational + attributes will be returned. If such an entry exists, this method should return a dict representing that entry. If no such entry exists, this method @@ -100,7 +102,7 @@ class CrudBackend(backend.Backend): """ raise NotImplementedError('%s.retrieve()' % self.name) - def update(self, primary_key, *kw): + def update(self, primary_key, **kw): """ Update an existing entry. diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 618f8385d..db2af1abd 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -58,6 +58,6 @@ class xmlrpc(Backend): print "%s: %s" % (code, getattr(err,'__doc__','')) else: raise err - return False + return {} api.register(xmlrpc) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index e3ecd2234..a1078fe74 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -110,7 +110,7 @@ class user_add(crud.Add): assert 'dn' not in kw ldap = self.api.Backend.ldap kw['uid'] = uid - kw['dn'] = ldap.get_user_dn(uid) + kw['dn'] = ldap.make_user_dn(uid) if servercore.uid_too_long(kw['uid']): raise errors.UsernameTooLong @@ -154,26 +154,34 @@ class user_add(crud.Add): # some required objectclasses kw['objectClass'] = config.get('ipauserobjectclasses') +<<<<<<< HEAD:ipalib/plugins/f_user.py +======= return ldap.create(**kw) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "User added" api.register(user_add) class user_del(crud.Del): 'Delete an existing user.' - def execute(self, *args, **kw): - """args[0] = uid of the user to remove - - Delete a user. Not to be confused with inactivate_user. This + def execute(self, uid, **kw): + """Delete a user. Not to be confused with inactivate_user. This makes the entry go away completely. uid is the uid of the user to delete The memberOf plugin handles removing the user from any other groups. + + :param uid: The login name of the user being added. + :param kw: Not used. """ - uid = args[0] if uid == "admin": # FIXME: do we still want a "special" user? raise SyntaxError("admin required") @@ -183,37 +191,46 @@ class user_del(crud.Del): if not user: raise errors.NotFound - return servercore.delete_entry(user['dn']) - def forward(self, *args, **kw): - result = super(crud.Del, self).forward(*args, **kw) - if result: - print "User %s removed" % args[0] + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, ["*"], "posixAccount") + return ldap.delete(dn) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "User deleted" + api.register(user_del) class user_mod(crud.Mod): 'Edit an existing user.' - def execute(self, *args, **kw): - uid=args[0] + def execute(self, uid, **kw): + """ + Execute the user-mod operation. - # Get the existing user entry - result = servercore.get_sub_entry("cn=accounts," + servercore.basedn, "uid=%s" % uid, ["*"]) + The dn should not be passed as a keyword argument as it is constructed + by this method. - user = kw - dn = result.get('dn') - del result['dn'] - entry = ipaldap.Entry((dn, servercore.convert_scalar_values(result))) + Returns the entry - for u in user: - entry.setValues(u, user[u]) + :param uid: The login name of the user to retrieve. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'uid' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, "posixAccount") + return ldap.update(dn, **kw) - result = servercore.update_entry(entry.toDict()) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "User updated" - return result - def forward(self, *args, **kw): - result = super(crud.Mod, self).forward(*args, **kw) - if result: - print "User %s modified" % args[0] api.register(user_mod) @@ -244,18 +261,23 @@ api.register(user_find) class user_show(crud.Get): 'Examine an existing user.' - def execute(self, *args, **kw): - uid=args[0] - result = servercore.get_user_by_uid(uid, ["*"]) - return result - def forward(self, *args, **kw): - try: - result = super(crud.Get, self).forward(*args, **kw) - if not result: return - for a in result: - print a, ": ", result[a] - except errors.NotFound: - print "User %s not found" % args[0] + def execute(self, uid, **kw): + """ + Execute the user-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param uid: The login name of the user to retrieve. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, "posixAccount") + # FIXME: should kw contain the list of attributes? + return ldap.retrieve(dn) + api.register(user_show) class user_lock(frontend.Command):