diff options
-rw-r--r-- | ipa-admintools/ipa-adduser | 55 | ||||
-rw-r--r-- | ipa-admintools/ipa-passwd | 36 | ||||
-rw-r--r-- | ipa-python/ipaclient.py | 26 | ||||
-rw-r--r-- | ipa-python/rpcclient.py | 22 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/controllers.py | 2 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/funcs.py | 57 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/ipaxmlrpc.py | 1 |
7 files changed, 111 insertions, 88 deletions
diff --git a/ipa-admintools/ipa-adduser b/ipa-admintools/ipa-adduser index cefb2383..8bca98d7 100644 --- a/ipa-admintools/ipa-adduser +++ b/ipa-admintools/ipa-adduser @@ -28,6 +28,7 @@ import ipa.config import xmlrpclib import kerberos +import krbV import ldap import getpass @@ -51,8 +52,10 @@ def parse_options(): help="Set user's login shell to shell") parser.add_option("-G", "--groups", dest="groups", help="Add account to one or more groups (comma-separated)") + parser.add_option("-k", "--krb-principal", dest="principal", + help="Set user's Kerberos Principal Name") parser.add_option("-M", "--mailAddress", dest="mail", - help="Set uesr's e-mail address") + help="Set user's e-mail address") parser.add_option("--usage", action="store_true", help="Program usage") @@ -66,8 +69,9 @@ def main(): givenname = "" lastname = "" username = "" + principal = "" password = "" - mail = "" + mail = "" gecos = "" directory = "" shell = "" @@ -100,7 +104,7 @@ def main(): cont = False if not options.sn: while (cont != True): - lastname = raw_input(" Last name: ") + lastname = raw_input("Last name: ") if (ipavalidate.plain(lastname, notEmpty=True)): print "Field is required and must be letters or '" else: @@ -140,18 +144,10 @@ def main(): else: password = options.sn - cont = False - if not options.mail: - while (cont != True): - mail = raw_input("E-mail addr: ") - if (ipavalidate.email(mail)): - print "Field is required and must include a user and domain name" - else: - cont = True - else: + if options.mail: mail = options.mail if (ipavalidate.email(mail)): - print "E-mail is required and must include a user and domain name" + print "The email provided seem not a valid email." return 1 # Ask the questions we don't normally force. We don't require answers @@ -168,8 +164,10 @@ def main(): cont = False if not options.directory: while (cont != True): - directory = raw_input("home directory []: ") - if (ipavalidate.path(gecos, notEmpty=False)): + directory = raw_input("home directory [/home/"+username+"]: ") + if directory == "": + directory = "/home/"+username + if (ipavalidate.path(directory, notEmpty=False)): print "Must be letters, numbers, spaces or '" else: cont = True @@ -180,29 +178,26 @@ def main(): if len(shell) < 1: shell = None - cont = True - cont = False - if not options.groups: - while (cont != True): - g = raw_input("Add to group [blank to exit]: ") - - if len(g) < 1: - cont = True - else: - if (ipavalidate.path(g, notEmpty=False)): - print "Must be letters, numbers, spaces or '" - else: - groups = groups + "," + g + cont = True + else: gecos = options.gecos directory = options.directory shell = options.shell groups = options.groups + if options.principal: + principal = options.principal + else: + ctx = krbV.default_context() + principal = username + "@" + ctx.default_realm + user.setValue('givenname', givenname) user.setValue('sn', lastname) user.setValue('uid', username) - user.setValue('mail', mail) + user.setValue('krbprincipalname', principal) + if mail: + user.setValue('mail', mail) if gecos: user.setValue('gecos', gecos) if directory: @@ -231,7 +226,7 @@ def main(): # Set the User's password if password is not None: try: - client.modifyPassword(username, None, password) + client.modifyPassword(principal, None, password) except ipa.ipaerror.IPAError, e: print "User added but setting the password failed." print "%s" % (e.message) diff --git a/ipa-admintools/ipa-passwd b/ipa-admintools/ipa-passwd index 20dea562..4db0838f 100644 --- a/ipa-admintools/ipa-passwd +++ b/ipa-admintools/ipa-passwd @@ -44,12 +44,12 @@ def parse_options(): return options, args -def get_principal(): +def get_principal(krbctx): try: - ctx = krbV.default_context() - ccache = ctx.default_ccache() + ccache = krbctx.default_ccache() cprinc = ccache.principal() except krbV.Krb5Error, e: + #TODO: do a kinit print "Unable to get kerberos principal: %s" % e[1] return None @@ -57,39 +57,47 @@ def get_principal(): def main(): match = False + username = None + principal = None + krbctx = krbV.default_context() options, args = parse_options() if len(args) == 2: username = args[1] else: - username = get_principal() - if username is None: + principal = get_principal(krbctx) + if principal is None: return 1 - u = username.split('@') - if len(u) > 1: - username = u[0] + if not principal: + u = username.split('@') + if len(u) > 2 or len(u) == 0: + print "Invalid user name (%s)" % username + if len(u) == 1: + principal = username+"@"+krbctx.default_realm + else: + principal = username - print "Changing password for %s" % username + print "Changing password for %s" % principal while (match != True): # No syntax checking of the password is required because that is done # on the server side password = getpass.getpass(" New Password: ") - confirm = getpass.getpass(" New Password (again): ") + confirm = getpass.getpass(" Confirm Password: ") if (password != confirm): print "Passwords do not match" match = False + elif (len(password) < 1): + print "Password cannot be empty" + match = False else: match = True - if (len(password) < 1): - print "Password cannot be empty" - match = False try: client = ipaclient.IPAClient() - client.modifyPassword(username, None, password) + client.modifyPassword(principal, None, password) except ipa.ipaerror.IPAError, e: print "%s" % (e.message) return 1 diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py index 27ad1c24..47788f39 100644 --- a/ipa-python/ipaclient.py +++ b/ipa-python/ipaclient.py @@ -35,7 +35,6 @@ class IPAClient: def __init__(self,local=None): self.local = local - ipa.config.init_config() if local: self.transport = funcs.IPAServer() # client needs to call set_principal(user@REALM) @@ -69,6 +68,13 @@ class IPAClient: result = self.transport.get_user_by_dn(dn,sattrs) return user.User(result) + def get_user_by_principal(self,principal,sattrs=None): + """Get a specific user by uid. If sattrs is set then only those + attributes will be returned, otherwise all available attributes + are returned.""" + result = self.transport.get_user_by_principal(principal,sattrs) + return user.User(result) + def get_users_by_manager(self,manager_dn,sattrs=None): """Gets the users the report to a particular manager. If sattrs is not None then only those @@ -81,8 +87,6 @@ class IPAClient: def add_user(self,user,user_container=None): """Add a user. user is a ipa.user.User object""" - realm = config.config.get_realm() - user_dict = user.toDict() # dn is set on the server-side @@ -126,31 +130,25 @@ class IPAClient: def update_user(self,user): """Update a user entry.""" - realm = config.config.get_realm() - result = self.transport.update_user(user.origDataDict(), user.toDict()) return result def delete_user(self,uid): """Delete a user entry.""" - realm = config.config.get_realm() - result = self.transport.delete_user(uid) return result - def modifyPassword(self,uid,oldpass,newpass): + def modifyPassword(self,principal,oldpass,newpass): """Modify a user's password""" - result = self.transport.modifyPassword(uid,oldpass,newpass) + result = self.transport.modifyPassword(principal,oldpass,newpass) return result def mark_user_deleted(self,uid): """Set a user as inactive by uid.""" - realm = config.config.get_realm() - result = self.transport.mark_user_deleted(uid) return result @@ -182,8 +180,6 @@ class IPAClient: def add_group(self,group,group_container=None): """Add a group. group is a ipa.group.Group object""" - realm = config.config.get_realm() - group_dict = group.toDict() # dn is set on the server-side @@ -238,6 +234,8 @@ class IPAClient: def add_user_to_group(self, user_uid, group_cn): """Add a user to an existing group. + user is a uid of the user to add + group is the cn of the group to be added to """ return self.transport.add_user_to_group(user_uid, group_cn) @@ -253,6 +251,8 @@ class IPAClient: def remove_user_from_group(self, user_uid, group_cn): """Remove a user from an existing group. + user is a uid of the user to remove + group is the cn of the group to be removed from """ return self.transport.remove_user_from_group(user_uid, group_cn) diff --git a/ipa-python/rpcclient.py b/ipa-python/rpcclient.py index 9f02b374..0327357d 100644 --- a/ipa-python/rpcclient.py +++ b/ipa-python/rpcclient.py @@ -84,7 +84,7 @@ class RPCClient: raise xmlrpclib.Fault(value, msg) return ipautil.unwrap_binary_data(result) - + def get_user_by_dn(self,dn,sattrs=None): """Get a specific user. If sattrs is not None then only those attributes will be returned, otherwise all available @@ -101,6 +101,22 @@ class RPCClient: return ipautil.unwrap_binary_data(result) + def get_user_by_principal(self,principal,sattrs=None): + """Get a specific user. If sattrs is not None then only those + attributes will be returned, otherwise all available + attributes are returned. The result is a dict.""" + server = self.setup_server() + if sattrs is None: + sattrs = "__NONE__" + try: + result = server.get_user_by_principal(principal, sattrs) + except xmlrpclib.Fault, fault: + raise ipaerror.gen_exception(fault.faultCode, fault.faultString) + except socket.error, (value, msg): + raise xmlrpclib.Fault(value, msg) + + return ipautil.unwrap_binary_data(result) + def get_users_by_manager(self,manager_dn,sattrs=None): """Gets the users that report to a manager. If sattrs is not None then only those @@ -212,7 +228,7 @@ class RPCClient: return result - def modifyPassword(self,uid,oldpass,newpass): + def modifyPassword(self,principal,oldpass,newpass): """Modify a user's password""" server = self.setup_server() @@ -220,7 +236,7 @@ class RPCClient: oldpass = "__NONE__" try: - result = server.modifyPassword(uid,oldpass,newpass) + result = server.modifyPassword(principal,oldpass,newpass) except xmlrpclib.Fault, fault: raise ipaerror.gen_exception(fault.faultCode, fault.faultString) except socket.error, (value, msg): diff --git a/ipa-server/ipa-gui/ipagui/controllers.py b/ipa-server/ipa-gui/ipagui/controllers.py index 41bd3b29..bdb7b102 100644 --- a/ipa-server/ipa-gui/ipagui/controllers.py +++ b/ipa-server/ipa-gui/ipagui/controllers.py @@ -338,7 +338,7 @@ class Root(controllers.RootController): # try: if password_change: - rv = client.modifyPassword(kw['uid'], "", kw.get('userpassword')) + rv = client.modifyPassword(kw['krbprincipalname'], "", kw.get('userpassword')) except ipaerror.IPAError, e: turbogears.flash("User password change failed: " + str(e)) return dict(form=user_edit_form, user=kw, diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index e4e2f40e..de089b61 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -20,12 +20,12 @@ import sys sys.path.append("/usr/share/ipa") +import krbV import ldap import ipaserver.dsinstance import ipaserver.ipaldap import ipa.ipautil import xmlrpclib -import ipa.config import copy from ipa import ipaerror @@ -86,11 +86,12 @@ class IPAServer: self.bindcert = "/usr/share/ipa/cert.pem" self.bindkey = "/usr/share/ipa/key.pem" self.bindca = "/usr/share/ipa/cacert.asc" - + self.krbctx = krbV.default_context() + self.realm = self.krbctx.default_realm + if _LDAPPool is None: _LDAPPool = IPAConnPool() - ipa.config.init_config() - self.basedn = ipa.ipautil.realm_to_suffix(ipa.config.config.get_realm()) + self.basedn = ipa.ipautil.realm_to_suffix(self.realm) self.scope = ldap.SCOPE_SUBTREE self.princ = None self.krbccache = None @@ -312,6 +313,15 @@ class IPAServer: filter = "(objectClass=*)" return self.__get_entry(dn, filter, sattrs, opts) + def get_user_by_principal(self, principal, sattrs=None, opts=None): + """Get a user entry searching by Kerberos Principal Name. + Return as a dict of values. Multi-valued fields are + represented as lists. + """ + + filter = "(krbPrincipalName="+self.__safe_filter(principal)+")" + return self.__get_entry(self.basedn, filter, sattrs, opts) + def get_users_by_manager (self, manager_dn, sattrs=None, opts=None): """Gets the users that report to a particular manager. """ @@ -342,9 +352,9 @@ class IPAServer: # Let us add in some missing attributes if user.get('homedirectory') is None: - user['homedirectory'] = '/home/%s' % user.get('uid') + user['homedirectory'] = '/home/%s' % user.get('uid') if not user.get('gecos') is None: - user['gecos'] = user['uid'] + user['gecos'] = user['uid'] # FIXME: This can be removed once the DS plugin is installed user['uidnumber'] = '501' @@ -352,8 +362,8 @@ class IPAServer: # FIXME: What is the default group for users? user['gidnumber'] = '501' - realm = ipa.config.config.get_realm() - user['krbprincipalname'] = "%s@%s" % (user.get('uid'), realm) + if user.get('krbprincipalname') is None: + user['krbprincipalname'] = "%s@%s" % (user.get('uid'), self.realm) # FIXME. This is a hack so we can request separate First and Last # name in the GUI. @@ -365,17 +375,7 @@ class IPAServer: del user['gn'] # some required objectclasses - entry.setValues('objectClass', 'top', 'posixAccount', 'shadowAccount', 'account', 'person', 'inetOrgPerson', 'organizationalPerson', 'krbPrincipalAux', 'krbTicketPolicyAux') - - # Fill in shadow fields - entry.setValue('shadowMin', '0') - entry.setValue('shadowMax', '99999') - entry.setValue('shadowWarning', '7') - entry.setValue('shadowExpire', '-1') - entry.setValue('shadowInactive', '-1') - entry.setValue('shadowFlag', '-1') - - # FIXME: calculate shadowLastChange + entry.setValues('objectClass', 'top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount', 'krbPrincipalAux') # fill in our new entry with everything sent by the user for u in user: @@ -426,7 +426,7 @@ class IPAServer: "label": "E-mail address:", "type": "text", "validator": "email", - "required": "true" + "required": "false" } fields.append(field1) @@ -455,6 +455,9 @@ class IPAServer: """Returns a list: counter followed by the results. If the results are truncated, counter will be set to -1.""" + # TODO - retrieve from config + timelimit = 2 + # Assume the list of fields to search will come from a central # configuration repository. A good format for that would be # a comma-separated list of fields @@ -562,31 +565,31 @@ class IPAServer: The memberOf plugin handles removing the user from any other groups. """ - user_dn = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts) - if user_dn is None: + user = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts) + if user is None: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) conn = self.getConnection(opts) try: - res = conn.deleteEntry(user_dn['dn']) + res = conn.deleteEntry(user['dn']) finally: self.releaseConnection(conn) return res - def modifyPassword (self, uid, oldpass, newpass, opts=None): + def modifyPassword (self, principal, oldpass, newpass, opts=None): """Set/Reset a user's password uid tells us who's password to change oldpass is the old password (if available) newpass is the new password """ - user_dn = self.get_user_by_uid(uid, ['dn', 'uid', 'objectclass'], opts) - if user_dn is None: + user = self.get_user_by_principal(principal, ['krbprincipalname'], opts) + if user is None or user['krbprincipalname'] != principal: raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND) conn = self.getConnection(opts) try: - res = conn.modifyPassword(user_dn['dn'], oldpass, newpass) + res = conn.modifyPassword(user['dn'], oldpass, newpass) finally: self.releaseConnection(conn) return res diff --git a/ipa-server/xmlrpc-server/ipaxmlrpc.py b/ipa-server/xmlrpc-server/ipaxmlrpc.py index 96d9299c..9f70550a 100644 --- a/ipa-server/xmlrpc-server/ipaxmlrpc.py +++ b/ipa-server/xmlrpc-server/ipaxmlrpc.py @@ -319,6 +319,7 @@ def handler(req, profiling=False): h = ModXMLRPCRequestHandler() h.register_function(f.get_user_by_uid) h.register_function(f.get_user_by_dn) + h.register_function(f.get_user_by_principal) h.register_function(f.get_users_by_manager) h.register_function(f.add_user) h.register_function(f.get_add_schema) |